Install Nginx on Debian 12 and Ubuntu 24.04 from the Official Repository
Install Nginx from the official nginx.org repository on Debian 12 or Ubuntu 24.04. Covers signing key setup, apt pinning, firewall rules for both UFW and nftables, systemd management, and verification after every step.
This tutorial installs Nginx from the official nginx.org repository on a Debian 12 or Ubuntu 24.04 VPS. You get the latest version (1.28.2 stable or 1.29.6 mainline) instead of the outdated package shipped by your distro. Every step includes verification so you know exactly what happened.
For context on where Nginx fits in your server stack, see Nginx Administration on a VPS.
Prerequisites
You need:
- A VPS running Debian 12 (Bookworm) or Ubuntu 24.04 (Noble Numbat)
- A non-root user with
sudoprivileges - SSH access to the server
All commands in this tutorial run as a sudo user. Not root.
Should I install Nginx stable or mainline?
Nginx maintains two branches. Stable (even version number, currently 1.28.x) receives only critical bug fixes. Mainline (odd version number, currently 1.29.x) gets all new features, bug fixes, and security patches. The Nginx team recommends mainline for production. Stable exists for users who want minimal changes between updates.
| Stable | Mainline | |
|---|---|---|
| Current version | 1.28.2 | 1.29.6 |
| Update frequency | Critical fixes only | Every 4-6 weeks |
| New features | No | Yes |
| Recommended by nginx.org | For conservative setups | For production use |
This tutorial defaults to stable. To install mainline instead, swap the repository URL where noted.
Why use the official repository instead of the distro package?
The default apt repositories on Debian 12 and Ubuntu 24.04 ship Nginx 1.22.1 and 1.24.0, respectively. These are months to years behind the official releases. The nginx.org repository gives you the latest stable or mainline build, maintained by the Nginx team.
| Source | Debian 12 version | Ubuntu 24.04 version | Maintained by |
|---|---|---|---|
| Distro repo | 1.22.1 | 1.24.0 | OS maintainers |
| nginx.org stable | 1.28.2 | 1.28.2 | Nginx team |
| nginx.org mainline | 1.29.6 | 1.29.6 | Nginx team |
How do I install Nginx on Debian 12 from the official repository?
Install the prerequisites, add the nginx.org signing key, configure the apt source, pin the repository, and install. This takes about two minutes.
Step 1: Install prerequisites
sudo apt update
sudo apt install -y curl gnupg2 ca-certificates lsb-release debian-archive-keyring
Step 2: Import the nginx.org signing key
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
Check the key fingerprint:
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
the output lists multiple signing keys. Look for this fingerprint among them:
573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
If none of the listed fingerprints match, remove the file and re-download. A mismatched key means the download was intercepted or corrupted.
Step 3: Add the apt repository
For stable:
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/debian $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
For mainline, replace packages with packages/mainline:
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/mainline/debian $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
Step 4: Pin the official repository
This ensures apt prefers the nginx.org package over the distro version:
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
Without pinning, a future apt upgrade could replace the official package with the older distro version.
Step 5: Install Nginx
sudo apt update
sudo apt install -y nginx
Step 6: Start and verify the installation
nginx -v
Expected output for stable:
nginx version: nginx/1.28.2
The nginx.org package does not start automatically after installation. Start it now:
sudo systemctl start nginx
Check that the service is running:
sudo systemctl status nginx
look for Active: active (running) in the output.
Confirm Nginx is listening on port 80:
ss -tlnp | grep :80
Expected output:
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=...,fd=...))
Test the welcome page:
curl -I http://localhost
the response should include HTTP/1.1 200 OK and Server: nginx/1.28.2.
How do I install Nginx on Ubuntu 24.04 from the official repository?
The process is almost identical to Debian. The only differences are the prerequisites package and the repository URL.
Step 1: Install prerequisites
sudo apt update
sudo apt install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring
Note: Ubuntu uses ubuntu-keyring instead of debian-archive-keyring.
Step 2: Import the nginx.org signing key
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
Check the fingerprint (same key as Debian):
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
Look for 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 among the listed keys.
Step 3: Add the apt repository
For stable:
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
For mainline:
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
Step 4: Pin the official repository
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
Step 5: Install Nginx
sudo apt update
sudo apt install -y nginx
Step 6: Start and verify the installation
Start Nginx (it does not start automatically after installation):
sudo systemctl start nginx
Run the same verification as Debian:
nginx -v
sudo systemctl status nginx
ss -tlnp | grep :80
curl -I http://localhost
You should see nginx/1.28.2 (stable) or nginx/1.29.6 (mainline) in both nginx -v and the curl response headers.
How do I manage Nginx with systemd?
Nginx ships a systemd unit file. These are the commands you will use daily.
| Command | What it does |
|---|---|
sudo systemctl start nginx |
Start Nginx |
sudo systemctl stop nginx |
Stop Nginx |
sudo systemctl restart nginx |
Stop then start (drops connections) |
sudo systemctl reload nginx |
Reload config without dropping connections |
sudo systemctl enable nginx |
Start on boot |
sudo systemctl disable nginx |
Do not start on boot |
sudo systemctl status nginx |
Show running state and recent logs |
Reload vs restart: Use reload after configuration changes. It applies the new config without dropping active connections. Use restart only when you have changed binary-level settings or upgraded Nginx. Reload is safe. Restart drops every active connection.
Enable Nginx to start on boot:
sudo systemctl enable nginx
Always test your configuration before reloading:
sudo nginx -t
Expected output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
If nginx -t reports errors, fix them before reloading. A failed reload leaves the previous config running. A failed restart leaves Nginx down.
How do I configure UFW firewall rules for Nginx?
UFW (Uncomplicated Firewall) is the default firewall frontend on Ubuntu. It is available on Debian but not installed by default. Some VPS images ship without UFW. If ufw is not found, install it first:
sudo apt install -y ufw
The nginx.org package does not include UFW application profiles (Nginx Full, Nginx HTTP, Nginx HTTPS). Those profiles only ship with the distro package. Use port numbers instead.
Allow SSH first (so you do not lock yourself out):
sudo ufw allow OpenSSH
Allow both HTTP (80) and HTTPS (443):
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
If you only need HTTPS:
sudo ufw allow 443/tcp
Make sure UFW is enabled:
sudo ufw enable
Check the active rules:
sudo ufw status
Expected output includes:
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
If ufw status shows Status: inactive, run sudo ufw enable first.
How do I configure nftables firewall rules for Nginx?
Debian 12 uses nftables as its default firewall backend. If you manage firewall rules directly (without UFW), add Nginx ports to your nftables configuration.
Edit your nftables config:
sudo nano /etc/nftables.conf
Add these rules inside your input chain (within your inet filter table):
tcp dport { 80, 443 } accept
A minimal working configuration looks like this:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
tcp dport 22 accept
tcp dport { 80, 443 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Apply the rules:
sudo nft -f /etc/nftables.conf
Confirm it works:
sudo nft list ruleset
look for tcp dport { 80, 443 } accept in the output. If it is missing, the rules were not applied.
Enable nftables on boot:
sudo systemctl enable nftables
How do I verify Nginx is running correctly?
After installation and firewall setup, run through this checklist.
From the server:
nginx -v
sudo systemctl status nginx
ss -tlnp | grep :80
curl -I http://localhost
From your local machine (replace YOUR_SERVER_IP):
curl -I http://YOUR_SERVER_IP
Expected response headers:
HTTP/1.1 200 OK
Server: nginx/1.28.2
If the external curl times out but localhost works, your firewall is blocking port 80. Go back to the UFW or nftables section above.
You can also open http://YOUR_SERVER_IP in a browser. You should see the "Welcome to nginx!" page.
Key file and directory locations
| Path | Purpose |
|---|---|
/etc/nginx/nginx.conf |
Main configuration file |
/etc/nginx/conf.d/ |
Additional config files (loaded by default) |
/var/log/nginx/access.log |
Access log |
/var/log/nginx/error.log |
Error log |
/usr/share/nginx/html/ |
Default document root |
The official nginx.org package uses /etc/nginx/conf.d/ for site configurations. This differs from the distro package, which uses sites-available/ and sites-enabled/. Both approaches work. The conf.d pattern is simpler.
To learn how Nginx configuration files are organized, see Nginx Config File Structure Explained. To host multiple domains on this server, see Nginx Server Blocks: Host Multiple Domains on One VPS.
Ready to try it yourself?
Host your web applications on a reliable VPS. →