> ## Documentation Index
> Fetch the complete documentation index at: https://help.freakhosting.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Set Up Nginx as a Reverse Proxy

> Set up Nginx as a reverse proxy: add proxy_pass http://127.0.0.1:3000 to a server block, pass the Host and X-Forwarded headers, enable WebSockets and add HTTPS.

To set up Nginx as a reverse proxy, add a server block with `location / { proxy_pass http://127.0.0.1:3000; }` plus the `Host`, `X-Real-IP`, `X-Forwarded-For` and `X-Forwarded-Proto` headers, then run `sudo nginx -t` and `sudo systemctl reload nginx`. Your app keeps listening only on `127.0.0.1`, and Nginx serves it on ports 80 and 443 with your domain and HTTPS.

| Difficulty | Time | Works on | Needs |
| - | - | - | - |
| Intermediate | 15 minutes | Ubuntu 22.04 / 24.04, Debian 12 / 13, AlmaLinux / Rocky 9 / 10 | Nginx, an app on a local port, sudo |

## Before you start

* [Install Nginx](https://help.freakhosting.com/portals/other/how-to-install-nginx.md) and point your domain at the server ([point a domain](https://help.freakhosting.com/portals/other/how-to-point-a-domain-to-your-server.md)).
* Start your app and check it answers locally, for example `curl http://127.0.0.1:3000`. This guide uses port `3000` and the domain `app.example.com`.
* Use a user with `sudo`. If you are `root`, leave out `sudo`.

A reverse proxy sits in front of your app. Visitors talk to Nginx; Nginx forwards each request to the app and returns the answer. This gives you one place for HTTPS, domains, logs and limits, and your app port is never exposed.

## How to configure the reverse proxy

**1. Create the server block**

Ubuntu / Debian: `/etc/nginx/sites-available/app.example.com`. AlmaLinux / Rocky: `/etc/nginx/conf.d/app.example.com.conf`.

```nginx theme={null}
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

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

    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;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}
```

The `map` block and the `Upgrade` / `Connection` headers let WebSocket connections through. Define the `map` only once across all your config files.

**2. Enable the site (Ubuntu / Debian only)**

```bash theme={null}
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
```

**3. Allow Nginx to connect to the app (AlmaLinux / Rocky only)**

SELinux blocks Nginx from opening network connections by default. Allow it:

```bash theme={null}
sudo setsebool -P httpd_can_network_connect 1
```

**4. Test and reload**

```bash theme={null}
sudo nginx -t
sudo systemctl reload nginx
```

### What each line does

| Directive | Why |
| - | - |
| `proxy_pass http://127.0.0.1:3000;` | Where the app listens. Use `http://unix:/run/app/app.sock;` for a Unix socket. |
| `proxy_http_version 1.1;` | Needed for WebSockets and keep-alive. Nginx only made 1.1 the default in version 1.29.7; distribution packages are older. |
| `Host $host` | Passes the domain the visitor asked for. By default Nginx sends the `proxy_pass` address instead. |
| `X-Real-IP`, `X-Forwarded-For` | The visitor's real IP. Without them, your app sees every request as coming from `127.0.0.1`. |
| `X-Forwarded-Proto $scheme` | Tells the app whether the visitor used `http` or `https`, so it builds correct links. |

## How to check it worked

```bash theme={null}
curl -H "Host: app.example.com" http://127.0.0.1/
```

You should get your app's response, the same as `curl http://127.0.0.1:3000`. Then open `http://app.example.com` in a browser.

If you see `502 Bad Gateway`, Nginx could not reach the app. The error log names the reason, for example `connect() failed (111: Connection refused) while connecting to upstream`. See [fix 502 Bad Gateway](https://help.freakhosting.com/portals/other/how-to-fix-502-bad-gateway-nginx.md).

## How to add HTTPS

Run Certbot for the proxied domain:

```bash theme={null}
sudo certbot --nginx -d app.example.com
```

Certbot adds the `listen 443 ssl` lines and the certificate to this server block. See [free SSL with Certbot](https://help.freakhosting.com/portals/other/how-to-get-a-free-ssl-certificate-with-certbot.md).

> [!WARNING]
>
> Make your app listen on `127.0.0.1`, not `0.0.0.0`, and do not open its port (such as 3000) in your firewall. Otherwise visitors can bypass Nginx and HTTPS.

## How to proxy long requests or large uploads

Nginx closes a proxied request if the app sends nothing for 60 seconds (`proxy_read_timeout`) and refuses request bodies over 1 MB (`client_max_body_size`). Raise them only where needed:

```nginx theme={null}
location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_read_timeout 300s;
    client_max_body_size 50M;
    # keep the proxy_set_header lines from above
}
```

## Frequently asked questions

### My app still logs 127.0.0.1 as the client IP. Why?

The app must be told to trust the proxy and read `X-Forwarded-For`. In Express, set `app.set('trust proxy', 'loopback')`; in Django or Flask, use the framework's proxy settings. Only trust the header from `127.0.0.1`.

### Can I proxy a sub-path like example.com/app/?

Yes: `location /app/ { proxy_pass http://127.0.0.1:3000/; }`. The trailing slash on `proxy_pass` strips `/app/` before the request reaches the app. Many apps also need a base-path setting.

### Can Nginx balance across several app instances?

Yes. Define `upstream app_servers { server 127.0.0.1:3000; server 127.0.0.1:3001; }` in the `http` context and use `proxy_pass http://app_servers;`.

### Is Caddy easier for this?

Caddy needs one line, `reverse_proxy 127.0.0.1:3000`, and adds HTTPS by itself. See [install Caddy](https://help.freakhosting.com/portals/other/how-to-install-caddy-web-server.md).

## Related guides

> [card] [VPS and dedicated server guides](https://help.freakhosting.com/portals/other/vps-and-dedicated-server-guides.md)
>
> Every server guide in one place.

> [card] [Node.js with PM2](https://help.freakhosting.com/portals/other/how-to-install-nodejs-and-run-apps-with-pm2.md)
>
> Run the app behind the proxy.

> [card] [Python with Gunicorn](https://help.freakhosting.com/portals/other/how-to-deploy-a-python-app-with-gunicorn.md)
>
> Flask and Django behind Nginx.

> [card] [Fix 502 Bad Gateway](https://help.freakhosting.com/portals/other/how-to-fix-502-bad-gateway-nginx.md)
>
> When the upstream fails.

> [card] [Free SSL with Certbot](https://help.freakhosting.com/portals/other/how-to-get-a-free-ssl-certificate-with-certbot.md)
>
> HTTPS for your proxy.

***

> [!NOTE]
>
> **Checked against the official [nginx proxy module documentation](https://nginx.org/en/docs/http/ngx_http_proxy_module.html), [nginx WebSocket proxying guide](https://nginx.org/en/docs/http/websocket.html) and [Red Hat Enterprise Linux 9 Nginx guide](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/deploying_web_servers_and_reverse_proxies/setting-up-and-configuring-nginx_deploying-web-servers-and-reverse-proxies)** on 4 November 2026; proxy configuration tested on Ubuntu 24.04 LTS (Nginx 1.24.0) with a Node.js app. Commands can differ on other distributions or releases.

> [!NOTE]
>
> ### Need Extra Help?
>
> If you encounter any issues, our support team is ready to assist:
>
> * **Live Chat:** Quick assistance via our website.
> * **Support Ticket:** [Open a Ticket](https://freakhosting.com/clientarea/submitticket.php)
> * **Discord:** [Join our Community](https://discord.gg/freakhosting)
> * **Email:** [support@freakhosting.com](mailto:support@freakhosting.com)

> [!TIP]
>
> ### Save on Your Hosting
>
> Ready to upgrade your hosting? Use code **KB20** at checkout for **20% off** your first order!

***

**Last Updated:** November 2026


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.