KAHIBARO
Discord Login Register

HTTPS and Domain Setup

Overview

In the final project, your backend will run on a real server and must be reachable securely over HTTPS using a human friendly domain name. This chapter walks through the practical setup from “I have an IP” to “my API is available at https://api.myapp.com”.

You will connect four main pieces:

We will focus on simple, repeatable setups that work for small production systems.


Domains, DNS, and IPs

Before you can enable HTTPS, you must have:

Domain and DNS basics for this project

You buy a domain name from a domain registrar such as:

The domain has DNS records. DNS is a global phonebook that translates names like api.myapp.com to IP addresses like 203.0.113.10.

You control DNS records from your registrar or from a DNS provider like Cloudflare or AWS Route 53.

Two record types are most useful for your backend:

Record typeTypical useExample
AMap name to IPv4 addressapi.myapp.com -> 203.0.113.10
CNAMEAlias one name to another namewww.myapp.com -> myapp.com

For HTTPS, certificate authorities must be able to resolve your domain to your server IP, so DNS must be correct before you request certificates.

Example: DNS records for a backend API

Imagine you have:

In your DNS panel you might create:

NameTypeValuePurpose
myapp.comA203.0.113.10Main website / frontend
api.myapp.comA203.0.113.10Backend API
wwwCNAMEmyapp.comwww.myapp.com to myapp.com

After saving, DNS changes can take minutes to propagate. Use tools such as:

bash
# On Linux/macOS
dig api.myapp.com
# On Windows
nslookup api.myapp.com

Verify that api.myapp.com resolves to your server IP before going further.


HTTP vs HTTPS in production

Your backend may already work with HTTP, for example:

This is fine for local development, but not safe for production.

Why HTTPS is mandatory

HTTPS is simply HTTP over TLS. It provides:

Without HTTPS:

Always expose your production backend only over HTTPS. Never send credentials, tokens, or session cookies over plain HTTP in production.

In your final project, you will keep HTTP internally on the same machine (for example Nginx to Uvicorn) and expose only HTTPS to the internet.


Reverse proxy for HTTPS

Your FastAPI app usually runs on an internal port such as 8000. A reverse proxy sits in front of it, listens on ports 80 and 443, and forwards requests to your app.

Common choices:

This chapter will describe Nginx because it is widely used and integrates well with Docker.

Typical production flow

  1. Client accesses https://api.myapp.com/users.
  2. DNS resolves api.myapp.com to your server IP.
  3. Nginx on your server terminates HTTPS on port 443 (handles TLS).
  4. Nginx forwards the request using HTTP to http://backend:8000 or http://127.0.0.1:8000.
  5. FastAPI receives the request and returns a response.
  6. Nginx sends the encrypted response back to the client.

This lets Nginx handle certificates, redirects, compression, and buffering, while your app focuses on business logic.


Getting TLS certificates with Let’s Encrypt

To serve HTTPS you need a TLS certificate. Buying one manually is possible, but for small production systems Let’s Encrypt is the standard free option.

Let’s Encrypt uses the ACME protocol and tools like certbot to:

Requirements for Let’s Encrypt HTTP validation

For HTTP-01 validation:

If port 80 is blocked by firewall or ISP, you may need DNS-01 validation instead, which is usually managed via DNS APIs.


Basic Certbot + Nginx setup (without Docker)

If your final project is not containerized, a common setup is:

Step 1: Install Nginx

On Ubuntu:

bash
sudo apt update
sudo apt install nginx

Start and enable Nginx:

bash
sudo systemctl enable nginx
sudo systemctl start nginx

Visit http://your-server-ip/ to confirm you see the default Nginx welcome page.

Step 2: Create an Nginx server block

Create a configuration for your API, for example /etc/nginx/sites-available/api.myapp.com:

