# Reverse Proxy and TLS

Fronting internal services with a proxy that terminates TLS, routes by hostname and issues certificates automatically.

**Rests on:** LTS Distribution Choice

*MLOps and Platform · Self-Hosting*


## Why learn this

This is how you run any service you host at home—like a blog, a file server, or an AI tool—safely on the internet. Without this setup, you would have to leave every service open directly, which is dangerous and messy. You would also spend hours manually updating security keys when they expire. By mastering this, you get three concrete benefits: first, a single door for all your services so you don't have to remember different connection addresses; second, automatic renewal of the security certificates that show the padlock icon in your browser, so you never get locked out; and third, the ability to send visitors to the right place based on what they type (for example, sending someone who types `blog.yourdomain.com` to your writing app and someone who types `api.yourdomain.com` to your AI tool). This prevents security holes and keeps your services running reliably.


## The intuition

Think of your home office or apartment building. You have a single front door that the outside world can see. Inside, you have many different rooms: one for your blog, one for your photo library, one for your personal data storage. Each room is on a different 'street address' (port) inside the house, but none of those internal addresses are visible or reachable from the street. The **reverse proxy** is like a highly efficient receptionist standing at that single front door. Visitors do not know where your rooms are; they just walk up to the door and tell the receptionist what they need. If someone says, 'I want to see the blog,' the receptionist checks a list, sees that the blog is in Room 2, and politely escorts them there. The other rooms stay private and secure. This centralizes control: if you want to change which room holds your blog, you only update the receptionist's list, not the instructions for every visitor on the internet. The **TLS certificate** is like a specialized security badge system. It ensures that when you talk to someone through the front door, no one else can eavesdrop. The certificate itself is a digital ID card issued by a trusted authority (like Let's Encrypt) that proves you are who you say you are. Because these cards expire every 90 days, automation is key: you set it up once so that a 'security company' automatically replaces the expired badge with a new one before anyone notices, ensuring your site never goes down due to an expired ID.


## An analogy

Imagine a large corporate headquarters with many departments (your services). The company has only one public entrance (your IP address). All employees and visitors arrive here. A **receptionist** (the reverse proxy) sits at the desk. When a visitor says, 'I have an appointment with Sales,' the receptionist checks their list and routes them to Department 402. When someone else says, 'I want to access the HR portal,' the receptionist sends them to Department 105. The receptionist doesn't let anyone wander into the server room or pay offices directly; they only direct traffic based on where it needs to go. They also handle security by verifying IDs (the **TLS certificate**) at the gate, ensuring that only valid visitors enter and that their conversations are kept private behind encrypted glass walls. The analogy holds well for routing and basic security, but in reality, the receptionist also does heavy lifting like caching responses (remembering common answers to speed things up) and compressing data, which a human receptionist might not do automatically.


## Definition

A reverse proxy is a program that sits between your computer and the internet, acting as a single entry point that directs visitors to the correct internal service while handling all security connections automatically.


## How it connects

This concept builds on **Containerization**, which lets you isolate each service (like your blog or AI tool) in its own secure box, and is managed via **Docker Compose**, the tool you use to define how those boxes and the proxy interact. It is essential for **Ingress Routing**, which is simply the formal name for the rule set that tells the proxy where to send traffic based on the domain name typed by the user.


## The mathematics

The mathematics behind TLS and reverse proxies is not about equations you'll compute by hand — it's about cryptography, which uses number theory, but the concepts you need are simple arithmetic and logic. The main ideas are: 1) **Public and Private Keys**: A certificate contains a public key that everyone can see, and the server has a corresponding private key that is secret. When a client connects, they do a handshake where they agree on a session key using these keys. The math ensures that even if an eavesdropper sees the public key and the encrypted messages, they cannot decrypt them without the private key. 2) **Certificate Signing**: Let's Encrypt verifies you own the domain by having you place a file at a specific URL or set a DNS record. This is like proving you have a mailbox key. The math ensures that the certificate they issue is trusted by browsers because it's signed by a root certificate that the browser already trusts. 3) **Routing rules**: The reverse proxy's job is to match a hostname (like `app.example.com`) against patterns. This is string matching, not arithmetic, but the outcome is binary: if it matches, forward; if not, try next rule. So the 'mathematics' here is more about logic and protocols than calculation. The key branch of math is **number theory** (the foundation of public-key cryptography), but you don't need to learn it; you just need to understand the properties it guarantees: it's computationally infeasible to reverse the encryption without the key, and a digital signature is unforgeable. The operations you'll do in this page are: adding a forwarding rule (which is like adding a row to a table), and making sure the right ports are open (basic networking arithmetic, like port 443 is for HTTPS).

