How to Install Nginx Mainline on Debian 13, 12 and 11

Last updated Wednesday, May 20, 2026 9:36 am Joshua James 10 min read

Nginx Mainline is the nginx.org branch for Debian servers that need upstream Nginx changes before Debian’s release-frozen packages receive them. Use this path when a feature, module package, protocol change, or upstream bug fix matters more than staying on Debian’s slower default package line.

With the official nginx.org Linux package repository, Debian can keep Nginx Mainline updates inside APT while still using a source-specific signing key, repository pin, systemd service checks, and normal package cleanup. If you only need Debian’s standard web server package, use the default Nginx on Debian install guide instead.

Install Nginx Mainline on Debian

The nginx.org Debian repository currently supports Debian 13 (Trixie), Debian 12 (Bookworm), and Debian 11 (Bullseye) on the Debian package architectures amd64 and arm64. The commands use Debian’s /etc/os-release file instead of lsb_release, which keeps the setup usable on minimal server and cloud images.

Check Your Debian Release and Architecture

Confirm the release codename and architecture before adding the repository. The source file later uses these values to choose the correct nginx.org suite and package index.

. /etc/os-release
printf 'Debian release: %s (%s)\n' "$VERSION_ID" "$VERSION_CODENAME"
dpkg --print-architecture

Example output from Debian 13 on x86_64 hardware:

Debian release: 13 (trixie)
amd64

Continue when the codename is trixie, bookworm, or bullseye, and the architecture is amd64 or arm64. Stop on older Debian releases or unsupported architectures because APT may otherwise create a source file that cannot provide a package candidate.

Refresh Debian Package Metadata

Refresh APT metadata before installing prerequisites. If APT reports important pending upgrades, apply them during a maintenance window before changing the web server package source.

sudo apt update

These commands use sudo for root-level package, service, and repository changes. If your account is not configured for sudo yet, follow the Debian sudoers walkthrough before continuing: add a user to sudoers on Debian.

Install Nginx Repository Prerequisites

Install the packages needed to download the key, trust HTTPS repository endpoints, and convert the signing key into the binary keyring format used by the APT source file.

sudo apt install ca-certificates curl gpg -y

The curl package downloads the key over HTTPS, ca-certificates lets APT and curl validate TLS certificates, and gpg provides the gpg --dearmor command. For a broader refresher on the downloader syntax used in repository setup tasks, see these curl command examples.

Import the Nginx Signing Key

Download the official nginx.org signing key and store it as a dedicated keyring. The --yes option keeps reruns from hanging if the keyring already exists.

curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor --yes -o /usr/share/keyrings/nginx-archive-keyring.gpg

Inspect the saved keyring before trusting the repository. nginx.org documents the long-running 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 fingerprint, and the current key file also includes newer signing keys used by the package repository.

gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
pub   rsa4096 2024-05-29 [SC]
      8540A6F18833A80E9C1653A42FD21310B49F6B46
uid                      nginx signing key <signing-key-2@nginx.com>

pub   rsa2048 2011-08-19 [SC] [expires: 2027-05-24]
      573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
uid                      nginx signing key <signing-key@nginx.com>

pub   rsa4096 2024-05-29 [SC]
      9E9BE90EACBCDE69FE9B204CBCDCD8A38D88A2B3
uid                      nginx signing key <signing-key-3@nginx.com>

Add the Nginx Mainline Repository

Create a DEB822 source file for the mainline repository. The guard keeps the source file from being written on unsupported releases or architectures, which is safer than letting a later apt update fail with a confusing repository error.

CODENAME=$(. /etc/os-release && printf '%s' "$VERSION_CODENAME")
ARCH=$(dpkg --print-architecture)

