Skip to content

Instantly share code, notes, and snippets.

@tribixbite
Created November 16, 2024 02:22
Show Gist options
  • Select an option

  • Save tribixbite/e0f42d42dbb39cbe7e29b692abca868b to your computer and use it in GitHub Desktop.

Select an option

Save tribixbite/e0f42d42dbb39cbe7e29b692abca868b to your computer and use it in GitHub Desktop.
authentik caddy

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

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git ufw

Configure Firewall

sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS
sudo ufw enable

Install Docker (if not installed)

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
sudo systemctl enable --now docker

Install Docker Compose

sudo apt install -y docker-compose

2. DNS Configuration

Set Up DNS Records

Create the following A records in your DNS management system:

authentik.example.com  →  YOUR_SERVER_IP
outpost.example.com   →  YOUR_SERVER_IP

Verify DNS Configuration

# 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)

3. SSL Certificate Generation

Create Certificate Directory

mkdir -p ~/authentik/certs
cd ~/authentik/certs

Generate Root CA with Strong Parameters

openssl 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 Authentik Certificate

# 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 Outpost Certificate

# 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")

Set Proper Permissions

chmod 600 *.key
chmod 644 *.crt

4. Install and Configure Caddy

Install Caddy

sudo 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 caddy

Configure Caddy

Create /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
    }
}

Copy Certificates

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/*.key

Create Log Directory

sudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddy

Start Caddy

sudo systemctl enable caddy
sudo systemctl restart caddy

5. Deploy Authentik

Create Directory Structure

mkdir -p ~/authentik/{postgres,redis}
cd ~/authentik

Create Environment File

Create .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.com

Create Docker Compose File

Create 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

Monitor Initial Startup

# Watch the logs
docker-compose logs -f --tail=100

# Check service status
docker-compose ps

Initial Setup

  1. Wait a few minutes for all services to start and initialize
  2. Navigate to https://authentik.example.com
  3. Follow the setup wizard to create the admin account
  4. Configure initial settings:
    • Set up email configuration
    • Configure password policies
    • Set up MFA preferences

Configure Outpost Token

  1. In the Authentik admin interface:

    • Go to System → Outposts
    • Create a new Proxy Outpost
    • Copy the generated token
  2. Add the token to your .env file:

echo "AUTHENTIK_OUTPOST_TOKEN=your-token-here" >> .env
  1. Restart the outpost:
docker-compose restart outpost

7. Backup and Recovery

Create Backup Script

Create 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 {} +

Schedule Regular Backups

chmod +x backup.sh
sudo cp backup.sh /etc/cron.daily/authentik-backup

Recovery Process

# 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 -d

8. Monitoring and Maintenance

Set Up Prometheus Monitoring

Add 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:

Set Up Log Management

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
}
EOF

Regular Maintenance Tasks

Create 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

9. Security Hardening

System Hardening

# 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

Docker Security

# 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

10. Troubleshooting

Common Issues and Solutions

  1. Service Won't Start
# Check logs
docker-compose logs [service_name]

# Check container status
docker-compose ps

# Verify configurations
docker-compose config
  1. 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
  1. Database Connection Issues
# Check PostgreSQL logs
docker-compose logs postgresql

# Verify PostgreSQL connection
docker-compose exec postgresql psql -U authentik -d authentik -c "\l"
  1. 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-token

Debug Mode

To enable debug logging:

  1. Update .env file:
AUTHENTIK_LOG_LEVEL=debug
  1. Restart services:
docker-compose down
docker-compose up -d

11. Updating

Create Update Script

Create 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=100

Make it executable:

chmod +x update.sh

12. Performance Tuning

PostgreSQL Tuning

Create 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

Redis Tuning

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.

13. Additional Resources

14. Support and Community


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

Configure Firewall

sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS
sudo ufw enable

Install Docker (if not installed)

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
sudo systemctl enable --now docker

Install Docker Compose

sudo apt install -y docker-compose

2. DNS Configuration

Set Up DNS Records

Create the following A records in your DNS management system:

authentik.example.com  →  YOUR_SERVER_IP
outpost.example.com   →  YOUR_SERVER_IP

Verify DNS Configuration

# 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)

3. SSL Certificate Generation

Create Certificate Directory

mkdir -p ~/authentik/certs
cd ~/authentik/certs

Generate Root CA with Strong Parameters

openssl 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 Authentik Certificate

# 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 Outpost Certificate

# 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")

Set Proper Permissions

chmod 600 *.key
chmod 644 *.crt

4. Install and Configure Caddy

Install Caddy

sudo 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 caddy

Configure Caddy

Create /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
    }
}

Copy Certificates

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/*.key

Create Log Directory

sudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddy

Start Caddy

sudo systemctl enable caddy
sudo systemctl restart caddy

5. Deploy Authentik

Create Directory Structure

mkdir -p ~/authentik/{postgres,redis}
cd ~/authentik

Create Environment File

Create .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.com

Create Docker Compose File

Create 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

Monitor Initial Startup

# Watch the logs
docker-compose logs -f --tail=100

# Check service status
docker-compose ps

Initial Setup

  1. Wait a few minutes for all services to start and initialize
  2. Navigate to https://authentik.example.com
  3. Follow the setup wizard to create the admin account
  4. Configure initial settings:
    • Set up email configuration
    • Configure password policies
    • Set up MFA preferences

Configure Outpost Token

  1. In the Authentik admin interface:

    • Go to System → Outposts
    • Create a new Proxy Outpost
    • Copy the generated token
  2. Add the token to your .env file:

echo "AUTHENTIK_OUTPOST_TOKEN=your-token-here" >> .env
  1. Restart the outpost:
docker-compose restart outpost

7. Backup and Recovery

Create Backup Script

Create 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 {} +

Schedule Regular Backups

chmod +x backup.sh
sudo cp backup.sh /etc/cron.daily/authentik-backup

Recovery Process

# 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 -d

8. Monitoring and Maintenance

Set Up Prometheus Monitoring

Add 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:

Set Up Log Management

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
}
EOF

Regular Maintenance Tasks

Create 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

9. Security Hardening

System Hardening

# 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

Docker Security

# 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

10. Troubleshooting

Common Issues and Solutions

  1. Service Won't Start
# Check logs
docker-compose logs [service_name]

# Check container status
docker-compose ps

# Verify configurations
docker-compose config
  1. 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
  1. Database Connection Issues
# Check PostgreSQL logs
docker-compose logs postgresql

# Verify PostgreSQL connection
docker-compose exec postgresql psql -U authentik -d authentik -c "\l"
  1. 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-token

Debug Mode

To enable debug logging:

  1. Update .env file:
AUTHENTIK_LOG_LEVEL=debug
  1. Restart services:
docker-compose down
docker-compose up -d

11. Updating

Create Update Script

Create 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=100

Make it executable:

chmod +x update.sh

12. Performance Tuning

PostgreSQL Tuning

Create 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

Redis Tuning

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.

13. Additional Resources

14. Support and Community


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?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment