Install Nginx on Debian 12 and Ubuntu 24.04 from the Official Repository

7 min read·Matthieu·NginxDebianUbuntuWeb ServerFirewall|

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 sudo privileges
  • 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.