Networking Azure

freenginx on Ubuntu 24.04 on Azure User Guide

| Product: freenginx on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of freenginx on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. freenginx is a community-driven fork of the nginx HTTP server, reverse proxy and load balancer, maintained by Maxim Dounin. It keeps nginx's configuration language and behaviour, so everything you already know about nginx.conf, server blocks and location blocks applies unchanged.

The image ships freenginx 1.30.1 (the current stable line) compiled from the official source tarball with SSL, HTTP/2, real-IP, gzip-static, stub-status and sub-filter modules, and hardened compiler flags. Rather than a bare default, it boots with a production configuration: the server version is hidden (server_tokens off), only TLS 1.2 and 1.3 are accepted, HTTP/2 is on, gzip is enabled and common security headers are set. HTTPS works out of the box because each VM generates its own self-signed certificate, private key and Diffie-Hellman parameters at first boot — nothing secret is baked into the image.

What is included:

  • freenginx 1.30.1 compiled from source to /usr/sbin/nginx, running as the nginx system user

  • Hardened /etc/nginx/nginx.conf: server_tokens off, gzip, TLS 1.2/1.3, session hardening

  • Default site at /etc/nginx/conf.d/default.conf serving the cloudimg landing page on TCP 80 and TCP 443

  • Document root at /var/www/html

  • Per-VM self-signed TLS certificate, key and DH parameters generated at first boot in /etc/nginx/ssl/ (never shipped in the image)

  • Local-only stub_status health endpoint at /nginx_status (bound to 127.0.0.1)

  • Commented reverse-proxy location block ready for you to point at an upstream

  • nginx.service and freenginx-firstboot.service systemd units auto-starting on boot

  • Listeners: TCP 80 (HTTP), TCP 443 (HTTP/2 + TLS)

  • Ubuntu 24.04 LTS base with latest security patches applied at build time and unattended-upgrades enabled

  • Azure Linux Agent for seamless cloud integration and SSH key injection

  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • An active Azure subscription

  • A subscription to the freenginx on Ubuntu 24.04 listing on Azure Marketplace

  • An SSH public key for VM authentication

  • A virtual network and subnet in the target region

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for typical web and reverse-proxy traffic. freenginx is efficient with a small memory footprint — scale up only for very high request rates or large reverse-proxy fleets.

Step 1: Deploy from the Azure Portal

Navigate to Marketplace in the Azure Portal, search for freenginx, select the cloudimg publisher entry, and click Create.

On the Networking tab attach a network security group that allows inbound TCP 22 from your management IP range, and TCP 80 and TCP 443 from the client networks that should reach your site.

Click Review + create, wait for validation, then Create. Deployment takes around two minutes.

Step 2: Deploy from the Azure CLI

RG="freenginx-prod"
LOCATION="eastus"
VM_NAME="freenginx-01"
ADMIN_USER="azureuser"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/freenginx-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"

az group create --name "$RG" --location "$LOCATION"

az vm create \
  --resource-group "$RG" \
  --name "$VM_NAME" \
  --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s \
  --admin-username "$ADMIN_USER" \
  --ssh-key-values "$SSH_KEY" \
  --public-ip-sku Standard

Open the web ports on the VM's network security group (adjust the source ranges to your own networks):

az network nsg rule create --resource-group "$RG" --nsg-name "${VM_NAME}NSG" \
  --name allow-http  --priority 1001 --destination-port-ranges 80  --access Allow --protocol Tcp
az network nsg rule create --resource-group "$RG" --nsg-name "${VM_NAME}NSG" \
  --name allow-https --priority 1002 --destination-port-ranges 443 --access Allow --protocol Tcp

Step 3: Verify the service is running

SSH to the VM and confirm freenginx is active, enabled at boot, and listening on TCP 80 and 443. The self-signed certificate and DH parameters are generated once at first boot by freenginx-firstboot.service.

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

Expected output:

● nginx.service - freenginx - high performance web server (cloudimg)
     Loaded: loaded (/etc/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running)
nginx version: freenginx/1.30.1
LISTEN 0  511  0.0.0.0:80   0.0.0.0:*
LISTEN 0  511  0.0.0.0:443  0.0.0.0:*

freenginx nginx.service active and enabled, reporting version freenginx/1.30.1 and listening on TCP 80 and 443

