Nginx reverse proxy with FastAPI: publishing an API with HTTPS

Published on 2026-10-26 by frfrand

Configure Nginx and Uvicorn on a VPS with TLS and local upstream

Nginx reverse proxy with FastAPI: publishing an API with HTTPS

Your FastAPI API responds on localhost:8000, but you want a client to open it at https://api.ejemplo.com. Nginx can receive HTTPS and forward to the internal port without exposing Uvicorn directly to the Internet.

Let's turn it into a procedure you can use on a real VPS. The goal is to understand why it works, how to test it, and what problem appears if one part is misconfigured.

What Nginx reverse proxy means for FastAPI and when you need it

The reverse proxy is a public layer that manages connections and can direct requests to several services according to domain. FastAPI continues running as a private process, normally supervised by systemd or inside a container. HTTPS terminates at Nginx and the application receives the internal request.

Before changing anything in production, note the current state: IP, domain, port, affected service, and time of last deploy. An isolated modification is easy to check; five simultaneous changes make it harder to reconstruct what happened.

Configuration or example commands

# /etc/nginx/sites-available/api.ejemplo.com
server {
    listen 80;
    server_name api.ejemplo.com;
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
# Validar sintaxis ANTES de recargar
sudo nginx -t
sudo systemctl reload nginx

Domains, IP, routes, and names are illustrative. Do not copy an entire configuration over the current one without comparing first. In examples that include ports or firewall, make sure to keep administrative access.

How I would do it step by step

  1. Preparation. Check that FastAPI works locally with curl http://127.0.0.1:8000/health.
  2. Step 2. Create a server block with server_name corresponding to the domain DNS.
  3. Step 3. Configure the proxy to the internal port and the appropriate headers.
  4. Step 4. Enable HTTPS with a valid certificate; the HTTP block is only the starting point.
  5. Verification. Verify nginx -t, reload, and test via the domain from another network.

When finished, check the actual operation from another connection. For example, for an API it is not enough to open the browser: run a read request, a write to a test database, and check the process logs.

Example of a real project

A booking app has React on app.ejemplo.com and FastAPI on api.ejemplo.com. Both domains point to the same VPS, but Nginx routes each one to its corresponding service. PostgreSQL remains in the private environment.

The lesson is simple: an infrastructure configuration does not live isolated from the application. The frontend, the server, the database, and the workers connect, so measuring where the failure starts is more useful than restarting everything.

The mistake to avoid

Do not confuse proxy_pass with the URL used by the browser. If FastAPI uses cookie-based authentication or generated links, check headers and trusted proxy configuration. Never enable --proxy-headers without controlling who can connect to the process.

When working with client servers, keep a backup or rollback procedure before changes that affect data, network, or certificates. And if you don't know what permissions an operation needs, avoid running it as root just to make errors stop appearing.

How does it relate to ArduMaker?

On an ArduMaker VPS you can manage domain, HTTPS, and backend service while keeping internal port 8000. This helps host several applications without opening a port per project.

In a typical case you can create a VPS for the application, deploy from Git, associate HTTPS domain, and manage the backend and necessary databases. The tools help centralize operations, but you must understand which port and process fulfills each function.

Questions that arise when you try it

How do I know if the failure is DNS or the service? Check resolution first, then connection to the port, and finally the application response. That order avoids confusing different problems.

Can I expose a database to make it easier to maintain? Better design private access or authenticated tunnels when possible. Exposing a port does not replace engine permissions nor the firewall.

What should I document? The expected configuration, how it is verified, and how to return to the previous state. That document helps you more than a list of commands without context.

References

In summary: a good network or server configuration is one that you can explain, verify, and recover when something fails.

  • Nginx
  • Tutorial
  • ArduMaker

Keep reading

All articles · VPS plans