if [ "$CODENAME" = "trixie" ] || [ "$CODENAME" = "bookworm" ] || [ "$CODENAME" = "bullseye" ]; then
  if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "arm64" ]; then
    printf '%s\n' \
      'Types: deb' \
      'URIs: https://nginx.org/packages/mainline/debian' \
      "Suites: ${CODENAME}" \
      'Components: nginx' \
      "Architectures: ${ARCH}" \
      'Signed-By: /usr/share/keyrings/nginx-archive-keyring.gpg' | sudo tee /etc/apt/sources.list.d/nginx.sources > /dev/null
  else
    printf 'nginx.org lists Debian packages for amd64 and arm64, not "%s".\n' "$ARCH" >&2
    false
  fi
else
  printf 'nginx.org does not list Debian codename "%s" for this repository.\n' "$CODENAME" >&2
  false
fi

Check the generated source file once so you can see the exact suite and architecture APT will consume.

cat /etc/apt/sources.list.d/nginx.sources
Types: deb
URIs: https://nginx.org/packages/mainline/debian
Suites: trixie
Components: nginx
Architectures: amd64
Signed-By: /usr/share/keyrings/nginx-archive-keyring.gpg

The upstream stable branch uses https://nginx.org/packages/debian instead of the mainline URI. Keep only one nginx.org branch enabled at a time unless you have a tested pinning plan, because both branches publish packages named nginx.

Configure APT Pinning for Nginx Mainline

Refresh APT after adding the source, then confirm the repository metadata advertises the expected Origin value. The pin uses that value so nginx.org packages are preferred over Debian packages with the same names.

