applications Azure

NGINX 1.28 Stable on Ubuntu 24.04 LTS | cloudimg

| Product: nginx-1-28

NGINX 1.28 Stable on Ubuntu 24.04 LTS

NGINX 1.28 is the current stable mainline release of the most widely deployed web server on the Internet. It serves static content, reverse-proxies application servers, terminates TLS, load-balances across backends, caches, rate-limits, and speaks HTTP/1.1, HTTP/2, and HTTP/3 (QUIC). This cloudimg image installs NGINX 1.28 from the official nginx.org APT repository onto Ubuntu 24.04 LTS (Noble Numbat) and ships a ready-to-edit welcome page plus a sample reverse-proxy server block.

Prerequisites

  • An Azure subscription with permission to create virtual machines
  • An SSH key pair — the public key is uploaded during VM creation
  • A domain name pointed at your VM's public IP if you plan to request a Let's Encrypt TLS certificate

Step 1 — Deploy from the Azure Portal

  1. Find NGINX 1.28 Stable on Ubuntu 24.04 LTS by cloudimg in the Azure Marketplace and click Create.
  2. On the Basics tab, select or create a Resource Group, choose East US as the region, and set the VM size to Standard_B2s (2 vCPU / 4 GB RAM) for a lightweight reverse proxy, or Standard_D2s_v3 (2 vCPU / 8 GB RAM) and upward for production TLS-terminating workloads.
  3. Under Administrator account, choose SSH public key and paste your public key.
  4. On the Networking tab, open inbound ports 80 (HTTP) and 443 (HTTPS) in addition to 22 (SSH).
  5. Click Review + create, then Create.

Step 2 — Deploy with the Azure CLI

az vm create \
  --resource-group <your-resource-group> \
  --name nginx-1-28 \
  --image "$(az sig image-version list \
       --resource-group AZURE-CLOUDIMG \
       --gallery-name cloudimgGallery \
       --gallery-image-definition nginx-1-28-ubuntu-24-04 \
       --query '[0].id' -o tsv)" \
  --size Standard_D2s_v3 \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard

After the VM starts, open HTTP and HTTPS:

az vm open-port --port 80  --resource-group <your-resource-group> --name nginx-1-28 --priority 1010
az vm open-port --port 443 --resource-group <your-resource-group> --name nginx-1-28 --priority 1011

Step 3 — Connect via SSH

ssh azureuser@<vm-ip>

On first boot, nginx-firstboot.service marks the image as live and enables nginx.service. The service is a quick one-shot and completes in under a second.

Step 4 — Verify NGINX is Running

Check the service status and listening ports:

sudo systemctl status nginx --no-pager
sudo ss -tln | grep -E ':80|:443'

Confirm the mainline version shipped in this image:

sudo nginx -v

Parse the configuration to make sure it is syntactically valid:

sudo nginx -t

Fetch the landing page locally. The cloudimg welcome page is served from /usr/share/nginx/html/index.html.

curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/
curl -sI http://127.0.0.1/ | grep -iE '^(HTTP|Server|Content-Type)'

NGINX 1.28 verification output: nginx -v, systemctl status nginx, nginx -t, and curl -I response headers captured from the cloudimg Azure image

From a browser, open http://<vm-ip>/ and you should see the cloudimg NGINX 1.28 landing page. That page is a template — replace it with your own content in Step 5.

cloudimg NGINX 1.28 Stable welcome page served from the fresh Azure Marketplace image

Step 5 — Publish Your Own Content

The active document root is /usr/share/nginx/html. Replace the welcome page with your own HTML:

sudo tee /usr/share/nginx/html/index.html > /dev/null <<'HTML'
<!doctype html>
<html><head><meta charset="utf-8"><title>Hello from NGINX</title></head>
<body><h1>Hello from NGINX 1.28 on Azure by cloudimg.</h1></body></html>
HTML

Reload NGINX to pick up any file changes without dropping connections:

sudo nginx -s reload

Fetch the new page:

curl -s http://127.0.0.1/ | head -3

