An Nginx reverse proxy receives requests from website visitors and forwards them to another server or application. It’s commonly used to make applications running on ports such as 3000 accessible through a domain name, without exposing their internal ports to the internet.
In this tutorial, you’ll configure Nginx on Ubuntu to forward requests to a local application, connect a domain, and enable HTTPS.
What Is an Nginx Reverse Proxy?
A reverse proxy sits between visitors and your backend application.
Instead of connecting directly to an application running on port 3000, visitors connect to Nginx on the standard HTTP or HTTPS ports.
Nginx forwards the request to the application and returns its response.
The request flow looks like this:
Visitor → Nginx → Backend Application
This setup is commonly used for Node.js, Python, and other web applications. It can also support TLS termination, load balancing, and centralized request handling.
Prerequisites
Before starting, you’ll need:
- An Ubuntu 24.04 LTS server with sudo access.
- SSH access to your server.
- A domain name pointing to your server’s public IP address.
- A backend application listening on a local port.
We’ll use port 3000 in this example.
If you’re new to SSH, read our SSH commands beginner’s guide before continuing.

Step 1: Install Nginx on Ubuntu
Connect to your Ubuntu server through SSH.
Update the package index and install Nginx:
sudo apt update
sudo apt install nginx -y
Check whether Nginx is running:
sudo systemctl status nginx
You should see active (running).
If Nginx isn’t started, run:
sudo systemctl enable --now nginx
You can also visit your server’s public IP address in a browser. The default Nginx welcome page should appear if HTTP access is allowed.
If you’re using UFW, allow HTTP and HTTPS traffic:
sudo ufw allow 'Nginx Full'
Also check any firewall rules configured through your hosting provider. Don’t disable the firewall to make Nginx accessible.
Step 2: Start a Test Backend Application
Before configuring the reverse proxy, we need an application for Nginx to forward requests to.
For a simple test, create a temporary directory:
mkdir -p ~/nginx-proxy-test
cd ~/nginx-proxy-test
Create a basic HTML page:
echo '<h1>Nginx Reverse Proxy Works!</h1>' > index.html
Now start Python’s built-in HTTP server:
python3 -m http.server 3000 --bind 127.0.0.1
This serves your test page on port 3000, accessible only through the local loopback address.
Leave this terminal running and open a second SSH session.
Verify that the application responds:
curl http://127.0.0.1:3000
You should see:
<h1>Nginx Reverse Proxy Works!</h1>
This Python server is only for demonstration. For a production application, use its recommended application server and service-management setup.
Step 3: Create an Nginx Reverse Proxy Configuration
Create a new Nginx server block:
sudo nano /etc/nginx/sites-available/app.example.com
Replace app.example.com with your actual domain.
Add the following configuration:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}
Save the file.
Understanding the Configuration
listen 80accepts HTTP requests.server_namespecifies the domain Nginx should handle.proxy_passforwards requests to the application on port 3000.proxy_set_headerpasses useful information about the original request to the backend.
The backend must understand and safely handle forwarded headers. Only configure applications to trust these headers when requests arrive through your trusted proxy.
Step 4: Enable and Test the Configuration
Enable your new server block:
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
If the link already exists, don’t recreate it.
Check the configuration for errors:
sudo nginx -t
If the test succeeds, reload Nginx:
sudo systemctl reload nginx
Now open:
http://app.example.com
If DNS is pointing to the correct server and the test backend is still running, you should see:
Nginx Reverse Proxy Works!
If the default Nginx page appears instead, check your domain’s DNS records and server_name configuration.
Step 5: Enable HTTPS with Let’s Encrypt
For a public website, use HTTPS rather than leaving traffic unencrypted.
First, confirm your domain resolves to the correct server and that inbound port 80 is accessible. These are important for the standard HTTP certificate-validation process.
Install Certbot using the official Snap-based approach:
sudo snap install --classic certbot
If the certbot command isn’t already available, create the command link:
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
Then request a certificate:
sudo certbot --nginx -d app.example.com
Follow the prompts. Certbot can obtain a certificate and configure Nginx to serve your domain over HTTPS.
Afterward, test certificate renewal:
sudo certbot renew --dry-run
Visit:
https://app.example.com
Your test application should now load through an encrypted connection.
Step 6: Verify Your Reverse Proxy
Check the HTTPS response:
curl -I https://app.example.com
For the example Python backend, an HTTP 200 OK response indicates that the request reached the application successfully.
You can also check which processes are listening on your server:
sudo ss -ltnp
Your Nginx installation should listen on the configured public HTTP and HTTPS ports, while the example backend listens on 127.0.0.1:3000.
Remember that the temporary Python server will stop when you terminate its terminal session. Production applications should run under a process supervisor such as systemd.
Common Nginx Reverse Proxy Problems
502 Bad Gateway
This usually means Nginx couldn’t receive a valid response from the backend.
Check that your application is running and that the port in proxy_pass is correct.
Our guide to fixing 502 Bad Gateway in Nginx covers logs, upstream services, and connection problems in more detail.
504 Gateway Timeout
A 504 error occurs when the gateway doesn’t receive the required upstream response in time.
Investigate slow application requests and backend performance before increasing timeouts.
See our 504 Gateway Timeout troubleshooting guide for further instructions.
The Domain Doesn’t Load
Check that your domain’s A record points to the correct public IP address, the relevant firewall ports are open, and the Nginx server block matches the requested hostname.
Frequently Asked Questions
proxy_pass tells Nginx where to forward requests, such as an HTTP application running on 127.0.0.1:3000.
Yes. You can configure separate domains, subdomains, or URL paths to forward requests to different backend applications.
No. You can test a reverse proxy with an IP address or locally. However, a domain makes public hosting and obtaining a standard HTTPS certificate more straightforward.
Yes. Open-source Nginx supports reverse proxy functionality without requiring a commercial license.
Conclusion
You’ve configured an Nginx reverse proxy on Ubuntu, forwarded requests to a local application, and enabled HTTPS.
The same basic configuration can be adapted for Node.js, Python, and other HTTP-based applications by updating the backend address in proxy_pass.
Before using the setup in production, ensure your application starts automatically, runs under appropriate permissions, and has adequate monitoring and security controls.