$\text{If } \text{Host} \in \{ \text{blog.example.com} \} \rightarrow \text{forward to } \text{http://127.0.0.1:3000}$


## A worked example

```
We'll walk through a concrete example of setting up a reverse proxy with auto-TLS. Let's say your server has an IP address 123.45.67.89, and you own the domain `example.com`. You want to expose two services: a blog at `blog.example.com` (running on port 3000) and an AI API at `api.example.com` (running on port 5000). You are using a reverse proxy (e.g., Traefik) and Let's Encrypt for certificates.

Step 1: Listen on port 443 (HTTPS) - this is the standard secure port   # The reverse proxy binds to the public IP on port 443, so all external traffic comes here.
Step 2: Rule: Host `blog.example.com` -> forward to `http://127.0.0.1:3000`   # This routing rule says: if the `Host` header in the request is `blog.example.com`, send it to the internal blog service.
Step 3: Rule: Host `api.example.com` -> forward to `http://127.0.0.1:5000`   # Similarly, API subdomain routes to the API service.
Step 4: DNS A record: `blog.example.com` and `api.example.com` both point to 123.45.67.89   # You set up DNS so both subdomains resolve to your server's public IP, so the request reaches the reverse proxy.
Step 5: Let's Encrypt verification: ACME HTTP-01 challenge places a token at `http://blog.example.com/.well-known/acme-challenge/{token}`   # To prove you own the domain, the ACME protocol asks you to serve a token at a specific URL path. The reverse proxy automatically responds to this.
Step 6: Certificate issued: `blog.example.com` gets a certificate with public key and private key stored in /etc/traefik/certs   # The certificate is valid for 90 days, and will be renewed automatically 30 days before expiry.

Result: The reverse proxy now serves `blog.example.com` and `api.example.com` over HTTPS automatically, with certificates that renew themselves, no manual intervention required.
```


## From scratch, in Python

We'll look at a simple configuration file for a reverse proxy (Traefik) and a Docker Compose setup. This is more config than code, but it shows the core concepts. The learner doesn't need Python for this, but we can show a simple Python HTTP server as a placeholder for an internal service.

First, a minimal Python HTTP server that will be one of our 'internal services' (e.g., the blog):

```python
# blog_server.py - a simple HTTP server that runs on port 3000
from http.server import HTTPServer, BaseHTTPRequestHandler

class HelloHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b'<h1>Blog!</h1>')

if __name__ == '__main__':
    server = HTTPServer(('127.0.0.1', 3000), HelloHandler)
    print('Serving on port 3000')
    server.serve_forever()
```

Now, a `docker-compose.yml` to run the reverse proxy (Traefik) alongside this service:

```yaml
version: '3'
services:
  blog:
    build: .
    ports:
      - "127.0.0.1:3000:3000"  # only localhost can reach this directly
    labels:
      - "traefik.http.routers.blog.rule=Host(`blog.example.com`)"
      - "traefik.http.routers.blog.tls.certresolver=letsencrypt"
  reverse-proxy:
    image: traefik:v2.9
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "./traefik.toml:/etc/traefik/traefik.toml"
```

And the `traefik.toml` configuration for auto-TLS:

```toml
[entryPoints]
  [entryPoints.web]  # port 80 for ACME challenge
    address = ":80"
  [entryPoints.websecure]  # port 443 for HTTPS
    address = ":443"

[certificatesResolvers.letsencrypt.acme]
  email = "you@example.com"
  storage = "acme.json"
  httpChallenge = true
```


## What the code does

The Python server is the 'internal service' — it listens only on localhost (127.0.0.1) on port 3000, so it's not exposed to the internet. The Docker Compose file declares two services: 'blog' (the internal service) and 'reverse-proxy' (Traefik). The blog container's port is bound to localhost:3000, so only the host machine can reach it directly. Traefik is a reverse proxy; it has two ports exposed: 80 (HTTP) and 443 (HTTPS). It also mounts the Docker socket so it can discover the blog service. The labels on the blog service tell Traefik: 'if the Host header is blog.example.com, route to this service, and get a TLS certificate from Let's Encrypt.' The `traefik.toml` file sets up the entry points and the ACME resolver with your email and a storage file for certificates. When a request comes in for `https://blog.example.com`, Traefik accepts the TLS connection (terminates it), reads the Host header, matches the rule, and forwards it to the blog container. When the certificate is about to expire, Traefik automatically requests a new one from Let's Encrypt.


## Common misconceptions

**"A reverse proxy is just like a VPN"** — A VPN connects you to a private network; a reverse proxy just redirects traffic. They're different things.

A VPN creates an encrypted tunnel to a network, giving you access to internal resources as if you were on the network. A reverse proxy is a server that fronts your public services; it doesn't encrypt the entire connection between client and network, but it handles TLS per request. They could be used together, but they serve different purposes. In fact: A VPN is a private tunnel to a network; a reverse proxy is a single entrance to public services, handling TLS and routing.

**"TLS certificates never expire for services I don't visit often"** — If I set up a certificate for my API, it will work forever as long as no one complains.

Certificates have a validity period (typically 90 days for Let's Encrypt). If not renewed, the browser or client will reject the connection with a security error. Regular use isn't what keeps it alive; renewal is automated or manual. In fact: Certificates expire after a set time. Let's Encrypt certificates last 90 days; auto-renewal is essential to avoid downtime.

**"I need to open many ports, one for each service"** — To expose my blog and API, I need to open ports 3000 and 5000 on my firewall.

Best practice is to only expose port 80 (for ACME challenge) and 443 (HTTPS) to the internet. The reverse proxy listens on 443 and routes internally. Exposing other ports increases your attack surface and complicates firewall rules. In fact: Open only port 80 and 443; the reverse proxy routes traffic to internal services on private ports.

**"The reverse proxy is a single point of failure, so I should avoid it"** — If the proxy fails, everything goes down, so it's risky.

Yes, the proxy is a single point of failure, but with proper configuration (e.g., restart policies, more replicas) and health checks, this can be mitigated. The benefits of centralised routing and TLS management far outweigh the risk for most self-hosted setups. In fact: A reverse proxy is a dependency, but with Docker's restart policies and multiple replicas, it can be made resilient.

**"I can set up TLS once and forget it"** — After I configure certificates, I don't need to think about them again.

Certificates have a finite lifespan. Without automatic renewal, you'll need to manually renew them every ~90 days, which is error-prone. Automation is what makes it 'forget' possible. In fact: Automatic renewal is essential; manual renewal is a chore and the most common cause of outages.


## In short

A reverse proxy is your single front door to the internet: it handles TLS (the secure padlock), routes requests by hostname to your internal services, and with automatic certificate issuance (Let's Encrypt), it renews that padlock before it breaks. This removes the most common self-hosting failure — certificate expiry. Remember: only expose ports 80 and 443, let the proxy terminate TLS, and let automation handle the certificates.


## Where this is used

This concept is everywhere in modern AI deployment and self-hosting. **Large language models (LLMs)**: When you run an LLM like Llama 2 on your own server and expose it through an API (e.g., using something like vLLM or text-generation-webui), you put it behind a reverse proxy like Nginx or Traefik. The reverse proxy terminates TLS so users can call `https://llm.yourdomain.com/v1/...` securely. It can also handle load balancing (if you have multiple replicas), rate limiting, and requesting authentication headers. **Small language models on devices**: For a local model on a Raspberry Pi or a phone, you don't need a reverse proxy — it's local. But if you want to expose it to your LAN for your other devices, you might use a simple proxy to add TLS and access control. The concept is the same: one entry point to your model. **Retrieval-augmented generation (RAG)**: In a RAG pipeline, you have multiple services: a document store (e.g., a vector database like Weaviate), an embedding service, and the LLM. Each runs on a different port. A reverse proxy routes requests to the right service based on the path: `/embed` goes to the embedding service, `/search` to the vector DB, and `/generate` to the LLM. It also adds TLS to every service, so your entire RAG API is secure. **Agentic systems**: When you build an agent that calls tools, the agent might be running on one server and the tools (e.g., web search, code execution) on another. The reverse proxy can securely forward requests from the agent to the tool services, with proper authentication headers and TLS, so no secrets are exposed in URL parameters. **Everyday applied ML**: If you're a data scientist deploying a Flask model to production, you put Gunicorn behind Nginx, and Nginx acts as a reverse proxy to handle TLS, serve static files, and pass requests to the model's workers. The developer's workflow: they write a `Dockerfile` and a `docker-compose.yml` that include the model API and the reverse proxy service. They set labels or config to route the domain to the model. They open port 80 and 443 on their firewall. They make sure `acme.json` is writable for certificate storage. What breaks: if the certificate expires and auto-renewal fails (e.g., because the ACME challenge can't be completed due to DNS misconfiguration or the volume for `acme.json` is not persistent), the site shows a browser warning. If routing is wrong, requests go to the wrong service or 404. If you don't set up the proxy correctly and expose the internal service directly, you introduce security risks and have to manage multiple certificates manually — and that is the most common self-hosting failure this page is designed to fix.


---

Read this on the web: https://basavapurushottam.com/learn-ai/reverse-proxy-and-tls