Step 4: Review the build configuration

The image is compiled from the official freenginx source tarball. Inspect the exact modules and compiler flags it was built with, and confirm the running configuration passes a syntax test:

nginx -V
nginx -t

The build includes the SSL, HTTP/2, real-IP, stub-status, gzip-static and sub-filter modules, with stack-protector and RELRO hardening flags. nginx -t reports the configuration syntax is OK.

freenginx nginx -V build configuration listing the compiled modules and hardened compiler flags, with nginx -t reporting the configuration test is successful

Step 5: Confirm the hardened defaults and TLS

Check that the server version is hidden, the security headers are present, the per-VM self-signed certificate is in place, and HTTP/2 is negotiated on TCP 443:

curl -sI http://localhost/ | grep -iE '^HTTP|^Server:|^X-|^Referrer'
echo | openssl s_client -connect 127.0.0.1:443 2>/dev/null | openssl x509 -noout -subject -issuer -dates
curl -skI --http2 https://localhost/ | grep -iE '^HTTP|^strict-transport'

Server: freenginx appears with no version number (server_tokens off), the X-Content-Type-Options, X-Frame-Options and Referrer-Policy headers are set, the certificate is this VM's own self-signed cert, and HTTP/2 200 confirms HTTP/2 is active with HSTS on HTTPS.

curl showing HTTP 200 with a bare Server: freenginx header and security headers, the per-VM self-signed certificate subject and issuer, and an HTTP/2 200 response with HSTS on port 443

The default landing page is served from /var/www/html over both HTTP and HTTPS:

The default cloudimg freenginx landing page rendered in a browser over HTTP, confirming freenginx is serving content

Step 6: Serve your own website

Drop your files into the document root, or edit the default site. The document root is /var/www/html:

ls -la /var/www/html/
cat /etc/nginx/conf.d/default.conf

To serve your own static site, replace the contents of /var/www/html, then test and reload:

sudo nginx -t
sudo systemctl reload nginx

Step 7: Reverse-proxy an upstream application

freenginx makes an excellent reverse proxy and load balancer. The default site ships a commented location /app/ block — uncomment it in /etc/nginx/conf.d/default.conf and point proxy_pass at your backend:

location /app/ {
    proxy_pass         http://127.0.0.1:8080/;
    proxy_http_version 1.1;
    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;
}

To load-balance across several backends, declare an upstream block and proxy to it:

upstream app_pool {
    server 10.0.0.4:8080;
    server 10.0.0.5:8080;
}

server {
    listen 80;
    location / {
        proxy_pass http://app_pool;
    }
}

After editing any configuration, always validate before reloading — a reload never drops live connections:

sudo nginx -t
sudo systemctl reload nginx

Step 8: Install a real TLS certificate

The image ships with a per-VM self-signed certificate so HTTPS works immediately. To serve a certificate browsers trust, replace the two files referenced by the default :443 server block and reload:

  • /etc/nginx/ssl/cloudimg.crt — your certificate (full chain)
  • /etc/nginx/ssl/cloudimg.key — your private key
ssl_certificate      /etc/nginx/ssl/cloudimg.crt;
ssl_certificate_key  /etc/nginx/ssl/cloudimg.key;

Copy your certificate and key over those paths (keeping the key readable only by root), then:

sudo nginx -t
sudo systemctl reload nginx

For automated Let's Encrypt certificates, install certbot with the nginx plugin (sudo apt-get install -y python3-certbot-nginx) and run sudo certbot --nginx -d your-domain.example — Certbot rewrites the certificate paths for you and installs a renewal timer.

Security notes

  • No baked secret. The TLS private key, certificate and DH parameters are generated uniquely on every VM at first boot in /etc/nginx/ssl/; the private key is mode 0600 root:root. No two instances share a key, and nothing secret ships in the image.

  • Version hidden. server_tokens off means responses carry a bare Server: freenginx header with no version, reducing fingerprinting.

  • TLS 1.2 and 1.3 only, with session tickets disabled and HSTS set on HTTPS responses.

  • Local-only status. The stub_status metrics endpoint at /nginx_status is restricted to 127.0.0.1.

  • Patched at build time with unattended-upgrades left enabled, so the VM keeps receiving OS security updates.

Support