sudo apt update
grep -h '^Origin:' /var/lib/apt/lists/*nginx*_InRelease
Origin: nginx

Create the APT preference after the origin check returns nginx. Priority 900 keeps nginx.org ahead of Debian’s normal priority 500 packages without forcing a downgrade or replacing unrelated repositories.

printf '%s\n' \
  'Package: *' \
  'Pin: release o=nginx' \
  'Pin-Priority: 900' | sudo tee /etc/apt/preferences.d/99nginx > /dev/null

Verify the selected package candidate before installation. The key detail is that the candidate comes from https://nginx.org/packages/mainline/debian at priority 900.

apt-cache policy nginx
nginx:
  Installed: (none)
  Candidate: 1.31.0-1~trixie
  Version table:
     1.31.0-1~trixie 900
        900 https://nginx.org/packages/mainline/debian trixie/nginx amd64 Packages
     1.26.3-3+deb13u5 500
        500 http://security.debian.org/debian-security trixie-security/main amd64 Packages

Debian 12 and Debian 11 show the same mainline branch from nginx.org, with release-specific package revisions such as 1.31.0-1~bookworm or 1.31.0-1~bullseye.

Install the Nginx Mainline Package

Install the nginx package. The nginx.org package uses the same package name as Debian’s default package, so the policy output is what proves APT will install the upstream mainline build.

sudo apt install nginx -y

Check the installed binary version. On many Debian SSH sessions, /usr/sbin is not in a regular user’s PATH, so sudo nginx -v is more reliable than a plain nginx -v.

sudo nginx -v
nginx version: nginx/1.31.0

Enable and Start Nginx Mainline

Enable the service at boot and start it now. These commands are safe to rerun if the package already started Nginx during installation.

sudo systemctl enable nginx
sudo systemctl start nginx

Use focused systemd checks for stable output.

systemctl is-enabled nginx
systemctl is-active nginx
enabled
active

Test the Nginx Configuration and Local Response

Run the syntax check before any reload or configuration handoff. A successful test proves Nginx can parse the active configuration tree.

sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Probe the local listener after the service starts. The HTTP status proves Nginx is serving on loopback, while the Server header confirms the upstream mainline binary is handling the request.

curl -fsSI http://127.0.0.1/ | sed -n '1p;/^Server:/p'
HTTP/1.1 200 OK
Server: nginx/1.31.0

A browser may show the default “Welcome to nginx” page at this point. That page means the server is installed and responding, not that a production site or reverse proxy has been configured yet.

Create a Starter Local Test Page

Create a tiny local test page before moving to a real domain or reverse proxy. The nginx.org package serves the default document root at /usr/share/nginx/html/, so this smoke test backs up the stock welcome page, writes a temporary page, reloads Nginx, and verifies the response through loopback.

if [ ! -f /usr/share/nginx/html/index.html.nginx-org-backup ]; then
  sudo cp -a /usr/share/nginx/html/index.html /usr/share/nginx/html/index.html.nginx-org-backup
fi

printf '%s\n' 'Nginx Mainline test page' | sudo tee /usr/share/nginx/html/index.html > /dev/null

Test the syntax, reload the service, and request the page from the local listener. This confirms that Nginx is serving your changed file, not only returning headers from the stock welcome page.

sudo nginx -t
sudo systemctl reload nginx
curl -fsS http://127.0.0.1/
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Nginx Mainline test page

This local page is only a first-use check. For a real site, create a dedicated server block under /etc/nginx/conf.d/, point DNS at the server, test with sudo nginx -t, and reload. If the local probe works but remote browsers cannot connect, check the host firewall, cloud security group, router forwarding, and DNS record before changing the Nginx package. Debian does not enable UFW by default, but servers that use it can follow the UFW on Debian setup guide.

Restore the stock welcome page after the smoke test if you are not replacing it with a real site yet.

if [ -f /usr/share/nginx/html/index.html.nginx-org-backup ]; then
  sudo mv /usr/share/nginx/html/index.html.nginx-org-backup /usr/share/nginx/html/index.html
fi

sudo nginx -t
sudo systemctl reload nginx

Compare Nginx Mainline, Stable, and Debian Packages on Debian

Package checks on May 20, 2026 showed nginx.org Mainline at 1.31.0 for Debian 13, 12, and 11. The official Nginx download page listed stable at 1.30.1 on the same date, while Debian’s default APT sources remained on older release-managed package lines.

Package SourceCurrent Line CheckedUpdate OwnerBest ForTrade-off
nginx.org Mainline1.31.0 packages for Debian 13, 12, and 11nginx.org through APTNew upstream features, newer dynamic module packages, earlier upstream fixesFaster branch movement can expose compatibility issues sooner
nginx.org Stable1.30.1 upstream stable branchnginx.org through APT when the stable repository URI is usedUpstream packaging with a slower branch cadenceNot the branch installed by this mainline repository workflow
Debian default APT sourcesDebian 13: 1.26.3-3+deb13u5; Debian 12: 1.22.1-9+deb12u7; Debian 11: 1.18.0-6.1+deb11u6Debian security and release updatesConservative server installs that do not need newer upstream Nginx behaviorOlder feature set, especially on oldstable and LTS systems

Choose mainline only when the newer upstream branch solves a real requirement. Debian’s default package is still the lower-maintenance choice for a basic static site, reverse proxy, or LEMP stack that does not depend on mainline-only behavior.

Do not mix Debian’s libnginx-mod-* packages with nginx.org’s nginx package. Use module packages from the same nginx.org repository, such as nginx-module-njs or nginx-module-image-filter, so the module ABI matches the installed binary.

Manage Nginx Mainline on Debian

The nginx.org package uses the upstream-style Debian layout. Managing it is still normal systemd and APT work, but the site configuration path differs from Debian’s default sites-available and sites-enabled workflow.

Check Nginx Mainline File Locations

Inspect the active configuration for the included site directory and default web root.

sudo nginx -T 2>/dev/null | grep -E 'include /etc/nginx/conf\.d/\*\.conf|root +/usr/share/nginx/html'
    include /etc/nginx/conf.d/*.conf;
        root   /usr/share/nginx/html;
        root   /usr/share/nginx/html;
  • /etc/nginx/nginx.conf is the main Nginx configuration file.
  • /etc/nginx/conf.d/ is the default location for site, reverse-proxy, and application snippets with nginx.org packages.
  • /usr/share/nginx/html/ serves the default welcome page until you replace or override it.
  • /var/log/nginx/access.log and /var/log/nginx/error.log store request and error details for normal troubleshooting.

If you want Debian’s symlink pattern, add and validate an include for /etc/nginx/sites-enabled/*.conf yourself. The stock nginx.org configuration only includes files from /etc/nginx/conf.d/*.conf.

Reload Nginx After Configuration Changes

Run a syntax check before reloading. Reloads let new worker processes use the updated configuration without dropping active connections in normal cases.

sudo nginx -t
sudo systemctl reload nginx
systemctl is-active nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
active

Restart Nginx When Reload Is Not Enough

Use a restart after a package upgrade, a failed reload, or a service state problem that requires a full stop and start cycle.

sudo systemctl restart nginx
systemctl is-active nginx
active

Update Nginx Mainline with APT

Nginx Mainline updates through APT because the repository source stays enabled. Use a targeted package upgrade when you want to update Nginx without upgrading the whole Debian system at the same time.

sudo apt update
sudo apt install --only-upgrade nginx -y
nginx is already the newest version (1.31.0-1~trixie).
0 upgraded, 0 newly installed, 0 to remove and 59 not upgraded.

After a real Nginx package upgrade, run sudo nginx -t and check systemctl is-active nginx before assuming the web server is healthy.

Find Optional Nginx Module Packages

The main nginx.org package includes the base server, while selected dynamic modules ship as separate nginx-module-* packages. Search the same repository before installing a module so you do not accidentally mix Debian module packages with the nginx.org binary.

apt-cache search '^nginx-module' | sed -n '1,12p'
nginx-module-acme - nginx nginx-acme
nginx-module-acme-dbg - debug symbols for the nginx-module-acme
nginx-module-geoip - nginx GeoIP dynamic modules
nginx-module-geoip-dbg - debug symbols for the nginx-module-geoip
nginx-module-image-filter - nginx image filter dynamic module
nginx-module-image-filter-dbg - debug symbols for the nginx-module-image-filter
nginx-module-njs - nginx njs dynamic modules
nginx-module-njs-dbg - debug symbols for the nginx-module-njs
nginx-module-otel - nginx OpenTelemetry dynamic module
nginx-module-otel-dbg - debug symbols for the nginx-module-otel
nginx-module-perl - nginx Perl dynamic module
nginx-module-perl-dbg - debug symbols for the nginx-module-perl

Install only the module package your configuration needs, then run sudo nginx -t before reloading. Module packages update through the same nginx.org APT source and can be removed later by package name.

Troubleshoot Nginx Mainline on Debian

Start with the narrowest check that matches the symptom. Repository failures usually need source or key inspection; service failures need syntax, port, and journal checks; browser failures often mean Nginx is running but still serving the default site.

Fix Nginx Reload When the Service Is Inactive

Reload only works when the service is already running. If Nginx is stopped, systemd can return this error:

sudo systemctl reload nginx
nginx.service is not active, cannot reload.

Check the configuration, start the service, and verify that it is active before trying another reload.

sudo nginx -t
sudo systemctl start nginx
systemctl is-active nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
active

Fix Port 80 Conflicts

Nginx cannot start on port 80 when another service already owns that listener. Check the process using the port before changing Nginx itself.

sudo ss -ltnp '( sport = :80 )'

If another web server, development server, or container proxy appears in the output, stop that service or move one of the listeners to another port. Then start Nginx again and inspect the recent service log if it still fails.

sudo systemctl start nginx
sudo journalctl -u nginx -n 30 --no-pager

For deeper request-level troubleshooting after Nginx starts, use the dedicated Nginx access and error logs guide.

Fix Repository or Signing Key Errors

A NO_PUBKEY, signature, or missing Release file error usually means the keyring path, source file, suite, or architecture does not match the repository metadata. Inspect the saved source before reinstalling packages.

cat /etc/apt/sources.list.d/nginx.sources
ls -l /usr/share/keyrings/nginx-archive-keyring.gpg
sudo apt update

The mainline source should point to https://nginx.org/packages/mainline/debian, use your Debian codename, list nginx as the component, and reference /usr/share/keyrings/nginx-archive-keyring.gpg. Re-run the signing-key import command if the keyring file is missing or empty.

Fix Nginx Command Not Found

The nginx.org package installs the binary under /usr/sbin/nginx. Some regular SSH sessions do not include /usr/sbin in PATH, so an unprivileged nginx -v can fail even when the package is installed correctly.

sudo nginx -v
/usr/sbin/nginx -v
nginx version: nginx/1.31.0
nginx version: nginx/1.31.0

Understand the Welcome to nginx Page

The default welcome page means the service is installed, running, and serving the stock document root. It does not configure your domain, TLS certificate, PHP application, or reverse proxy target.

For a typical next step, create a server block under /etc/nginx/conf.d/, run sudo nginx -t, and reload the service. Use the generic Nginx reverse proxy guide when your first site will forward traffic to an application on another local port.

Remove Nginx Mainline from Debian

Removal has two parts: remove the installed package, then remove the nginx.org source, pin, and keyring when no other nginx.org source still uses that key. Back up any real site configuration before purging, because the nginx.org package owns /etc/nginx/.

Back Up Nginx Configuration

Make a root-owned backup before purging if the server has custom site files, TLS snippets, reverse-proxy configuration, or module load directives you still need.

sudo cp -a /etc/nginx /etc/nginx.backup

Remove Nginx Mainline Packages

Stop and disable the service, then purge the nginx.org package. A clean nginx.org install uses the nginx package name; it does not install Debian’s separate nginx-common package.

sudo systemctl stop nginx
sudo systemctl disable nginx
sudo apt purge nginx -y

Preview dependency cleanup before removing anything else. Run the second command only when the preview lists packages you no longer need.

sudo apt autoremove --dry-run
sudo apt autoremove

Remove the Nginx Repository and Keyring

Remove the source and pin, refresh APT, then remove the keyring only when no remaining APT source references it. This protects systems that also use the nginx.org stable branch or another nginx.org source file.

sudo rm -f /etc/apt/sources.list.d/nginx.sources
sudo rm -f /etc/apt/preferences.d/99nginx
sudo apt update

key_refs=$(sudo grep -Rsl '/usr/share/keyrings/nginx-archive-keyring.gpg' /etc/apt/sources.list /etc/apt/sources.list.d 2> /dev/null || true)

if [ -z "$key_refs" ]; then
  sudo rm -f /usr/share/keyrings/nginx-archive-keyring.gpg
else
  printf 'Leaving keyring because these sources still use it:\n%s\n' "$key_refs"
fi

Verify Nginx Mainline Removal

Check installed state and package policy after the repository cleanup. The package should no longer be installed, and the version table should no longer include nginx.org entries.

dpkg-query -W -f='${db:Status-Abbrev} ${binary:Package}\n' nginx 2> /dev/null || true
apt-cache policy nginx
nginx:
  Installed: (none)
  Candidate: 1.26.3-3+deb13u5
  Version table:
     1.26.3-3+deb13u5 500
        500 http://security.debian.org/debian-security trixie-security/main amd64 Packages
     1.26.3-3+deb13u4 500
        500 http://deb.debian.org/debian trixie/main amd64 Packages

Debian 12 and Debian 11 show their own default candidates after cleanup, such as 1.22.1-9+deb12u7 on Debian 12 and 1.18.0-6.1+deb11u6 on Debian 11. The important signal is that Installed is (none) and no nginx.org repository appears in the version table.

Related Debian and Nginx Guides

Use these next-step guides according to the package source and site task you choose after the mainline install.

Conclusion

Nginx Mainline is installed from nginx.org, pinned at a higher APT priority than Debian’s default package source, and verified with service, syntax, and local HTTP checks. From here, configure a site under /etc/nginx/conf.d/, test every change with sudo nginx -t, and keep updates flowing through APT.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Let us know you are human: