After setting up my AI homelab and various other services in a previous blog post, my friend Nader and I experimented with how to access some of these services using a domain instead of the IP address without exposing our home IP or opening ports.
In this blog post, I will guide you through setting up a local reverse proxy on Proxmox with Traefik v3 and Cloudflare. This setup will allow you to access your services with a domain name and also secure them with SSL certificates.
What is a reverse proxy?
A reverse proxy is a server that sits between clients and servers. It forwards client requests to the appropriate backend server and then returns the server’s response to the client. This allows you to host multiple services on a single server and route traffic based on the domain name.
In this simplified diagram, the user wants to access “MyService.MyDomain.tld”, the requests goes through the DNS resolver, which gets a local IP address from Cloudflare and then the reverse proxy forwards the request to the correct service.
My Proxmox setup
On my Proxmox setup I have a few LXC containers running various services. I have a dedicated LXC container for Traefik v3, which is an underprivileged Alpine Linux container with Docker installed. This setup is, in my opinion, the most stable way to run Traefik on Proxmox.
If you want to replicate the setup I used the ttek script to create the LXC container. You should accept the docker compose installation and the script will install Docker and Docker Compose for you.
bash -c "$(wget -qO - https://github.com/tteck/Proxmox/raw/main/ct/alpine-docker.sh)"
Setting up Traefik on Docker
From this point on the setup is heavily inspired by the excellent video tutorial of Techno Tim. Inside the Traefik LXC container, create a folder for the Traefik configuration
mkdir traefik
cd traefik
touch docker-compose.yml
services:
traefik:
image: traefik:latest # Use the latest Traefik image
container_name: traefik # Name of the container
restart: unless-stopped # Ensures the container restarts if it stops unexpectedly
security_opt:
- no-new-privileges:true # Prevents the container from gaining additional privileges
networks:
proxy: # Connects to the predefined external network named 'proxy'
ports:
- 80:80 # HTTP port
- 443:443 # HTTPS port
- 8080:8080 # Traefik dashboard port
environment:
- CF_API_EMAIL=YOUR_CLOUDFLARE_ACCOUNT_EMAIL # Cloudflare account email for API access
- CF_DNS_API_TOKEN=YOUR_CLOUDFLARE_API_TOKEN_HERE # Cloudflare DNS API token
volumes:
- /etc/localtime:/etc/localtime:ro # Sync time with the host
- /var/run/docker.sock:/var/run/docker.sock:ro # Allows Traefik to interact with Docker
- /root/traefik/data/traefik.yml:/traefik.yml:ro # Traefik configuration file
- /root/traefik/data/acme.json:/acme.json # SSL certificate file
- /root/traefik/data/config.yml:/config.yml:ro # Additional configuration file
- /root/traefik/data/logs:/var/log/traefik # Log directory
labels:
- "traefik.enable=true" # Enable Traefik on this service
- "traefik.http.routers.traefik.entrypoints=http" # Define HTTP entrypoint
- "traefik.http.routers.traefik.rule=Host(`traefik.MyDomain.TLD`)" # Host rule for routing
- "traefik.http.middlewares.traefik-auth.basicauth.users=traefik:$2y$$05$$fkKKsDM0LEQAG6nPuk7dxeJElSkGJxCeuCsZgwoQWqPzyZdRkfYeK" # Basic auth for security traefik for username/pass
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https" # Redirect HTTP to HTTPS
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https" # Set forwarded headers for SSL
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect" # Apply HTTPS redirect middleware
- "traefik.http.routers.traefik-secure.entrypoints=https" # Secure entrypoint for HTTPS
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.MyDomain.TLD`)" # Host rule for secure routing
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth" # Apply authentication middleware
- "traefik.http.routers.traefik-secure.tls=true" # Enable TLS for secure connection
- "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare" # Use Cloudflare for SSL certificate resolution
- "traefik.http.routers.traefik-secure.tls.domains[0].main=MyDomain.TLD" # Main domain for SSL certificate
- "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.MyDomain.TLD" # SANs for SSL certificate
- "traefik.http.routers.traefik-secure.service=api@internal" # Internal service for Traefik API
networks:
proxy:
name: proxy # Specifies the external network to connect to
external: true # Indicates that the network is external
Configuring Traefik v3 with our services
Get your Cloudflare DNS API key with a restricted scope for the zone you want to use. Add a docker-compose.yml
file with the following content:
In the data
folder we need 3 files:
mkdir data
cd data
Add a traefik.yml
file with the following content:
api:
dashboard: true
debug: true
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: ":443"
traefik:
address: ":8080"
serversTransport:
insecureSkipVerify: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
filename: config.yml
certificatesResolvers:
cloudflare:
acme:
email: YOUR_CLOUDFLARE_ACCOUNT_EMAIL
storage: acme.json
dnsChallenge:
provider: cloudflare
# uncomment this if you have issues pulling certificates through cloudflare, By setting this flag to true disables the need to wait for the
#disablePropagationCheck: true
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
Add a config.yml
file with the following content:
http:
#region routers
routers:
dashboard:
entryPoints:
- "https"
rule: "Host(`MyDomain.TLD`)"
middlewares:
- default-headers
- https-redirectscheme
tls: {}
service: dashboard
#endregion
#region services
services:
dashboard:
loadBalancer:
servers:
- url: "http://192.168.1.200:8080"
passHostHeader: true
#endregion
#region middlewares
middlewares:
https-redirectscheme:
redirectScheme:
scheme: https
permanent: true
default-headers:
headers:
frameDeny: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 15552000
customFrameOptionsValue: SAMEORIGIN
customRequestHeaders:
X-Forwarded-Proto: https
default-whitelist:
ipWhiteList:
sourceRange:
- "10.0.0.0/8"
- "192.168.0.0/16"
- "172.16.0.0/12"
secured:
chain:
middlewares:
- default-whitelist
- default-headers
#endregion
Add a blank acme.json
file:
touch acme.json
chmod 600 acme.json
At start this file will be empty, but Traefik will populate it with the SSL certificates it gets from certbot and the DNS verification through Cloudflare.
Setting up your domain with Cloudflare
Before running Traefik, it’s essential to configure your domain’s DNS settings on Cloudflare to ensure that your services are accessible via your domain name and secured with SSL. Here are the steps to set up the necessary DNS records:
Log in to your Cloudflare account and select the domain you want to configure.
Navigate to the DNS section of your Cloudflare dashboard.
Add the following DNS records:
- A Record: This should point to the local IP address of your Traefik container. Set the name to
@
to represent your root domain (e.g.,MyDomain.TLD
). - CNAME Record: Create a CNAME record for each subdomain that points to your root domain. For example, if you have a service accessible at
MyService.MyDomain.TLD
, create a CNAME record with the nameMyService
and the valueMyDomain.TLD
.
- A Record: This should point to the local IP address of your Traefik container. Set the name to
Ensure Proxy Status: Set the proxy status to ‘DNS Only’ for these records.
SSL/TLS Configuration:
- Go to the SSL/TLS section of your Cloudflare dashboard.
- Ensure that the SSL/TLS encryption mode is set to ‘Full (strict)‘. This ensures that the connection between Cloudflare and your server is secure.
Starting Traefik
In your root folder `/traefik, run the following command to start the Traefik container:
docker network create proxy
docker compose up -d --force-recreate
At this point you should be able to access the Traefik dashboard at https://traefik.MyDomain.TLD
with the username/password you set in the docker-compose.yml
file.
Conclusion
Setting up a local reverse proxy using Proxmox, Traefik, and Cloudflare enhances the security and accessibility of your services. By following the steps outlined in this guide, you can achieve a robust setup that protects your services with SSL certificates and makes them accessible via domain names instead of IP addresses.
If you found this guide useful you can also check the previous ones about Using venv, pyvenv-autoenv, and macOS and Abstracting local development environments through containers.