Set up an Nginx reverse proxy on Ubuntu

A reverse proxy places Nginx between the public internet and an application server. Visitors connect to a normal domain name, while Nginx forwards their requests to a service listening on a private port such as 127.0.0.1:3000. This hides the application’s internal address and gives you one place to manage routing, TLS certificates, request limits, and logs.

This guide uses Ubuntu 24.04 LTS with an application already running on the server. You will configure Nginx, obtain an HTTPS certificate, protect the server with the firewall, and check the complete request path. The same arrangement works for a self-hosted WordPress site, a small API, a development preview, or a business application used by staff across Australia.

You need administrative access to the Ubuntu machine, a public IP address, and control of a domain name. Before changing DNS, confirm that the application responds locally and that its data is stored safely. Keep the original server configuration available so you can compare settings if a request behaves differently after it passes through the proxy.

Prepare the server and backend application

Start by updating the operating system and checking the server’s basic settings:

sudo apt update
sudo apt upgrade -y
sudo apt install curl
timedatectl

Keeping the clock accurate matters because TLS validation, certificate renewal, and application sessions depend on correct time. Automatic security updates are enabled by default on current Ubuntu releases, although you should still review the schedule to suit your maintenance window. Run sudo reboot after a kernel update only when you can reconnect to the machine.

The backend application must listen on an address that Nginx can reach. A local port such as 3000 or 8080 is suitable, provided the application binds to 127.0.0.1 rather than 0.0.0.0. Test it with curl http://127.0.0.1:3000, replacing the port with the one your service uses. A blank response or connection refusal means the service has not started or is bound somewhere else; fix that before involving Nginx.

Point DNS at the server next. For an Australian business, a .com.au or .au domain is a natural choice, with the hostname recorded as an A record for IPv4 and an AAAA record for IPv6 only when the server has a working IPv6 address. Cloud hosting in Sydney, Melbourne, Brisbane, or another major city generally gives Australian visitors lower latency than an overseas region. An incorrect AAAA record can make some devices try an unreachable IPv6 route, so remove stale records.

Install Nginx and define the server name

Install Nginx, enable it at boot, and remove the default site from the enabled configuration:

sudo apt install nginx
sudo systemctl enable --now nginx
sudo rm /etc/nginx/sites-enabled/default

The rm command removes only the symlink that activates the default site; the original file remains in /etc/nginx/sites-available. This prevents the default catch-all page from competing with your hostname. Check that Nginx is active with systemctl status nginx, and confirm its version and compiled modules with nginx -V.

Each hostname should have its own file under /etc/nginx/sites-available, followed by a symlink in /etc/nginx/sites-enabled. This keeps websites isolated and makes a particular service easy to disable or move. Before reloading, run sudo nginx -t; a syntax error should be corrected before the configuration is applied. The general UbuntuNext guidance is useful for additional Ubuntu administration and open-source background.

Configure Nginx to forward requests

Create /etc/nginx/sites-available/app.example.com.au and replace the hostname and backend port with your own values:

server {
    listen 80;
    listen [::]:80;
    server_name app.example.com.au;

    client_max_body_size 20M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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;
    }
}

Enable the file with sudo ln -s /etc/nginx/sites-available/app.example.com.au /etc/nginx/sites-enabled/app.example.com.au, then test and reload it:

sudo nginx -t
sudo systemctl reload nginx

The forwarded headers carry information about the original request. Host preserves the hostname requested by the browser, while the X-Forwarded-* headers identify the client address and original protocol. Applications such as WordPress, Node.js, and Django may use these values to generate correct links, record client addresses, or enforce HTTPS. Configure the application to trust forwarded headers only from the local proxy, and sanitize them at the edge if another proxy or content delivery network sits in front of Nginx.

Some applications also use WebSockets. Create /etc/nginx/conf.d/websocket-upgrade.conf with:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Then add Upgrade and Connection header directives to the relevant location block. Keep the map outside the server block. This allows a live connection to remain open without forcing an upgrade header onto ordinary requests.

Add HTTPS with a trusted certificate

Port 80 currently handles the initial HTTP request. To encrypt traffic with a widely trusted certificate, install Certbot’s Nginx integration:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d app.example.com.au

Follow the prompts to select the correct hostname and allow Certbot to redirect HTTP to HTTPS. The process uses ACME validation to prove that the server controls the domain. It requires inbound port 80 to remain reachable during issuance and renewal, even when normal visitors are redirected to port 443. If the hostname also serves www, include it with another -d option during the same request.

Certbot normally renews certificates automatically through a systemd timer. Verify that arrangement with systemctl status certbot.timer and sudo certbot renew --dry-run. The dry run contacts the certificate authority and exercises the renewal hooks without issuing a replacement certificate. Renewed files are placed under /etc/letsencrypt, and Certbot’s Nginx plugin reloads the web server after installation.

Do not copy private certificate keys into application directories or source repositories. They should remain readable only by the account that needs them, normally root. For a busy Australian storefront or service, HTTPS also prevents passwords, session cookies, and customer details from being exposed on public Wi-Fi, a common situation when staff connect through café networks or mobile broadband.

Protect the server and plan for local requirements

Allow SSH before enabling the Ubuntu firewall, especially if the server uses a nonstandard SSH port. The normal commands are:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose

The firewall should permit outbound connections for package updates and allow inbound HTTP and HTTPS traffic. Cloud providers often apply a separate network security group, so both layers may need adjustment. If the application port is already blocked at the operating-system level, leaving it closed is ideal; Nginx can still reach it over the loopback interface. If another proxy, such as a CDN, reaches Nginx, restrict port 80 and 443 to the provider’s published addresses where practical.

Review what Nginx logs. Access logs help identify failed requests and unusual traffic, but IP addresses, URLs, and user-agent strings can contain personal information. Apply sensible retention limits, protect the log directory, and avoid recording request bodies or authentication credentials. The Australian market includes many small retailers, professional services, and creators operating online stores or customer portals, so Australian-dollar checkout, local payment providers, and clear support procedures should continue to work normally through the proxy.

Privacy obligations depend on the information being processed. If the service handles personal information, assess its responsibilities under the Privacy Act 1988 and the Australian Privacy Principles, including the Notifiable Data Breaches scheme. Health information may also engage state and territory legislation. Reverse proxying does not transfer legal responsibility away from the organisation operating the application, and a valid TLS certificate does not replace appropriate privacy controls.

Verify, monitor, and operate the proxy

Test the layers separately. The backend should respond on its local port, Nginx should respond when given the correct Host header, and the public HTTPS address should work from another device:

curl -I http://127.0.0.1:3000
curl -I -H "Host: app.example.com.au" http://127.0.0.1
curl -I https://app.example.com.au/

If the local test fails, inspect the application service rather than Nginx. If the local request works but the host-header test fails, examine the server block, enabled-site symlink, and error log. Access and error records live under /var/log/nginx, and sudo tail -f /var/log/nginx/error.log is useful while reproducing a problem. After changes, always run sudo nginx -t before reloading the service.

Monitor certificate expiry, disk space, memory use, and response errors. Ubuntu’s logrotate configuration handles the standard Nginx log files, while systemd restarts the service after a crash. Fixed-line NBN connections can perform well, but latency varies by exchange and region, while 4G and 5G mobile connections may introduce extra delay. Locating the server near the main customer base and avoiding unnecessary proxy layers generally produces more consistent response times.

Open https://app.example.com.au/ in a browser and confirm that the application appears with a valid certificate.