Set up Traefik 3.1 reverse proxy with Consul service discovery to automatically route traffic to services without manual configuration. Learn dynamic routing, SSL automation, health checks, and monitoring setup for production environments.
Prerequisites
- Root or sudo access
- Basic understanding of reverse proxies
- Domain name for SSL certificates
What this solves
Traefik with Consul service discovery automatically routes traffic to your services without manual configuration updates. When you deploy or scale services, Consul registers them and Traefik immediately starts load balancing traffic based on health checks and routing rules.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions.
sudo apt update && sudo apt upgrade -y
Install required packages
Install curl and unzip to download Consul and Traefik binaries.
sudo apt install -y curl unzip wget
Download and install Consul
Download the latest Consul binary and install it in the system PATH.
curl -fsSL https://releases.hashicorp.com/consul/1.17.0/consul_1.17.0_linux_amd64.zip -o consul.zip
unzip consul.zip
sudo mv consul /usr/local/bin/
sudo chmod +x /usr/local/bin/consul
consul --version
Create Consul user and directories
Create a dedicated user for Consul and set up the necessary directories with proper permissions.
sudo useradd --system --home /etc/consul.d --shell /bin/false consul
sudo mkdir -p /opt/consul /etc/consul.d
sudo chown -R consul:consul /opt/consul /etc/consul.d
sudo chmod 755 /opt/consul /etc/consul.d
Configure Consul server
Create the main Consul configuration file with clustering and service discovery settings.
{
"datacenter": "dc1",
"data_dir": "/opt/consul",
"log_level": "INFO",
"server": true,
"bootstrap_expect": 1,
"bind_addr": "0.0.0.0",
"client_addr": "0.0.0.0",
"retry_join": ["127.0.0.1"],
"ui_config": {
"enabled": true
},
"connect": {
"enabled": true
},
"ports": {
"grpc": 8502
},
"acl": {
"enabled": false,
"default_policy": "allow"
}
}
Create Consul systemd service
Set up Consul as a systemd service for automatic startup and management.
[Unit]
Description=Consul
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/etc/consul.d/consul.json
[Service]
Type=notify
User=consul
Group=consul
ExecStart=/usr/local/bin/consul agent -config-dir=/etc/consul.d/
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Start and enable Consul
Start Consul and configure it to start automatically on boot.
sudo systemctl daemon-reload
sudo systemctl enable --now consul
sudo systemctl status consul
Download and install Traefik
Download Traefik 3.1 binary and install it in the system PATH.
curl -fsSL https://github.com/traefik/traefik/releases/download/v3.1.0/traefik_v3.1.0_linux_amd64.tar.gz -o traefik.tar.gz
tar -xzf traefik.tar.gz
sudo mv traefik /usr/local/bin/
sudo chmod +x /usr/local/bin/traefik
traefik version
Create Traefik user and directories
Create a dedicated user for Traefik and set up configuration directories.
sudo useradd --system --home /var/lib/traefik --shell /bin/false traefik
sudo mkdir -p /etc/traefik /var/lib/traefik /var/log/traefik
sudo chown -R traefik:traefik /etc/traefik /var/lib/traefik /var/log/traefik
sudo chmod 755 /etc/traefik /var/lib/traefik
sudo chmod 750 /var/log/traefik
Configure Traefik with Consul integration
Create the main Traefik configuration file with Consul service discovery and Let's Encrypt SSL automation.
global:
checkNewVersion: false
sendAnonymousUsage: false
serversTransport:
insecureSkipVerify: true
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
consul:
endpoints:
- "127.0.0.1:8500"
watch: true
exposedByDefault: false
defaultRule: "Host({{ .Name }}.example.com)"
consulCatalog:
prefix: traefik
exposedByDefault: false
endpoints:
- "127.0.0.1:8500"
watch: true
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: "/var/lib/traefik/acme.json"
httpChallenge:
entryPoint: web
api:
dashboard: true
debug: true
log:
level: INFO
filePath: "/var/log/traefik/traefik.log"
accessLog:
filePath: "/var/log/traefik/access.log"
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
Set secure permissions for ACME storage
Create and secure the ACME certificate storage file with proper permissions.
sudo touch /var/lib/traefik/acme.json
sudo chown traefik:traefik /var/lib/traefik/acme.json
sudo chmod 600 /var/lib/traefik/acme.json
Create Traefik systemd service
Set up Traefik as a systemd service with proper security constraints.
[Unit]
Description=Traefik
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/traefik --configfile=/etc/traefik/traefik.yml
Restart=on-failure
RestartSec=5
User=traefik
Group=traefik
StandardOutput=journal
StandardError=journal
SyslogIdentifier=traefik
KillMode=mixed
KillSignal=SIGTERM
Security settings
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectHome=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/traefik /var/log/traefik
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
Configure firewall rules
Open the necessary ports for Traefik HTTP/HTTPS and Consul communication.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8500/tcp
sudo ufw allow 8300/tcp
sudo ufw reload
Start and enable Traefik
Start Traefik and configure it to start automatically on boot.
sudo systemctl daemon-reload
sudo systemctl enable --now traefik
sudo systemctl status traefik
Register a sample service in Consul
Create a sample web service registration to test the Traefik-Consul integration.
{
"ID": "web-app-1",
"Name": "web-app",
"Tags": [
"traefik.enable=true",
"traefik.http.routers.web-app.rule=Host(web-app.example.com)",
"traefik.http.routers.web-app.tls=true",
"traefik.http.routers.web-app.tls.certresolver=letsencrypt",
"traefik.http.services.web-app.loadbalancer.server.port=8080"
],
"Address": "127.0.0.1",
"Port": 8080,
"Check": {
"HTTP": "http://127.0.0.1:8080/health",
"Interval": "10s",
"Timeout": "5s"
}
}
Register the service with Consul
Use the Consul API to register the sample service for testing.
curl -X PUT -d @/tmp/sample-service.json http://localhost:8500/v1/agent/service/register
Configure Traefik dashboard access
Create a separate configuration file for secure dashboard access.
http:
routers:
dashboard:
rule: "Host(traefik.example.com)"
tls:
certResolver: letsencrypt
service: "api@internal"
middlewares:
- "dashboard-auth"
middlewares:
dashboard-auth:
basicAuth:
users:
- "admin:$2y$10$8K6zGz7gO.4xFz7L8O4YBOxP7SqEcNz2V8wA5c9vQ7XYz1b2c3d4e"
Configure health checks and monitoring
Create health check endpoint
Set up a simple health check service to demonstrate Consul health monitoring.
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
class HealthHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/health':
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
response = {'status': 'healthy', 'service': 'web-app'}
self.wfile.write(json.dumps(response).encode())
else:
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b'Sample Web Application
')
if __name__ == '__main__':
server = HTTPServer(('localhost', 8080), HealthHandler)
print('Starting health check server on port 8080')
server.serve_forever()
Run the sample service
Start the sample web service to test health checks and load balancing.
sudo chmod +x /tmp/health-server.py
python3 /tmp/health-server.py &
Configure log rotation
Set up log rotation for Traefik to prevent disk space issues.
/var/log/traefik/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 traefik traefik
postrotate
systemctl reload traefik
endscript
}
Configure SSL automation and security
Test SSL certificate generation
Verify that Let's Encrypt certificates are being generated automatically.
sudo journalctl -u traefik -f
Configure security headers middleware
Add security headers to all services through Traefik middleware.
http:
middlewares:
security-headers:
headers:
frameDeny: true
sslRedirect: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customRequestHeaders:
X-Forwarded-Proto: "https"
customResponseHeaders:
X-Robots-Tag: "noindex,nofollow,nosnippet,noarchive"
rate-limit:
rateLimit:
burst: 100
average: 50
Update Traefik configuration to include security
Modify the main Traefik configuration to load additional configuration files.
sudo sed -i '/providers:/a\ file:\n directory: /etc/traefik\n watch: true' /etc/traefik/traefik.yml
sudo systemctl restart traefik
Verify your setup
Check that all services are running and communicating properly.
# Check Consul status
consul members
curl -s http://localhost:8500/v1/status/leader
Check registered services
curl -s http://localhost:8500/v1/catalog/services | python3 -m json.tool
Check Traefik status
sudo systemctl status traefik
curl -s http://localhost:8080/api/rawdata | python3 -m json.tool
Test service discovery
curl -s http://localhost:8500/v1/health/service/web-app
Check health of sample service
curl -s http://localhost:8080/health
Access the Consul UI at http://your-server-ip:8500 and Traefik dashboard at http://your-server-ip:8080 to verify the setup.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Consul won't start | Port 8500 already in use | sudo ss -tulpn | grep :8500 to find conflicting process |
| Traefik can't connect to Consul | Consul not accessible | Check curl http://localhost:8500/v1/status/leader |
| SSL certificates not generating | Let's Encrypt rate limits or DNS issues | Check sudo journalctl -u traefik -f for ACME errors |
| Service not appearing in Traefik | Missing traefik.enable=true tag | Add traefik.enable=true to service tags in Consul |
| 502 Bad Gateway | Backend service not responding | Check service health in Consul UI and verify port configuration |
| Permission denied on ACME file | Incorrect file ownership | sudo chown traefik:traefik /var/lib/traefik/acme.json && sudo chmod 600 |
Next steps
- Monitor Consul with Prometheus and Grafana for service discovery observability
- Configure advanced Consul ACL policies for production security hardening
- Set up Traefik with multi-cluster service mesh for distributed applications
- Implement advanced Traefik middleware for rate limiting and circuit breakers
- Configure Traefik OAuth2 authentication with Keycloak integration
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Production Traefik + Consul Installation Script
# Supports Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS, RHEL, Fedora, Amazon Linux
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Default versions
CONSUL_VERSION="1.17.0"
TRAEFIK_VERSION="3.1.0"
DOMAIN="${1:-example.com}"
# Usage message
usage() {
echo "Usage: $0 [domain]"
echo "Example: $0 mydomain.com"
exit 1
}
# Print colored output
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Cleanup function for rollback
cleanup() {
log_error "Installation failed. Cleaning up..."
systemctl stop consul traefik 2>/dev/null || true
systemctl disable consul traefik 2>/dev/null || true
userdel consul traefik 2>/dev/null || true
rm -rf /opt/consul /etc/consul.d /etc/traefik /var/lib/traefik 2>/dev/null || true
rm -f /usr/local/bin/consul /usr/local/bin/traefik 2>/dev/null || true
rm -f /etc/systemd/system/consul.service /etc/systemd/system/traefik.service 2>/dev/null || true
exit 1
}
trap cleanup ERR
# Check if running as root or with sudo
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
# Detect distribution and set package manager
echo "[1/12] Detecting distribution..."
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
FIREWALL_CMD="ufw"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
FIREWALL_CMD="firewall-cmd"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
FIREWALL_CMD="firewall-cmd"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_info "Detected: $PRETTY_NAME"
else
log_error "Cannot detect distribution"
exit 1
fi
# Update system packages
echo "[2/12] Updating system packages..."
$PKG_UPDATE
# Install required packages
echo "[3/12] Installing required packages..."
$PKG_INSTALL curl unzip wget tar
# Download and install Consul
echo "[4/12] Downloading and installing Consul..."
cd /tmp
curl -fsSL "https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip" -o consul.zip
unzip consul.zip
mv consul /usr/local/bin/
chmod 755 /usr/local/bin/consul
rm consul.zip
log_info "Consul version: $(consul --version | head -n1)"
# Create Consul user and directories
echo "[5/12] Creating Consul user and directories..."
useradd --system --home /etc/consul.d --shell /bin/false consul 2>/dev/null || true
mkdir -p /opt/consul /etc/consul.d
chown -R consul:consul /opt/consul /etc/consul.d
chmod 755 /opt/consul /etc/consul.d
# Configure Consul server
echo "[6/12] Configuring Consul server..."
cat > /etc/consul.d/consul.json << 'EOF'
{
"datacenter": "dc1",
"data_dir": "/opt/consul",
"log_level": "INFO",
"server": true,
"bootstrap_expect": 1,
"bind_addr": "0.0.0.0",
"client_addr": "0.0.0.0",
"retry_join": ["127.0.0.1"],
"ui_config": {
"enabled": true
},
"connect": {
"enabled": true
},
"ports": {
"grpc": 8502
},
"acl": {
"enabled": false,
"default_policy": "allow"
}
}
EOF
chown consul:consul /etc/consul.d/consul.json
chmod 644 /etc/consul.d/consul.json
# Create Consul systemd service
echo "[7/12] Creating Consul systemd service..."
cat > /etc/systemd/system/consul.service << 'EOF'
[Unit]
Description=Consul
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/etc/consul.d/consul.json
[Service]
Type=notify
User=consul
Group=consul
ExecStart=/usr/local/bin/consul agent -config-dir=/etc/consul.d/
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
# Start and enable Consul
echo "[8/12] Starting and enabling Consul..."
systemctl daemon-reload
systemctl enable consul
systemctl start consul
sleep 5
systemctl status consul --no-pager -l
# Download and install Traefik
echo "[9/12] Downloading and installing Traefik..."
cd /tmp
curl -fsSL "https://github.com/traefik/traefik/releases/download/v${TRAEFIK_VERSION}/traefik_v${TRAEFIK_VERSION}_linux_amd64.tar.gz" -o traefik.tar.gz
tar -xzf traefik.tar.gz
mv traefik /usr/local/bin/
chmod 755 /usr/local/bin/traefik
rm traefik.tar.gz
log_info "Traefik version: $(traefik version | head -n1)"
# Create Traefik user and directories
echo "[10/12] Creating Traefik user and directories..."
useradd --system --home /var/lib/traefik --shell /bin/false traefik 2>/dev/null || true
mkdir -p /etc/traefik /var/lib/traefik /var/log/traefik
chown -R traefik:traefik /etc/traefik /var/lib/traefik /var/log/traefik
chmod 755 /etc/traefik /var/lib/traefik
chmod 755 /var/log/traefik
# Configure Traefik with Consul integration
echo "[11/12] Configuring Traefik with Consul integration..."
cat > /etc/traefik/traefik.yml << EOF
global:
checkNewVersion: false
sendAnonymousUsage: false
serversTransport:
insecureSkipVerify: true
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
consulCatalog:
prefix: traefik
exposedByDefault: false
endpoints:
- "127.0.0.1:8500"
watch: true
defaultRule: "Host(\`{{ .Name }}.${DOMAIN}\`)"
certificatesResolvers:
letsencrypt:
acme:
email: admin@${DOMAIN}
storage: /var/lib/traefik/acme.json
httpChallenge:
entryPoint: web
api:
dashboard: true
insecure: false
log:
level: INFO
filePath: "/var/log/traefik/traefik.log"
accessLog:
filePath: "/var/log/traefik/access.log"
EOF
# Create Traefik systemd service
cat > /etc/systemd/system/traefik.service << 'EOF'
[Unit]
Description=Traefik
Documentation=https://doc.traefik.io/traefik/
After=network-online.target consul.service
Wants=network-online.target
Requires=consul.service
[Service]
Type=simple
User=traefik
Group=traefik
ExecStart=/usr/local/bin/traefik --configfile=/etc/traefik/traefik.yml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=traefik
KillMode=mixed
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.target
EOF
chown -R traefik:traefik /etc/traefik
chmod 644 /etc/traefik/traefik.yml
# Configure firewall
if command -v ufw >/dev/null 2>&1; then
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8080/tcp
ufw allow 8500/tcp
elif command -v firewall-cmd >/dev/null 2>&1; then
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --add-port=8500/tcp
firewall-cmd --reload
fi
# Start and enable Traefik
echo "[12/12] Starting and enabling Traefik..."
systemctl daemon-reload
systemctl enable traefik
systemctl start traefik
sleep 3
# Verification checks
log_info "Performing verification checks..."
if systemctl is-active --quiet consul; then
log_info "✓ Consul is running"
else
log_error "✗ Consul is not running"
exit 1
fi
if systemctl is-active --quiet traefik; then
log_info "✓ Traefik is running"
else
log_error "✗ Traefik is not running"
exit 1
fi
if curl -s http://localhost:8500/v1/status/leader | grep -q "127.0.0.1"; then
log_info "✓ Consul API is responding"
else
log_error "✗ Consul API is not responding"
exit 1
fi
log_info "Installation completed successfully!"
echo
echo "Access points:"
echo "- Consul UI: http://$(hostname -I | awk '{print $1}'):8500"
echo "- Traefik Dashboard: http://$(hostname -I | awk '{print $1}'):8080"
echo
echo "Next steps:"
echo "1. Register services with Consul"
echo "2. Configure DNS to point *.${DOMAIN} to this server"
echo "3. Services will be automatically available at servicename.${DOMAIN}"
Review the script before running. Execute with: bash install.sh