- A Linux server (Ubuntu 22.04 LTS recommended)
- Domain names pointing to your server
- Root or sudo access
- Docker and Docker Compose installed
- At least 2GB RAM, 2 CPU cores
- 20GB storage minimum
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git ufwsudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enablecurl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
sudo systemctl enable --now dockersudo apt install -y docker-composeCreate the following A records in your DNS management system:
authentik.example.com → YOUR_SERVER_IP
outpost.example.com → YOUR_SERVER_IP
# Install dig if not present
sudo apt install -y dnsutils
# Verify DNS records
dig authentik.example.com +short
dig outpost.example.com +short
# Wait for DNS propagation (can take up to 24 hours)mkdir -p ~/authentik/certs
cd ~/authentik/certsopenssl req -x509 \
-newkey rsa:4096 \
-keyout rootCA.key \
-out rootCA.crt \
-days 3650 \
-nodes \
-sha512 \
-subj "/C=US/ST=State/L=City/O=YourOrg/OU=IT/CN=YourOrg Root CA" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,digitalSignature,keyCertSign,cRLSign"# Generate private key
openssl genrsa -out authentik.key 4096
# Generate CSR
openssl req -new \
-key authentik.key \
-out authentik.csr \
-sha512 \
-subj "/C=US/ST=State/L=City/O=YourOrg/OU=IT/CN=authentik.example.com"
# Generate certificate
openssl x509 -req \
-in authentik.csr \
-CA rootCA.crt \
-CAkey rootCA.key \
-CAcreateserial \
-out authentik.crt \
-days 365 \
-sha512 \
-extfile <(printf "subjectAltName=DNS:authentik.example.com\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth")# Generate private key
openssl genrsa -out outpost.key 4096
# Generate CSR
openssl req -new \
-key outpost.key \
-out outpost.csr \
-sha512 \
-subj "/C=US/ST=State/L=City/O=YourOrg/OU=IT/CN=outpost.example.com"
# Generate certificate
openssl x509 -req \
-in outpost.csr \
-CA rootCA.crt \
-CAkey rootCA.key \
-CAcreateserial \
-out outpost.crt \
-days 365 \
-sha512 \
-extfile <(printf "subjectAltName=DNS:outpost.example.com\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth")chmod 600 *.key
chmod 644 *.crtsudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddyCreate /etc/caddy/Caddyfile:
{
# Global options
admin off # Disable admin API for security
auto_https off # We're managing our own certificates
local_certs # Use local certificates instead of Let's Encrypt
}
authentik.example.com {
encode gzip
# TLS configuration
tls /etc/caddy/certs/authentik.crt /etc/caddy/certs/authentik.key {
protocols tls1.3
ciphers TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256
}
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
X-XSS-Protection "1; mode=block"
}
# Reverse proxy configuration
reverse_proxy localhost:9000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
health_check /healthz
}
# Logging
log {
output file /var/log/caddy/authentik.access.log {
roll_size 10MB
roll_keep 10
}
format json
}
}
outpost.example.com {
encode gzip
# TLS configuration
tls /etc/caddy/certs/outpost.crt /etc/caddy/certs/outpost.key {
protocols tls1.3
ciphers TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256
}
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
X-XSS-Protection "1; mode=block"
}
# Reverse proxy configuration
reverse_proxy localhost:8000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
health_check /healthz
}
# Logging
log {
output file /var/log/caddy/outpost.access.log {
roll_size 10MB
roll_keep 10
}
format json
}
}sudo mkdir -p /etc/caddy/certs
sudo cp ~/authentik/certs/{authentik,outpost}.{crt,key} /etc/caddy/certs/
sudo chown -R caddy:caddy /etc/caddy/certs
sudo chmod 600 /etc/caddy/certs/*.keysudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddysudo systemctl enable caddy
sudo systemctl restart caddymkdir -p ~/authentik/{postgres,redis}
cd ~/authentikCreate .env:
# PostgreSQL
POSTGRES_USER=authentik
POSTGRES_PASSWORD=$(openssl rand -base64 32)
POSTGRES_DB=authentik
# Redis
REDIS_PASSWORD=$(openssl rand -base64 32)
# Authentik
AUTHENTIK_SECRET_KEY=$(openssl rand -base64 48)
AUTHENTIK_ERROR_REPORTING__ENABLED=false
AUTHENTIK_DISABLE_STARTUP_ANALYTICS=true
AUTHENTIK_LOG_LEVEL=info
# Email (replace with your settings)
AUTHENTIK_EMAIL__HOST=smtp.example.com
AUTHENTIK_EMAIL__PORT=587
AUTHENTIK_EMAIL__USERNAME=noreply@example.com
AUTHENTIK_EMAIL__PASSWORD=your-smtp-password
AUTHENTIK_EMAIL__USE_TLS=true
AUTHENTIK_EMAIL__FROM=noreply@example.comCreate docker-compose.yml:
version: '3.8'
services:
postgresql:
image: postgres:15-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- authentik
redis:
image: redis:alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- ./redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- authentik
authentik:
image: ghcr.io/goauthentik/server:2024.2.1
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_REDIS__PASSWORD: ${REDIS_PASSWORD}
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${POSTGRES_USER}
AUTHENTIK_POSTGRESQL__PASSWORD: ${POSTGRES_PASSWORD}
AUTHENTIK_POSTGRESQL__DATABASE: ${POSTGRES_DB}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING__ENABLED}
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: ${AUTHENTIK_DISABLE_STARTUP_ANALYTICS}
AUTHENTIK_LOG_LEVEL: ${AUTHENTIK_LOG_LEVEL}
AUTHENTIK_EMAIL__HOST: ${AUTHENTIK_EMAIL__HOST}
AUTHENTIK_EMAIL__PORT: ${AUTHENTIK_EMAIL__PORT}
AUTHENTIK_EMAIL__USERNAME: ${AUTHENTIK_EMAIL__USERNAME}
AUTHENTIK_EMAIL__PASSWORD: ${AUTHENTIK_EMAIL__PASSWORD}
AUTHENTIK_EMAIL__USE_TLS: ${AUTHENTIK_EMAIL__USE_TLS}
AUTHENTIK_EMAIL__FROM: ${AUTHENTIK_EMAIL__FROM}
volumes:
- ./media:/media
- ./certs:/certs
- ./custom-templates:/templates
ports:
- "127.0.0.1:9000:9000"
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/healthz/"]
interval: 30s
timeout: 10s
retries: 5
networks:
- authentik
authentik-worker:
image: ghcr.io/goauthentik/server:2024.2.1
restart: unless-stopped
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_REDIS__PASSWORD: ${REDIS_PASSWORD}
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${POSTGRES_USER}
AUTHENTIK_POSTGRESQL__PASSWORD: ${POSTGRES_PASSWORD}
AUTHENTIK_POSTGRESQL__DATABASE: ${POSTGRES_DB}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING__ENABLED}
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: ${AUTHENTIK_DISABLE_STARTUP_ANALYTICS}
AUTHENTIK_LOG_LEVEL: ${AUTHENTIK_LOG_LEVEL}
AUTHENTIK_EMAIL__HOST: ${AUTHENTIK_EMAIL__HOST}
AUTHENTIK_EMAIL__PORT: ${AUTHENTIK_EMAIL__PORT}
AUTHENTIK_EMAIL__USERNAME: ${AUTHENTIK_EMAIL__USERNAME}
AUTHENTIK_EMAIL__PASSWORD: ${AUTHENTIK_EMAIL__PASSWORD}
AUTHENTIK_EMAIL__USE_TLS: ${AUTHENTIK_EMAIL__USE_TLS}
AUTHENTIK_EMAIL__FROM: ${AUTHENTIK_EMAIL__FROM}
volumes:
- ./media:/media
- ./certs:/certs
- ./custom-templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/healthz/"]
interval: 30s
timeout: 10s
retries: 5
networks:
- authentik
outpost:
image: ghcr.io/goauthentik/outpost:2024.2.1
restart: unless-stopped
pid: host
environment:
AUTHENTIK_HOST: https://authentik.example.com
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN} # Will be configured later
AUTHENTIK_INSECURE: "false"
volumes:
- ./certs:/certs:ro
ports:
- "127.0.0.1:8000:8000"
depends_on:
- authentik
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/healthz/"]
interval: 30s
timeout: 10s
retries: 5
networks:
- authentik
networks:
authentik:
driver: bridge
volumes:
media:
custom-templates:
## 6. Initial Deployment and Configuration
### Start the Stack
```bash
# Create required directories with proper permissions
mkdir -p media custom-templates
chmod 755 media custom-templates
# Start the services
docker-compose up -d# Watch the logs
docker-compose logs -f --tail=100
# Check service status
docker-compose ps- Wait a few minutes for all services to start and initialize
- Navigate to https://authentik.example.com
- Follow the setup wizard to create the admin account
- Configure initial settings:
- Set up email configuration
- Configure password policies
- Set up MFA preferences
-
In the Authentik admin interface:
- Go to System → Outposts
- Create a new Proxy Outpost
- Copy the generated token
-
Add the token to your .env file:
echo "AUTHENTIK_OUTPOST_TOKEN=your-token-here" >> .env- Restart the outpost:
docker-compose restart outpostCreate backup.sh:
#!/bin/bash
BACKUP_DIR="/path/to/backup/directory"
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p "$BACKUP_DIR/$DATE"
# Stop services
docker-compose down
# Backup PostgreSQL
docker-compose run --rm postgresql pg_dump \
-U "$POSTGRES_USER" \
-d "$POSTGRES_DB" \
> "$BACKUP_DIR/$DATE/authentik_db.sql"
# Backup files
tar -czf "$BACKUP_DIR/$DATE/media.tar.gz" ./media
tar -czf "$BACKUP_DIR/$DATE/custom-templates.tar.gz" ./custom-templates
tar -czf "$BACKUP_DIR/$DATE/certs.tar.gz" ./certs
# Backup environment file
cp .env "$BACKUP_DIR/$DATE/"
# Start services
docker-compose up -d
# Cleanup old backups (keep last 7 days)
find "$BACKUP_DIR" -type d -mtime +7 -exec rm -rf {} +chmod +x backup.sh
sudo cp backup.sh /etc/cron.daily/authentik-backup# Stop services
docker-compose down
# Restore PostgreSQL
docker-compose run --rm postgresql psql \
-U "$POSTGRES_USER" \
-d "$POSTGRES_DB" \
< backup/authentik_db.sql
# Restore files
tar -xzf backup/media.tar.gz
tar -xzf backup/custom-templates.tar.gz
tar -xzf backup/certs.tar.gz
# Restore environment file
cp backup/.env .
# Start services
docker-compose up -dAdd to docker-compose.yml:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus:/etc/prometheus
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
ports:
- "127.0.0.1:9090:9090"
networks:
- authentik
grafana:
image: grafana/grafana:latest
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
ports:
- "127.0.0.1:3000:3000"
networks:
- authentik
volumes:
prometheus_data:
grafana_data:Create logrotate configuration:
sudo tee /etc/logrotate.d/authentik << EOF
/var/log/caddy/*.log {
daily
rotate 14
compress
delaycompress
notifempty
create 0640 caddy caddy
sharedscripts
postrotate
systemctl reload caddy
endscript
}
EOFCreate maintenance script maintain.sh:
#!/bin/bash
# Update images
docker-compose pull
# Clean up unused images
docker image prune -f
# Restart services
docker-compose down
docker-compose up -d
# Check certificates expiration
for cert in certs/*.crt; do
openssl x509 -noout -enddate -in "$cert"
done
# Check disk usage
df -h
# Check logs for errors
docker-compose logs --tail=1000 | grep -i error# Install security updates automatically
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# Configure SSH
sudo sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Set up fail2ban
sudo apt install -y fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local# Create daemon.json
sudo tee /etc/docker/daemon.json << EOF
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"userns-remap": "default",
"no-new-privileges": true,
"live-restore": true,
"userland-proxy": false
}
EOF
# Restart Docker
sudo systemctl restart docker- Service Won't Start
# Check logs
docker-compose logs [service_name]
# Check container status
docker-compose ps
# Verify configurations
docker-compose config- Certificate Issues
# Verify certificate validity
openssl verify -CAfile rootCA.crt authentik.crt
openssl verify -CAfile rootCA.crt outpost.crt
# Check certificate expiration
openssl x509 -noout -enddate -in authentik.crt- Database Connection Issues
# Check PostgreSQL logs
docker-compose logs postgresql
# Verify PostgreSQL connection
docker-compose exec postgresql psql -U authentik -d authentik -c "\l"- Outpost Connection Issues
# Verify network connectivity
curl -v https://authentik.example.com/api/v3/
# Check outpost logs
docker-compose logs outpost
# Verify token
docker-compose exec authentik ak-verify-tokenTo enable debug logging:
- Update .env file:
AUTHENTIK_LOG_LEVEL=debug- Restart services:
docker-compose down
docker-compose up -dCreate update.sh:
#!/bin/bash
# Backup first
./backup.sh
# Pull new images
docker-compose pull
# Update services one at a time
for service in postgresql redis authentik authentik-worker outpost; do
echo "Updating $service..."
docker-compose up -d --no-deps --build $service
sleep 30
done
# Check logs for errors
docker-compose logs --tail=100Make it executable:
chmod +x update.shCreate postgresql.conf:
max_connections = 100
shared_buffers = 2GB
effective_cache_size = 6GB
maintenance_work_mem = 512MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 52428kB
min_wal_size = 1GB
max_wal_size = 4GB
Create redis.conf:
maxmemory 1gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec
Remember to update your docker-compose.yml to use these configuration files.
- Official Authentik Documentation
- Authentik GitHub Repository
- Docker Documentation
- Caddy Documentation
Would you like me to continue with the rest of the configuration, including the worker configuration, outpost deployment, monitoring setup, backup procedures, and troubleshooting guides?# Comprehensive Authentik Deployment Guide
## Prerequisites
- A Linux server (Ubuntu 22.04 LTS recommended)
- Domain names pointing to your server
- Root or sudo access
- Docker and Docker Compose installed
- At least 2GB RAM, 2 CPU cores
- 20GB storage minimum
## 1. System Preparation
### Update System
```bash
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git ufw
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enablecurl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
sudo systemctl enable --now dockersudo apt install -y docker-composeCreate the following A records in your DNS management system:
authentik.example.com → YOUR_SERVER_IP
outpost.example.com → YOUR_SERVER_IP
# Install dig if not present
sudo apt install -y dnsutils
# Verify DNS records
dig authentik.example.com +short
dig outpost.example.com +short
# Wait for DNS propagation (can take up to 24 hours)mkdir -p ~/authentik/certs
cd ~/authentik/certsopenssl req -x509 \
-newkey rsa:4096 \
-keyout rootCA.key \
-out rootCA.crt \
-days 3650 \
-nodes \
-sha512 \
-subj "/C=US/ST=State/L=City/O=YourOrg/OU=IT/CN=YourOrg Root CA" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,digitalSignature,keyCertSign,cRLSign"# Generate private key
openssl genrsa -out authentik.key 4096
# Generate CSR
openssl req -new \
-key authentik.key \
-out authentik.csr \
-sha512 \
-subj "/C=US/ST=State/L=City/O=YourOrg/OU=IT/CN=authentik.example.com"
# Generate certificate
openssl x509 -req \
-in authentik.csr \
-CA rootCA.crt \
-CAkey rootCA.key \
-CAcreateserial \
-out authentik.crt \
-days 365 \
-sha512 \
-extfile <(printf "subjectAltName=DNS:authentik.example.com\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth")# Generate private key
openssl genrsa -out outpost.key 4096
# Generate CSR
openssl req -new \
-key outpost.key \
-out outpost.csr \
-sha512 \
-subj "/C=US/ST=State/L=City/O=YourOrg/OU=IT/CN=outpost.example.com"
# Generate certificate
openssl x509 -req \
-in outpost.csr \
-CA rootCA.crt \
-CAkey rootCA.key \
-CAcreateserial \
-out outpost.crt \
-days 365 \
-sha512 \
-extfile <(printf "subjectAltName=DNS:outpost.example.com\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth")chmod 600 *.key
chmod 644 *.crtsudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddyCreate /etc/caddy/Caddyfile:
{
# Global options
admin off # Disable admin API for security
auto_https off # We're managing our own certificates
local_certs # Use local certificates instead of Let's Encrypt
}
authentik.example.com {
encode gzip
# TLS configuration
tls /etc/caddy/certs/authentik.crt /etc/caddy/certs/authentik.key {
protocols tls1.3
ciphers TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256
}
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
X-XSS-Protection "1; mode=block"
}
# Reverse proxy configuration
reverse_proxy localhost:9000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
health_check /healthz
}
# Logging
log {
output file /var/log/caddy/authentik.access.log {
roll_size 10MB
roll_keep 10
}
format json
}
}
outpost.example.com {
encode gzip
# TLS configuration
tls /etc/caddy/certs/outpost.crt /etc/caddy/certs/outpost.key {
protocols tls1.3
ciphers TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256
}
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
X-XSS-Protection "1; mode=block"
}
# Reverse proxy configuration
reverse_proxy localhost:8000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
health_check /healthz
}
# Logging
log {
output file /var/log/caddy/outpost.access.log {
roll_size 10MB
roll_keep 10
}
format json
}
}sudo mkdir -p /etc/caddy/certs
sudo cp ~/authentik/certs/{authentik,outpost}.{crt,key} /etc/caddy/certs/
sudo chown -R caddy:caddy /etc/caddy/certs
sudo chmod 600 /etc/caddy/certs/*.keysudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddysudo systemctl enable caddy
sudo systemctl restart caddymkdir -p ~/authentik/{postgres,redis}
cd ~/authentikCreate .env:
# PostgreSQL
POSTGRES_USER=authentik
POSTGRES_PASSWORD=$(openssl rand -base64 32)
POSTGRES_DB=authentik
# Redis
REDIS_PASSWORD=$(openssl rand -base64 32)
# Authentik
AUTHENTIK_SECRET_KEY=$(openssl rand -base64 48)
AUTHENTIK_ERROR_REPORTING__ENABLED=false
AUTHENTIK_DISABLE_STARTUP_ANALYTICS=true
AUTHENTIK_LOG_LEVEL=info
# Email (replace with your settings)
AUTHENTIK_EMAIL__HOST=smtp.example.com
AUTHENTIK_EMAIL__PORT=587
AUTHENTIK_EMAIL__USERNAME=noreply@example.com
AUTHENTIK_EMAIL__PASSWORD=your-smtp-password
AUTHENTIK_EMAIL__USE_TLS=true
AUTHENTIK_EMAIL__FROM=noreply@example.comCreate docker-compose.yml:
version: '3.8'
services:
postgresql:
image: postgres:15-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- authentik
redis:
image: redis:alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- ./redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- authentik
authentik:
image: ghcr.io/goauthentik/server:2024.2.1
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_REDIS__PASSWORD: ${REDIS_PASSWORD}
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${POSTGRES_USER}
AUTHENTIK_POSTGRESQL__PASSWORD: ${POSTGRES_PASSWORD}
AUTHENTIK_POSTGRESQL__DATABASE: ${POSTGRES_DB}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING__ENABLED}
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: ${AUTHENTIK_DISABLE_STARTUP_ANALYTICS}
AUTHENTIK_LOG_LEVEL: ${AUTHENTIK_LOG_LEVEL}
AUTHENTIK_EMAIL__HOST: ${AUTHENTIK_EMAIL__HOST}
AUTHENTIK_EMAIL__PORT: ${AUTHENTIK_EMAIL__PORT}
AUTHENTIK_EMAIL__USERNAME: ${AUTHENTIK_EMAIL__USERNAME}
AUTHENTIK_EMAIL__PASSWORD: ${AUTHENTIK_EMAIL__PASSWORD}
AUTHENTIK_EMAIL__USE_TLS: ${AUTHENTIK_EMAIL__USE_TLS}
AUTHENTIK_EMAIL__FROM: ${AUTHENTIK_EMAIL__FROM}
volumes:
- ./media:/media
- ./certs:/certs
- ./custom-templates:/templates
ports:
- "127.0.0.1:9000:9000"
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/healthz/"]
interval: 30s
timeout: 10s
retries: 5
networks:
- authentik
authentik-worker:
image: ghcr.io/goauthentik/server:2024.2.1
restart: unless-stopped
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_REDIS__PASSWORD: ${REDIS_PASSWORD}
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${POSTGRES_USER}
AUTHENTIK_POSTGRESQL__PASSWORD: ${POSTGRES_PASSWORD}
AUTHENTIK_POSTGRESQL__DATABASE: ${POSTGRES_DB}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING__ENABLED}
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: ${AUTHENTIK_DISABLE_STARTUP_ANALYTICS}
AUTHENTIK_LOG_LEVEL: ${AUTHENTIK_LOG_LEVEL}
AUTHENTIK_EMAIL__HOST: ${AUTHENTIK_EMAIL__HOST}
AUTHENTIK_EMAIL__PORT: ${AUTHENTIK_EMAIL__PORT}
AUTHENTIK_EMAIL__USERNAME: ${AUTHENTIK_EMAIL__USERNAME}
AUTHENTIK_EMAIL__PASSWORD: ${AUTHENTIK_EMAIL__PASSWORD}
AUTHENTIK_EMAIL__USE_TLS: ${AUTHENTIK_EMAIL__USE_TLS}
AUTHENTIK_EMAIL__FROM: ${AUTHENTIK_EMAIL__FROM}
volumes:
- ./media:/media
- ./certs:/certs
- ./custom-templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/healthz/"]
interval: 30s
timeout: 10s
retries: 5
networks:
- authentik
outpost:
image: ghcr.io/goauthentik/outpost:2024.2.1
restart: unless-stopped
pid: host
environment:
AUTHENTIK_HOST: https://authentik.example.com
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN} # Will be configured later
AUTHENTIK_INSECURE: "false"
volumes:
- ./certs:/certs:ro
ports:
- "127.0.0.1:8000:8000"
depends_on:
- authentik
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/healthz/"]
interval: 30s
timeout: 10s
retries: 5
networks:
- authentik
networks:
authentik:
driver: bridge
volumes:
media:
custom-templates:
## 6. Initial Deployment and Configuration
### Start the Stack
```bash
# Create required directories with proper permissions
mkdir -p media custom-templates
chmod 755 media custom-templates
# Start the services
docker-compose up -d# Watch the logs
docker-compose logs -f --tail=100
# Check service status
docker-compose ps- Wait a few minutes for all services to start and initialize
- Navigate to https://authentik.example.com
- Follow the setup wizard to create the admin account
- Configure initial settings:
- Set up email configuration
- Configure password policies
- Set up MFA preferences
-
In the Authentik admin interface:
- Go to System → Outposts
- Create a new Proxy Outpost
- Copy the generated token
-
Add the token to your .env file:
echo "AUTHENTIK_OUTPOST_TOKEN=your-token-here" >> .env- Restart the outpost:
docker-compose restart outpostCreate backup.sh:
#!/bin/bash
BACKUP_DIR="/path/to/backup/directory"
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p "$BACKUP_DIR/$DATE"
# Stop services
docker-compose down
# Backup PostgreSQL
docker-compose run --rm postgresql pg_dump \
-U "$POSTGRES_USER" \
-d "$POSTGRES_DB" \
> "$BACKUP_DIR/$DATE/authentik_db.sql"
# Backup files
tar -czf "$BACKUP_DIR/$DATE/media.tar.gz" ./media
tar -czf "$BACKUP_DIR/$DATE/custom-templates.tar.gz" ./custom-templates
tar -czf "$BACKUP_DIR/$DATE/certs.tar.gz" ./certs
# Backup environment file
cp .env "$BACKUP_DIR/$DATE/"
# Start services
docker-compose up -d
# Cleanup old backups (keep last 7 days)
find "$BACKUP_DIR" -type d -mtime +7 -exec rm -rf {} +chmod +x backup.sh
sudo cp backup.sh /etc/cron.daily/authentik-backup# Stop services
docker-compose down
# Restore PostgreSQL
docker-compose run --rm postgresql psql \
-U "$POSTGRES_USER" \
-d "$POSTGRES_DB" \
< backup/authentik_db.sql
# Restore files
tar -xzf backup/media.tar.gz
tar -xzf backup/custom-templates.tar.gz
tar -xzf backup/certs.tar.gz
# Restore environment file
cp backup/.env .
# Start services
docker-compose up -dAdd to docker-compose.yml:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus:/etc/prometheus
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
ports:
- "127.0.0.1:9090:9090"
networks:
- authentik
grafana:
image: grafana/grafana:latest
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
ports:
- "127.0.0.1:3000:3000"
networks:
- authentik
volumes:
prometheus_data:
grafana_data:Create logrotate configuration:
sudo tee /etc/logrotate.d/authentik << EOF
/var/log/caddy/*.log {
daily
rotate 14
compress
delaycompress
notifempty
create 0640 caddy caddy
sharedscripts
postrotate
systemctl reload caddy
endscript
}
EOFCreate maintenance script maintain.sh:
#!/bin/bash
# Update images
docker-compose pull
# Clean up unused images
docker image prune -f
# Restart services
docker-compose down
docker-compose up -d
# Check certificates expiration
for cert in certs/*.crt; do
openssl x509 -noout -enddate -in "$cert"
done
# Check disk usage
df -h
# Check logs for errors
docker-compose logs --tail=1000 | grep -i error# Install security updates automatically
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# Configure SSH
sudo sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Set up fail2ban
sudo apt install -y fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local# Create daemon.json
sudo tee /etc/docker/daemon.json << EOF
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"userns-remap": "default",
"no-new-privileges": true,
"live-restore": true,
"userland-proxy": false
}
EOF
# Restart Docker
sudo systemctl restart docker- Service Won't Start
# Check logs
docker-compose logs [service_name]
# Check container status
docker-compose ps
# Verify configurations
docker-compose config- Certificate Issues
# Verify certificate validity
openssl verify -CAfile rootCA.crt authentik.crt
openssl verify -CAfile rootCA.crt outpost.crt
# Check certificate expiration
openssl x509 -noout -enddate -in authentik.crt- Database Connection Issues
# Check PostgreSQL logs
docker-compose logs postgresql
# Verify PostgreSQL connection
docker-compose exec postgresql psql -U authentik -d authentik -c "\l"- Outpost Connection Issues
# Verify network connectivity
curl -v https://authentik.example.com/api/v3/
# Check outpost logs
docker-compose logs outpost
# Verify token
docker-compose exec authentik ak-verify-tokenTo enable debug logging:
- Update .env file:
AUTHENTIK_LOG_LEVEL=debug- Restart services:
docker-compose down
docker-compose up -dCreate update.sh:
#!/bin/bash
# Backup first
./backup.sh
# Pull new images
docker-compose pull
# Update services one at a time
for service in postgresql redis authentik authentik-worker outpost; do
echo "Updating $service..."
docker-compose up -d --no-deps --build $service
sleep 30
done
# Check logs for errors
docker-compose logs --tail=100Make it executable:
chmod +x update.shCreate postgresql.conf:
max_connections = 100
shared_buffers = 2GB
effective_cache_size = 6GB
maintenance_work_mem = 512MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 52428kB
min_wal_size = 1GB
max_wal_size = 4GB
Create redis.conf:
maxmemory 1gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec
Remember to update your docker-compose.yml to use these configuration files.
- Official Authentik Documentation
- Authentik GitHub Repository
- Docker Documentation
- Caddy Documentation
Would you like me to continue with the rest of the configuration, including the worker configuration, outpost deployment, monitoring setup, backup procedures, and troubleshooting guides?