For larger sites, upload your content into /usr/share/nginx/html/ or configure an alternate document root in a server block (see Step 6).

Step 6 — Configure a Reverse Proxy Server Block

A sample reverse-proxy server block is shipped at /etc/nginx/conf.d/cloudimg-example.conf.disabled. Rename it and edit the upstream to point at your backend:

sudo cat /etc/nginx/conf.d/cloudimg-example.conf.disabled

Copy it into an active server block — edit the upstream backend block and the server_name line for your domain. For example, to reverse-proxy a Node.js app running on 127.0.0.1:8080:

sudo tee /etc/nginx/conf.d/backend.conf > /dev/null <<'CONF'
upstream backend {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name _;

    location / {
        proxy_pass         http://backend;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}
CONF

Disable the default server block so the new one answers:

sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.disabled

Validate the configuration and reload:

sudo nginx -t && sudo nginx -s reload

Step 7 — Add TLS with Let's Encrypt (certbot)

Install certbot and the NGINX plugin from the Ubuntu archive:

sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx

Request and install a certificate for your domain. Replace example.com and the email address with your own. certbot will edit your server block in place to listen on port 443 and redirect port 80 to HTTPS:

sudo certbot --nginx -d example.com -d www.example.com -m you@example.com --agree-tos --no-eff-email --redirect

certbot installs a systemd timer that renews certificates automatically twice a day.

Step 8 — Enable HTTP/2 and HTTP/3 (QUIC)

HTTP/2 is enabled automatically by certbot. NGINX 1.28 also supports HTTP/3 over QUIC on UDP port 443. Edit the 443 server block to add a QUIC listener alongside the TCP listener:

server {
    listen 443 ssl;
    listen 443 quic reuseport;
    http2 on;
    http3 on;
    add_header Alt-Svc 'h3=":443"; ma=86400';
    ...
}

Open UDP 443 on the VM's Network Security Group:

az network nsg rule create \
    --resource-group <your-resource-group> \
    --nsg-name <your-nsg> \
    --name allow-http3 \
    --priority 1012 \
    --protocol Udp --destination-port-ranges 443 \
    --access Allow --direction Inbound

Reload NGINX and verify the QUIC listener is bound:

sudo nginx -t && sudo nginx -s reload

Step 9 — Configure Rate Limiting and Caching

Rate-limit requests per client IP. Define a zone in the http {} block of /etc/nginx/nginx.conf, then apply it in a location block:

http {
    limit_req_zone $binary_remote_addr zone=api_zone:10m rate=10r/s;
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=edge_cache:100m max_size=1g inactive=60m use_temp_path=off;
}

server {
    location /api/ {
        limit_req zone=api_zone burst=20 nodelay;
        proxy_pass http://backend;
    }

    location /static/ {
        proxy_cache edge_cache;
        proxy_cache_valid 200 1h;
        proxy_pass http://backend;
    }
}

Reload to activate:

sudo nginx -t && sudo nginx -s reload

Step 10 — Security Hardening

The image ships with server_tokens off already applied, which hides the NGINX version from response headers and error pages. Verify:

curl -sI http://127.0.0.1/ | grep -i '^server:'

Add recommended security headers to your server block:

add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

Restrict admin endpoints by IP allowlist:

location /admin/ {
    allow 203.0.113.0/24;
    deny  all;
    proxy_pass http://backend;
}

Keep NGINX up to date by enabling unattended security upgrades from the nginx.org APT repo:

sudo apt-get update
sudo apt-get install -y --only-upgrade nginx

Step 11 — Everyday Operations

Reload the configuration without dropping connections:

sudo nginx -s reload

Check error and access logs:

sudo tail -50 /var/log/nginx/error.log
sudo tail -50 /var/log/nginx/access.log

Stop, start, or restart the service:

sudo systemctl restart nginx

Support

cloudimg provides 24/7/365 expert technical support. Guaranteed response within 24 hours, one hour average for critical issues. Contact support@cloudimg.co.uk.