> For the complete documentation index, see [llms.txt](https://docs.readyidc.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.readyidc.com/gpu-as-a-service/linux/docker/how-to-using-nginx-reverse-proxy-ssl-guide.md).

# How to using nginx reverse proxy ssl guide

> Securely expose your vLLM API, Open WebUI, AnythingLLM, or n8n to the internet with HTTPS. Uses nginx + Let's Encrypt (free SSL certificates).

{% hint style="info" %}
**Prerequisite:** A domain name pointing to your server's public IP.
{% endhint %}

***

## 1. Why Use a Reverse Proxy?

| Benefit                | Description                                              |
| ---------------------- | -------------------------------------------------------- |
| **HTTPS/SSL**          | Encrypt traffic; required for production                 |
| **Clean URLs**         | `https://api.yourdomain.com` instead of `http://ip:8000` |
| **Single entry point** | Route multiple services through one domain               |
| **Security**           | Hide internal ports, add rate limiting, access control   |
| **Streaming support**  | Proper SSE/streaming for LLM token output                |

### Services & Default Ports

| Service     | Internal Port | Suggested Subdomain   |
| ----------- | ------------- | --------------------- |
| vLLM API    | 8000          | `api.yourdomain.com`  |
| Open WebUI  | 3000          | `chat.yourdomain.com` |
| AnythingLLM | 3001          | `docs.yourdomain.com` |
| n8n         | 5678          | `n8n.yourdomain.com`  |

***

## 2. DNS Setup

Point your domain(s) to the server's public IP. Create **A records**:

```
api.yourdomain.com    →  A  →  <your-server-public-ip>
chat.yourdomain.com   →  A  →  <your-server-public-ip>
docs.yourdomain.com   →  A  →  <your-server-public-ip>
n8n.yourdomain.com    →  A  →  <your-server-public-ip>
```

Verify DNS propagation:

```bash
dig +short api.yourdomain.com
# should return your server IP
```

***

## 3. Install nginx + Certbot

```bash
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx

# Allow HTTP/HTTPS through firewall
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
```

Verify nginx is running:

```bash
sudo systemctl status nginx
```

***

## 4. Reverse Proxy Configs

Create a config per service. The vLLM API config includes **streaming support** (critical for token-by-token output).

{% tabs %}
{% tab title="vLLM API — `/etc/nginx/sites-available/vllm-api`" %}

```nginx
server {
    listen 80;
    server_name api.yourdomain.com;

    # Large request bodies (long prompts)
    client_max_body_size 10M;

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

        # Streaming (SSE) support — REQUIRED for LLM token streaming
        proxy_buffering off;
        proxy_cache off;
        proxy_set_header Connection '';
        chunked_transfer_encoding off;

        # Long generation timeouts
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}
```

{% endtab %}

{% tab title="Open WebUI — `/etc/nginx/sites-available/openwebui`" %}

```nginx
server {
    listen 80;
    server_name chat.yourdomain.com;
    client_max_body_size 50M;

    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;

        # WebSocket support (for live UI updates)
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_buffering off;
        proxy_read_timeout 300s;
    }
}
```

{% endtab %}

{% tab title="AnythingLLM — `/etc/nginx/sites-available/anythingllm`" %}

```nginx
server {
    listen 80;
    server_name docs.yourdomain.com;
    client_max_body_size 100M;     # large document uploads

    location / {
        proxy_pass http://127.0.0.1:3001;
        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 "upgrade";
        proxy_read_timeout 300s;
    }
}
```

{% endtab %}

{% tab title="n8n — `/etc/nginx/sites-available/n8n`" %}

```nginx
server {
    listen 80;
    server_name n8n.yourdomain.com;
    client_max_body_size 50M;

    location / {
        proxy_pass http://127.0.0.1:5678;
        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 "upgrade";
        proxy_read_timeout 300s;
    }
}
```

{% endtab %}
{% endtabs %}

### Enable Configs

```bash
# Enable each site
sudo ln -s /etc/nginx/sites-available/vllm-api /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/openwebui /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/anythingllm /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/

# Test config
sudo nginx -t

# Reload
sudo systemctl reload nginx
```

***

## 5. Enable SSL with Let's Encrypt

Certbot automatically obtains certificates and modifies your nginx configs to use HTTPS.

```bash
# Get certificates for all domains at once
sudo certbot --nginx \
  -d api.yourdomain.com \
  -d chat.yourdomain.com \
  -d docs.yourdomain.com \
  -d n8n.yourdomain.com
```

Follow the prompts:

* Enter email (for renewal notices)
* Agree to terms
* Choose **redirect HTTP → HTTPS** (recommended)

### Auto-Renewal

Certbot installs a renewal timer automatically. Verify:

```bash
sudo certbot renew --dry-run
sudo systemctl status certbot.timer
```

Certificates renew automatically before expiry (90-day certs, renewed at \~60 days).

### Verify HTTPS

```bash
curl https://api.yourdomain.com/v1/models
```

***

## 6. Securing the API

Exposing an LLM API publicly invites abuse. Add these protections.

### 6.1 API Key (vLLM built-in)

Ensure vLLM runs with `--api-key`:

```yaml
command: >
  --model ...
  --api-key sk-your-strong-secret-key
```

Clients must send: `Authorization: Bearer sk-your-strong-secret-key`

### 6.2 Rate Limiting (nginx)

Add to the **top** of `/etc/nginx/nginx.conf` inside the `http {}` block:

```nginx
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
```

Then in the vLLM API `location /` block:

```nginx
        limit_req zone=api_limit burst=20 nodelay;
```

### 6.3 IP Allowlist (Optional)

Restrict API access to specific IPs:

```nginx
    location / {
        allow 203.0.113.0/24;    # your office/VPN range
        allow 198.51.100.5;       # specific IP
        deny all;
        proxy_pass http://127.0.0.1:8000;
        # ... rest of proxy config
    }
```

### 6.4 Basic Auth (extra layer)

```bash
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd apiuser
```

In the location block:

```nginx
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;
```

***

## 7. Troubleshooting

<details>

<summary>Certbot fails — "Could not connect"</summary>

* DNS not propagated yet: `dig +short api.yourdomain.com`
* Port 80 blocked: `sudo ufw allow 'Nginx Full'`
* nginx not running: `sudo systemctl start nginx`

</details>

<details>

<summary>502 Bad Gateway</summary>

* Backend service not running: `docker compose ps`
* Wrong port in `proxy_pass`: verify service port
* Test backend directly: `curl http://127.0.0.1:8000/v1/models`

</details>

<details>

<summary>Streaming/SSE not working (responses arrive all at once)</summary>

* Ensure `proxy_buffering off;` is set in the API config
* Confirm `proxy_http_version 1.1;`

</details>

<details>

<summary>"413 Request Entity Too Large"</summary>

* Increase `client_max_body_size` in the relevant config

</details>

<details>

<summary>WebSocket errors (Open WebUI / n8n)</summary>

* Ensure `proxy_set_header Upgrade $http_upgrade;` and `Connection "upgrade";` are present

</details>

<details>

<summary>Certificate renewal issues</summary>

```bash
sudo certbot renew --dry-run
sudo nginx -t && sudo systemctl reload nginx
```

</details>

***

## Quick Reference

```bash
# Test nginx config
sudo nginx -t

# Reload nginx
sudo systemctl reload nginx

# Get/renew SSL
sudo certbot --nginx -d yourdomain.com
sudo certbot renew --dry-run

# Check what's listening
sudo ss -tlnp | grep -E ':(80|443|8000|3000|3001|5678)'
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.readyidc.com/gpu-as-a-service/linux/docker/how-to-using-nginx-reverse-proxy-ssl-guide.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
