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
sudofor 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/debianinstead 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 namednginx.
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 Source | Current Line Checked | Update Owner | Best For | Trade-off |
|---|---|---|---|---|
| nginx.org Mainline | 1.31.0 packages for Debian 13, 12, and 11 | nginx.org through APT | New upstream features, newer dynamic module packages, earlier upstream fixes | Faster branch movement can expose compatibility issues sooner |
| nginx.org Stable | 1.30.1 upstream stable branch | nginx.org through APT when the stable repository URI is used | Upstream packaging with a slower branch cadence | Not the branch installed by this mainline repository workflow |
| Debian default APT sources | Debian 13: 1.26.3-3+deb13u5; Debian 12: 1.22.1-9+deb12u7; Debian 11: 1.18.0-6.1+deb11u6 | Debian security and release updates | Conservative server installs that do not need newer upstream Nginx behavior | Older 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.confis 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.logand/var/log/nginx/error.logstore 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.
- Build Nginx from source on Debian when packaged modules or repository branches do not fit your requirement.
- Secure Nginx with Let’s Encrypt on Debian after your server block points at the correct domain.
- Enable gzip compression in Nginx for a common static-asset optimization step.
- Install Fail2Ban on Debian when SSH and web-facing services need log-based abuse protection.
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.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>