nginx
server {
    listen 80;
    server_name api.myapp.com;
    location / {
        proxy_pass http://127.0.0.1:8000;
        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 it:

bash
sudo ln -s /etc/nginx/sites-available/api.myapp.com \
           /etc/nginx/sites-enabled/api.myapp.com
sudo nginx -t   # test configuration
sudo systemctl reload nginx

Ensure your FastAPI app is running on 127.0.0.1:8000. Now http://api.myapp.com/docs should proxy correctly over HTTP.

Step 3: Install Certbot

On Ubuntu:

bash
sudo apt install certbot python3-certbot-nginx

Step 4: Obtain and configure the certificate

Run:

bash
sudo certbot --nginx -d api.myapp.com

Certbot will:

At the end you will have an Nginx configuration similar to:

nginx
server {
    listen 80;
    server_name api.myapp.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    server_name api.myapp.com;
    ssl_certificate /etc/letsencrypt/live/api.myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.myapp.com/privkey.pem;
    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

Try visiting https://api.myapp.com/docs. The browser should show a secure connection.


HTTPS with Docker and Nginx

In your final project you will likely run your backend in Docker. A common pattern is:

Example Docker Compose setup

A minimal docker-compose.yml could look like:

yaml
version: "3.9"
services:
  backend:
    build: ./backend
    container_name: backend
    expose:
      - "8000"
    environment:
      - ENV=production
  nginx:
    image: nginx:1.27-alpine
    container_name: nginx
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt:ro
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - backend

Here:

A simple Nginx config in ./nginx/conf.d/api.myapp.com.conf:

nginx
upstream backend_app {
    server backend:8000;
}
server {
    listen 80;
    server_name api.myapp.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    server_name api.myapp.com;
    ssl_certificate /etc/letsencrypt/live/api.myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.myapp.com/privkey.pem;
    location / {
        proxy_pass http://backend_app;
        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;
    }
}

In this example, Certbot is run on the host, not inside Docker, using the same /etc/letsencrypt path that is mounted read only into the Nginx container.

You would then run the same certbot --nginx -d api.myapp.com on the host, but adjust for the Docker based Nginx if needed, or use a webroot method.


Using Certbot with webroot in Docker setups

Sometimes the Certbot Nginx plugin does not work well inside Docker. In that case you can use the webroot method:

  1. Configure Nginx to serve a directory for ACME challenges.
  2. Point Certbot at that directory.

Nginx config:

nginx
server {
    listen 80;
    server_name api.myapp.com;
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    location / {
        proxy_pass http://backend_app;
        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;
    }
}

Mount the directory into Nginx and Certbot:

yaml
services:
  nginx:
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./certbot/www:/var/www/certbot
      - ./certbot/conf:/etc/letsencrypt
  certbot:
    image: certbot/certbot
    volumes:
      - ./certbot/www:/var/www/certbot
      - ./certbot/conf:/etc/letsencrypt

Then, on the host:

bash
docker compose run --rm certbot certonly \
  --webroot \
  --webroot-path /var/www/certbot \
  -d api.myapp.com

After this, certificates appear under ./certbot/conf/live/api.myapp.com/, which are shared with Nginx.


Automatic certificate renewal

Let’s Encrypt certificates are valid for 90 days. You must renew them regularly.

With Certbot installed on a Linux host, a systemd timer or cron job is usually set up automatically. You can check renewal with:

bash
sudo certbot renew --dry-run

In a Docker based certbot container approach, you can add a scheduled job on the host:

bash
0 3 * * * docker compose run --rm certbot certbot renew \
  --webroot --webroot-path /var/www/certbot && \
  docker compose kill -s HUP nginx

This example, to be placed in root crontab via sudo crontab -e, will:

Do not wait for certificates to expire. Always set up automated renewal and verify with a --dry-run command.


Redirecting HTTP to HTTPS

Once HTTPS works, you should ensure that all HTTP traffic is redirected to HTTPS.

In Nginx this is the standard pattern:

nginx
server {
    listen 80;
    server_name api.myapp.com;
    return 301 https://$host$request_uri;
}

Key points:

Test using curl:

bash
curl -I http://api.myapp.com/users

You should see:

text
HTTP/1.1 301 Moved Permanently
Location: https://api.myapp.com/users

Configuring your backend for HTTPS behind a proxy

Your FastAPI app still receives plain HTTP requests from Nginx, but the original client used HTTPS. For many APIs this is fine, but some frameworks use the scheme (http vs https) to:

Behind a reverse proxy, you should rely on headers that Nginx sets:

For Uvicorn / FastAPI behind Nginx, consider:

Example systemd service ExecStart:

ini
ExecStart=/usr/bin/uvicorn app.main:app \
  --host 127.0.0.1 \
  --port 8000 \
  --proxy-headers

This helps FastAPI generate correct HTTPS URLs in docs and handle security logic that depends on scheme.


Testing the full chain

After configuration, you should test:

  1. DNS: dig api.myapp.com shows your server IP.
  2. HTTP redirect:
bash
   curl -I http://api.myapp.com/health

Response should be a 301 redirect to HTTPS.

  1. HTTPS response:
bash
   curl -I https://api.myapp.com/health

Response should be 200 OK or your health check status.

  1. Certificate validity:
    • Use curl -v https://api.myapp.com/health and see certificate details.
    • Use online SSL checkers such as SSL Labs.
  2. OpenAPI docs in browser:
    • Visit https://api.myapp.com/docs and check that:
      • No mixed content warnings appear.
      • All API calls are made to https://api.myapp.com.
  3. Renewal dry run:
bash
   sudo certbot renew --dry-run

Security tips for HTTPS and domains

While the full security topic is covered in other chapters, keep these HTTPS related rules in mind:

Important HTTPS and domain rules:

  • Always redirect HTTP to HTTPS for production domains.
  • Never expose sensitive APIs over plain HTTP to the internet.
  • Use strong TLS settings in Nginx and keep it updated.
  • Protect private keys (privkey.pem) and restrict their permissions.
  • Use separate subdomains for internal admin panels, for example admin.myapp.com, and lock them behind strict authentication.

Additional practical tips:

nginx
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Putting it together for the final project

For your final project, a simple, realistic setup is:

  1. Buy a domain, for example myfinalapp.com.
  2. Create DNS A record:
    • api.myfinalapp.com -> <your-server-ip>.
  3. On your production server:
    • Run your FastAPI app on 127.0.0.1:8000 or inside a Docker container.
    • Install Nginx and configure it as a reverse proxy to your app.
  4. Install Certbot and obtain a Let’s Encrypt certificate for api.myfinalapp.com.
  5. Configure Nginx:
    • Listen on 80 and redirect to 443.
    • Listen on 443 with the certificate.
    • Proxy requests to your FastAPI app.
  6. Set up automatic certificate renewal and reload Nginx after renewals.
  7. Test the full flow and update configuration if you change domains or add more subdomains.

Once this is working, your production backend will be securely reachable at:

text
https://api.myfinalapp.com

Your other deployment tasks, such as CI/CD, logging, and monitoring, will build on top of this HTTPS and domain setup.

Views: 9

Comments

Please login to add a comment.

Don't have an account? Register now!