How to use Traefik for exposing Self Hosted Applications from your homelab
I will probably forget it so i will make a post so i can find it when i will forget it.
What you will need
- A VPS
- A VM/CT in your homelab
- Time
Login To Your VPS
- Use root@198.51.100.52 to login into your server.
- Make a folder with
mkdir -p compose/traefik
- Make a file named docker-compose.yml
- Paste in the file the following contents:
services:
traefik:
image: traefik:v3.5.2
restart: always
command:
- --configFile=/etc/traefik/traefik.yml
- --providers.file.directory=/etc/traefik/dynamic
- --log.level=INFO
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./acme.json:/acme.json
- ./conf/traefik.yml:/etc/traefik/traefik.yml:ro
- ./conf/dynamic:/etc/traefik/dynamic:ro # Mount the entire dynamic directory
container_name: traefik
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`traefik.voorbeeld.nl`)"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls=true"
- "traefik.http.routers.api.tls.certresolver=myresolver"
networks:
traefik:
external: true
Change joudomein.nl to your own domain.
- Make a conf folder with
mkdir -p conf
- Make in that folder two folders named rules and dynamic.
mkdir rules
mkdir dynamic
- Create a
traefik.ymlfile with the following contents. this file should in the rules folder.
# Entry points are the ports that Traefik listens on
entryPoints:
web:
address: ":80" # HTTP port
websecure:
address: ":443" # HTTPS port
# certificatesResolvers are used to generate SSL certificates
certificatesResolvers:
myresolver:
acme:
email: jij@voorbeeld.nl
storage: acme.json
httpChallenge:
entryPoint: web
# This enables the webinterface and API for Traefik
api:
dashboard: true
insecure: true
# Providers are used to configure the dynamic configuration of Traefik
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
directory: /etc/traefik/dynamic # Directory for dynamic config files
watch: true
# Log configuration
log:
level: INFO
accessLog: {}
- In the dynamic folder create a file named
tcp-routers.yml
tcp:
routers:
hl-traefik-rtr:
entryPoints:
- "websecure"
rule: "HostSNIRegexp(`hl.voorbeeld.nl`) || HostSNIRegexp(`{subdomain:[a-z0-9]+}.hl.voorbeeld.nl`)"
service: hl-traefik-svc
tls:
passthrough: true
test-traefik-rtr:
entryPoints:
- "websecure"
rule: "HostSNIRegexp(`test.voorbeeld.nl`) || HostSNIRegexp(`{subdomain:[a-z0-9]+}.test.voorbeeld.nl`)"
service: test-traefik-svc
tls:
passthrough: true
services:
hl-traefik-svc:
loadBalancer:
servers:
- address: "192.0.2.2:443"
test-traefik-svc:
loadBalancer:
servers:
- address: "192.0.2.5:443"
- Create a file named
acme.json
touch acme.json
- Change the permissions to 600
chmod 600
- Run the docker compose stack with
docker compose up -d
You are now done with the VPS side.
- Make a CT or VM on promxox.
- login with:
ssh user@192.0.2.5
- Install Docker
A.
apt install curl
dnf install curl
yum install curl
B.
curl -fsSL https://get.docker.com | sh
- Make a folder named
traefik - Create a file named docker-compose.yml and paste the following contents in the file.
version: '3.8'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard (optional, secure it in production)
volumes:
# Docker socket to discover containers
- /var/run/docker.sock:/var/run/docker.sock:ro
# Traefik configuration
- ./traefik.yml:/etc/traefik/traefik.yml:ro
# Dynamic configuration (optional)
- ./dynamic:/etc/traefik/dynamic:ro
# ACME certificates storage
- ./acme.json:/acme.json
# Access logs (optional)
- ./logs:/logs
environment:
# Cloudflare credentials - preferred method
- CF_DNS_API_TOKEN=apikey
# Alternative: API Key + Email (if you don't use tokens)
# - CF_API_EMAIL=${CF_API_EMAIL}
# - CF_API_KEY=${CF_API_KEY}
# Timezone
- TZ=UTC
networks:
- traefik-public
# Enable Traefik dashboard (optional - secure with basic auth)
labels:
- "traefik.enable=true"
# HTTP to HTTPS redirect
- "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-https"
- "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
- "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true"
# Dashboard router
- "traefik.http.routers.dashboard.rule=Host(`traefik.joudomein.nl`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=cloudflare"
- "traefik.http.routers.dashboard.service=api@internal"
## Basic auth middleware for dashboard (optional but recommended)
#- "traefik.http.routers.dashboard.middlewares=dashboard-auth"
#- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$05$$examplehash" # Generate with: htpasswd -nb admin yourpassword
networks:
traefik-public:
external: true
- Create a file named traefik.yml and paste the following contents.
# Global configuration
global:
checkNewVersion: false
sendAnonymousUsage: false
# Entry points
entryPoints:
web:
address: ":80"
# Automatic HTTP to HTTPS redirect
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
http:
tls:
certResolver: cloudflare # Default cert resolver
domains:
- main: "bbb.matinise.com" # Replace with your domain
sans:
- "*.bbb.matinise.com"
traefik:
address: ":8080"
# API and Dashboard
api:
dashboard: true
debug: false
# Logging
log:
level: INFO # Set to DEBUG for troubleshooting
filePath: "/logs/traefik.log"
format: json
# Access logs
accessLog:
filePath: "/logs/access.log"
bufferingSize: 100
filters:
statusCodes:
- "200-299"
- "300-399"
- "400-499"
- "500-599"
# Providers
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
watch: true
network: "traefik-public"
# File provider for dynamic configuration (optional)
file:
directory: "/etc/traefik/dynamic"
watch: true
# ACME Configuration
certificatesResolvers:
cloudflare:
acme:
email: "jij@voorbeeld.nl" # Replace with your email
storage: "acme.json"
# Use production server for real certificates
# caServer: "https://acme-v02.api.letsencrypt.org/directory"
# Use staging server for testing to avoid rate limits
# caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
# DNS Challenge configuration
dnsChallenge:
provider: "cloudflare"
# DNS resolvers for propagation checking
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
- "8.8.8.8:53"
- "8.8.4.4:53"
# Optional: Delay before checking propagation (in seconds)
delayBeforeCheck: 30
# Optional: Disable Traefik's DNS propagation check
# (Use if you have network issues, but be careful)
# disablePropagationCheck: true
# Servers transport configuration
serversTransport:
insecureSkipVerify: false
# TLS options
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY20_SHA256
curvePreferences:
- CurveP521
- CurveP384
- Change the examples to your own values.
- After you are done do
docker compose up -d
You are now done with the setup.