Set up a production-grade security stack using Traefik v3 reverse proxy with SSL automation and Authelia for multi-factor authentication. This tutorial covers Docker hardening, LDAP integration, and container security monitoring.
Prerequisites
- Root access to server
- Domain name with DNS control
- Basic Docker knowledge
- Email account for SSL certificates
What this solves
This tutorial creates a secure container environment where Traefik handles SSL termination and routing while Authelia provides authentication with support for LDAP and OIDC providers. You get automatic SSL certificates, multi-factor authentication, and hardened Docker containers suitable for production workloads.
Step-by-step installation
Update system and install Docker with security hardening
Start by updating your system and installing Docker with security-focused configuration.
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo dnf update -y
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Configure Docker daemon with security hardening
Create a secure Docker daemon configuration that enables user namespaces, restricts capabilities, and sets security options.
{
"userns-remap": "default",
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"seccomp-profile": "/etc/docker/seccomp.json",
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
},
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker $USER
newgrp docker
Create project directory structure
Set up the directory structure for your secure container stack with proper permissions.
mkdir -p ~/secure-stack/{traefik,authelia,config,data,logs}
cd ~/secure-stack
chmod 755 ~/secure-stack
chmod 750 ~/secure-stack/{config,data,logs}
Create Docker network for secure communication
Create a custom Docker network that isolates your secure services and enables encrypted communication.
docker network create --driver bridge \
--subnet=172.20.0.0/16 \
--opt encrypted=true \
--opt com.docker.network.bridge.name=secure-br0 \
secure-network
Configure Traefik v3 with SSL automation
Set up Traefik as a reverse proxy with automatic SSL certificate generation and security headers.
global:
checkNewVersion: false
sendAnonymousUsage: false
api:
dashboard: true
debug: false
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
middlewares:
- security-headers@file
tls:
certResolver: letsencrypt
serversTransport:
insecureSkipVerify: false
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /certificates/acme.json
httpChallenge:
entryPoint: web
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: secure-network
file:
filename: /config/middlewares.yml
watch: true
log:
level: INFO
filePath: "/logs/traefik.log"
format: json
accessLog:
filePath: "/logs/access.log"
format: json
Create Traefik security middlewares
Define security middlewares for headers, rate limiting, and authentication integration.
http:
middlewares:
security-headers:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
- POST
- DELETE
accessControlMaxAge: 100
hostsProxyHeaders:
- "X-Forwarded-Host"
referrerPolicy: "same-origin"
customRequestHeaders:
X-Forwarded-Proto: "https"
customResponseHeaders:
X-Robots-Tag: "noindex,nofollow,nosnippet,noarchive"
sslRedirect: true
sslTemporaryRedirect: true
sslHost: "example.com"
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
forceSTSHeader: true
frameDeny: true
contentTypeNosniff: true
browserXssFilter: true
permissionsPolicy: "camera=(), microphone=(), geolocation=()"
rate-limit:
rateLimit:
average: 100
period: 1m
burst: 50
authelia:
forwardAuth:
address: "http://authelia:9091/api/verify?rd=https://auth.example.com"
trustForwardHeader: true
authResponseHeaders:
- "Remote-User"
- "Remote-Groups"
- "Remote-Name"
- "Remote-Email"
Generate Authelia configuration
Create Authelia configuration with LDAP support, session security, and multi-factor authentication.
openssl rand -base64 32 > config/session_secret
openssl rand -base64 32 > config/storage_secret
openssl rand -base64 32 > config/jwt_secret
theme: auto
default_redirection_url: https://example.com
server:
host: 0.0.0.0
port: 9091
asset_path: /config/assets/
headers:
csp_template: ""
buffers:
read: 4096
write: 4096
timeouts:
read: 6s
write: 6s
idle: 30s
log:
level: info
format: text
file_path: /logs/authelia.log
keep_stdout: true
telemetry:
metrics:
enabled: true
address: tcp://0.0.0.0:9959
totp:
disable: false
issuer: authelia.com
algorithm: sha1
digits: 6
period: 30
skew: 1
secret_size: 32
webauthn:
disable: false
display_name: Authelia
attestation_conveyance_preference: indirect
user_verification: preferred
timeout: 60s
ntp:
address: "time.cloudflare.com:123"
version: 3
max_desync: 3s
disable_startup_check: false
disable_failure: false
authentication_backend:
password_reset:
disable: false
refresh_interval: 5m
ldap:
implementation: custom
url: ldap://openldap:389
timeout: 5s
start_tls: false
tls:
skip_verify: false
minimum_version: TLS1.2
base_dn: dc=example,dc=com
username_attribute: uid
additional_users_dn: ou=users
users_filter: (&({username_attribute}={input})(objectClass=person))
additional_groups_dn: ou=groups
groups_filter: (&(member={dn})(objectClass=groupOfNames))
group_name_attribute: cn
mail_attribute: mail
display_name_attribute: displayName
user: cn=admin,dc=example,dc=com
password: changeme123
session:
name: authelia_session
domain: example.com
same_site: lax
secret: file:///config/session_secret
expiration: 1h
inactivity: 5m
remember_me_duration: 1M
redis:
host: redis
port: 6379
password: ""
database_index: 0
maximum_active_connections: 8
minimum_idle_connections: 0
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
storage:
encryption_key: file:///config/storage_secret
local:
path: /data/db.sqlite3
notifier:
disable_startup_check: false
smtp:
host: smtp.gmail.com
port: 587
timeout: 5s
username: admin@example.com
password: changeme123
sender: admin@example.com
identifier: localhost
subject: "[Authelia] {title}"
startup_check_address: admin@example.com
disable_require_tls: false
disable_html_emails: false
tls:
skip_verify: false
minimum_version: TLS1.2
identity_providers:
oidc:
hmac_secret: file:///config/jwt_secret
issuer_private_key: |
-----BEGIN RSA PRIVATE KEY-----
# Generate with: openssl genrsa -out private.pem 4096
-----END RSA PRIVATE KEY-----
access_token_lifespan: 1h
authorize_code_lifespan: 1m
id_token_lifespan: 1h
refresh_token_lifespan: 90m
enable_client_debug_messages: false
clients:
- id: example-app
description: Example Application
secret: $pbkdf2-sha512$310000$example-hash
public: false
authorization_policy: two_factor
redirect_uris:
- https://app.example.com/oauth/callback
scopes:
- openid
- profile
- email
- groups
response_types:
- code
grant_types:
- authorization_code
response_modes:
- form_post
- query
- fragment
access_control:
default_policy: deny
networks:
- name: internal
networks:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
rules:
- domain: auth.example.com
policy: bypass
- domain: traefik.example.com
policy: two_factor
- domain: "*.example.com"
policy: two_factor
Create Redis configuration for session storage
Configure Redis with security settings for storing Authelia sessions.
bind 127.0.0.1
port 6379
protected-mode yes
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
maxmemory 256mb
maxmemory-policy allkeys-lru
Create Docker Compose configuration
Define the complete secure stack with proper networking, volumes, and security constraints.
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- secure-network
ports:
- "80:80"
- "443:443"
environment:
- TRAEFIK_LOG_LEVEL=INFO
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/traefik.yml:/traefik.yml:ro
- ./traefik/middlewares.yml:/config/middlewares.yml:ro
- ./data/certificates:/certificates
- ./logs:/logs
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.traefik.middlewares=authelia@file"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
authelia:
image: authelia/authelia:latest
container_name: authelia
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- secure-network
expose:
- 9091
environment:
- TZ=UTC
volumes:
- /etc/localtime:/etc/localtime:ro
- ./authelia/configuration.yml:/config/configuration.yml:ro
- ./config:/config:ro
- ./data/authelia:/data
- ./logs:/logs
labels:
- "traefik.enable=true"
- "traefik.http.routers.authelia.entrypoints=websecure"
- "traefik.http.routers.authelia.rule=Host(`auth.example.com`)"
- "traefik.http.routers.authelia.tls=true"
- "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
- "traefik.http.routers.authelia.service=authelia"
- "traefik.http.services.authelia.loadbalancer.server.port=9091"
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
depends_on:
- redis
redis:
image: redis:7-alpine
container_name: redis
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- secure-network
expose:
- 6379
volumes:
- /etc/localtime:/etc/localtime:ro
- ./config/redis.conf:/usr/local/etc/redis/redis.conf:ro
- ./data/redis:/data
command: redis-server /usr/local/etc/redis/redis.conf
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
- DAC_OVERRIDE
example-app:
image: nginx:alpine
container_name: example-app
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- secure-network
expose:
- 80
volumes:
- /etc/localtime:/etc/localtime:ro
- ./data/www:/usr/share/nginx/html:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.example-app.entrypoints=websecure"
- "traefik.http.routers.example-app.rule=Host(`app.example.com`)"
- "traefik.http.routers.example-app.middlewares=authelia@file"
- "traefik.http.routers.example-app.tls=true"
- "traefik.http.routers.example-app.tls.certresolver=letsencrypt"
read_only: true
tmpfs:
- /var/cache/nginx
- /var/run
- /tmp
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- SETGID
- SETUID
- NET_BIND_SERVICE
networks:
secure-network:
external: true
volumes:
certificates:
authelia-data:
redis-data:
Set proper file permissions and ownership
Configure secure file permissions for certificates and configuration files.
sudo chown -R $(id -u):$(id -g) ~/secure-stack
chmod 600 ~/secure-stack/config/*_secret
chmod 644 ~/secure-stack/traefik/traefik.yml
chmod 644 ~/secure-stack/authelia/configuration.yml
touch ~/secure-stack/data/certificates/acme.json
chmod 600 ~/secure-stack/data/certificates/acme.json
Create sample application content
Add a simple test page to verify the authentication flow works correctly.
mkdir -p data/www
<div class="container">
<h1>🔒 Secure Application</h1>
<div class="status">
✅ Authentication successful - You are accessing a protected resource
</div>
<p>This page is protected by Authelia authentication and served through Traefik reverse proxy with SSL.</p>
<h3>Security Features Active:</h3>
<ul>
<li>SSL/TLS encryption via Let's Encrypt</li>
<li>Multi-factor authentication</li>
<li>Security headers protection</li>
<li>Rate limiting</li>
<li>Container security hardening</li>
</ul>
<p><strong>Timestamp:</strong> <span></span></p>
</div>
Start the secure container stack
Launch all services and verify they start correctly with proper networking.
docker compose up -d
docker compose logs -f --tail=20
Configure DNS and SSL certificates
Set up DNS records and verify SSL certificate generation for your domains.
# Check certificate generation
docker compose logs traefik | grep -i certificate
# Verify ACME challenge
curl -I http://auth.example.com/.well-known/acme-challenge/test
# Test SSL endpoint
curl -I https://auth.example.com
Set up container security monitoring
Configure monitoring for container security events and performance metrics.
#!/bin/bash
# Container security monitoring script
LOG_FILE="/var/log/container-security.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
# Check for privileged containers
echo "[$DATE] Checking for privileged containers..." >> $LOG_FILE
docker ps --filter "label=privileged=true" --format "table {{.Names}}\t{{.Status}}" >> $LOG_FILE
# Monitor container resource usage
echo "[$DATE] Container resource usage:" >> $LOG_FILE
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}" >> $LOG_FILE
# Check for containers running as root
echo "[$DATE] Checking containers running as root:" >> $LOG_FILE
for container in $(docker ps -q); do
user=$(docker exec $container whoami 2>/dev/null || echo "unknown")
name=$(docker inspect --format '{{.Name}}' $container)
if [ "$user" = "root" ]; then
echo "WARNING: Container $name running as root user" >> $LOG_FILE
fi
done
# Verify security options
echo "[$DATE] Security options check:" >> $LOG_FILE
docker ps --format "table {{.Names}}" | tail -n +2 | while read container; do
security_opts=$(docker inspect --format '{{.HostConfig.SecurityOpt}}' $container)
echo "$container: $security_opts" >> $LOG_FILE
done
chmod +x config/docker-security.sh
sudo mkdir -p /var/log
sudo touch /var/log/container-security.log
sudo chmod 640 /var/log/container-security.log
Configure automated security monitoring
Set up a systemd timer to run security monitoring checks every hour.
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Usage function
usage() {
echo "Usage: $0 <domain> <email>"
echo "Example: $0 example.com admin@example.com"
exit 1
}
# Cleanup function for rollback
cleanup() {
echo -e "${RED}[ERROR] Installation failed. Cleaning up...${NC}"
cd /
rm -rf ~/secure-stack 2>/dev/null || true
docker network rm secure-network 2>/dev/null || true
exit 1
}
# Set trap for cleanup on error
trap cleanup ERR
# Check arguments
if [ $# -ne 2 ]; then
usage
fi
DOMAIN="$1"
EMAIL="$2"
# Validate email format
if ! echo "$EMAIL" | grep -qE "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"; then
echo -e "${RED}Invalid email format${NC}"
exit 1
fi
# Check if running as root or with sudo
if [ $EUID -eq 0 ]; then
SUDO=""
else
SUDO="sudo"
if ! command -v sudo >/dev/null 2>&1; then
echo -e "${RED}This script requires sudo privileges${NC}"
exit 1
fi
fi
echo -e "${GREEN}Installing Secure Docker Stack with Traefik and Authelia${NC}"
# Detect 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"
DOCKER_REPO="https://download.docker.com/linux/$ID"
GPG_KEY_CMD="curl -fsSL https://download.docker.com/linux/$ID/gpg | $SUDO gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg"
REPO_CMD="echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] $DOCKER_REPO \$(lsb_release -cs) stable\" | $SUDO tee /etc/apt/sources.list.d/docker.list > /dev/null"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
DOCKER_REPO="https://download.docker.com/linux/centos/docker-ce.repo"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
DOCKER_REPO="https://download.docker.com/linux/centos/docker-ce.repo"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}Cannot detect distribution${NC}"
exit 1
fi
echo -e "${YELLOW}[1/8] Updating system and installing prerequisites${NC}"
$SUDO $PKG_UPDATE
case "$PKG_MGR" in
apt)
$SUDO $PKG_INSTALL ca-certificates curl gnupg lsb-release
;;
*)
$SUDO $PKG_INSTALL ca-certificates curl gnupg2
;;
esac
echo -e "${YELLOW}[2/8] Installing Docker${NC}"
case "$PKG_MGR" in
apt)
eval "$GPG_KEY_CMD"
eval "$REPO_CMD"
$SUDO apt update
;;
*)
$SUDO dnf config-manager --add-repo $DOCKER_REPO || $SUDO yum-config-manager --add-repo $DOCKER_REPO
;;
esac
$SUDO $PKG_INSTALL docker-ce docker-ce-cli containerd.io docker-compose-plugin
echo -e "${YELLOW}[3/8] Configuring Docker daemon with security hardening${NC}"
$SUDO mkdir -p /etc/docker
$SUDO tee /etc/docker/daemon.json > /dev/null <<EOF
{
"userns-remap": "default",
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
},
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
EOF
$SUDO systemctl enable docker
$SUDO systemctl start docker
$SUDO usermod -aG docker $USER
echo -e "${YELLOW}[4/8] Creating project directory structure${NC}"
mkdir -p ~/secure-stack/{traefik,authelia,config,data,logs,certificates}
cd ~/secure-stack
chmod 755 ~/secure-stack
chmod 750 ~/secure-stack/{config,data,logs,certificates}
echo -e "${YELLOW}[5/8] Creating Docker network${NC}"
docker network create --driver bridge \
--subnet=172.20.0.0/16 \
--opt com.docker.network.bridge.name=secure-br0 \
secure-network
echo -e "${YELLOW}[6/8] Configuring Traefik${NC}"
tee ~/secure-stack/traefik/traefik.yml > /dev/null <<EOF
global:
checkNewVersion: false
sendAnonymousUsage: false
api:
dashboard: true
debug: false
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
middlewares:
- security-headers@file
tls:
certResolver: letsencrypt
certificatesResolvers:
letsencrypt:
acme:
email: $EMAIL
storage: /certificates/acme.json
httpChallenge:
entryPoint: web
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: secure-network
file:
filename: /config/middlewares.yml
watch: true
log:
level: INFO
filePath: "/logs/traefik.log"
format: json
accessLog:
filePath: "/logs/access.log"
format: json
EOF
tee ~/secure-stack/config/middlewares.yml > /dev/null <<EOF
http:
middlewares:
security-headers:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
- POST
- DELETE
accessControlMaxAge: 100
hostsProxyHeaders:
- "X-Forwarded-Host"
referrerPolicy: "same-origin"
customRequestHeaders:
X-Forwarded-Proto: "https"
customResponseHeaders:
X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"
X-Forwarded-Proto: "https"
sslProxyHeaders:
X-Forwarded-Proto: "https"
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
frameDeny: true
contentTypeNosniff: true
browserXssFilter: true
authelia:
forwardAuth:
address: "http://authelia:9091/api/verify?rd=https://auth.$DOMAIN/"
trustForwardHeader: true
authResponseHeaders:
- "Remote-User"
- "Remote-Groups"
- "Remote-Name"
- "Remote-Email"
EOF
echo -e "${YELLOW}[7/8] Configuring Authelia${NC}"
mkdir -p ~/secure-stack/authelia
tee ~/secure-stack/authelia/configuration.yml > /dev/null <<EOF
server:
host: 0.0.0.0
port: 9091
log:
level: info
format: json
default_redirection_url: https://auth.$DOMAIN
totp:
issuer: $DOMAIN
authentication_backend:
file:
path: /config/users.yml
access_control:
default_policy: deny
rules:
- domain: "auth.$DOMAIN"
policy: bypass
- domain: "*.$DOMAIN"
policy: two_factor
session:
name: authelia_session
domain: $DOMAIN
expiration: 1h
inactivity: 5m
regulation:
max_retries: 3
find_time: 120
ban_time: 300
storage:
local:
path: /config/db.sqlite3
notifier:
filesystem:
filename: /config/notification.txt
EOF
# Create a default user (admin/admin - should be changed in production)
HASHED_PASSWORD='$6$rounds=50000$BpLnfgDsc2WD8F2q$Zis.ixdg9s/UOJYrs56b5QEZFiZECu0qZVNsIYxBaNJ7ucIL.nlxVCT5tqh8KHG8X4tlwCFm5r6NZYK.Y.5yaE.'
tee ~/secure-stack/authelia/users.yml > /dev/null <<EOF
users:
admin:
displayname: "Admin User"
password: "$HASHED_PASSWORD"
email: $EMAIL
groups:
- admins
- dev
EOF
echo -e "${YELLOW}[8/8] Creating Docker Compose configuration${NC}"
tee ~/secure-stack/docker-compose.yml > /dev/null <<EOF
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- secure-network
ports:
- "80:80"
- "443:443"
volumes:
- ./traefik/traefik.yml:/traefik.yml:ro
- ./config:/config:ro
- ./logs:/logs
- ./certificates:/certificates
- /var/run/docker.sock:/var/run/docker.sock:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(\`traefik.$DOMAIN\`)"
- "traefik.http.routers.api.tls=true"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=authelia@file"
authelia:
image: authelia/authelia:latest
container_name: authelia
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- secure-network
volumes:
- ./authelia:/config
labels:
- "traefik.enable=true"
- "traefik.http.routers.authelia.rule=Host(\`auth.$DOMAIN\`)"
- "traefik.http.routers.authelia.tls=true"
- "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
networks:
secure-network:
external: true
EOF
# Set proper permissions
chmod 644 ~/secure-stack/traefik/traefik.yml
chmod 644 ~/secure-stack/config/middlewares.yml
chmod 644 ~/secure-stack/authelia/configuration.yml
chmod 600 ~/secure-stack/authelia/users.yml
chmod 644 ~/secure-stack/docker-compose.yml
echo -e "${GREEN}Installation completed successfully!${NC}"
echo -e "${YELLOW}Next steps:${NC}"
echo "1. Configure your DNS to point auth.$DOMAIN and traefik.$DOMAIN to this server"
echo "2. Start the stack: cd ~/secure-stack && docker compose up -d"
echo "3. Access Authelia at https://auth.$DOMAIN (admin/admin - change password!)"
echo "4. Access Traefik dashboard at https://traefik.$DOMAIN"
echo -e "${YELLOW}Note: Default login is admin/admin. Please change this immediately!${NC}"
Review the script before running. Execute with: bash install.sh