Authentication & SSO Guide

    Deploying Authelia on RamNode VPS

    Authelia is an open-source authentication and authorization server providing two-factor authentication and single sign-on via a web portal. This guide walks through deploying Authelia with Docker Compose and Traefik on a RamNode VPS.

    Ubuntu 24.04 LTS
    Docker Compose
    โฑ๏ธ 30-45 minutes

    Key Features

    • Single Sign-On across all self-hosted apps
    • MFA via TOTP, WebAuthn/FIDO2, Duo Push
    • Fine-grained access control rules
    • OpenID Connect 1.0 provider (Certifiedโ„ข)
    • Brute-force protection & account lockout
    • Lightweight single-container deployment

    Prerequisites

    Before starting, ensure you have the following:

    Server Requirements

    ResourceMinimumRecommended
    CPU1 vCPU2 vCPU
    RAM1 GB2 GB
    Storage10 GB SSD20 GB SSD
    OSUbuntu 22.04Ubuntu 24.04

    Software Requirements

    • โ€ข Docker Engine 24.0+ & Docker Compose V2
    • โ€ข Registered domain with DNS pointed to VPS
    • โ€ข SSH access with sudo privileges
    • โ€ข Basic Linux & YAML familiarity

    ๐Ÿ’ก RamNode's VPS Standard or Premium plans with 2 GB RAM are ideal for running Authelia alongside Traefik.

    2

    Initial Server Setup

    Update the System

    System Update
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y curl git ca-certificates gnupg lsb-release

    Install Docker and Docker Compose

    Install Docker
    curl -fsSL https://get.docker.com | sudo sh
    sudo usermod -aG docker $USER
    newgrp docker

    Verify Installation

    Check Versions
    docker --version
    docker compose version

    Configure Firewall

    Configure UFW
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable
    3

    DNS Configuration

    Configure DNS A records pointing to your RamNode VPS public IP address:

    Record TypeHostPurpose
    Aauth.example.comAuthelia portal
    Atraefik.example.comTraefik dashboard
    Aapp.example.comProtected app

    โ„น๏ธ Replace example.com with your actual domain throughout this guide. DNS propagation may take up to 24 hours.

    4

    Create the Project Structure

    Create Directory Layout

    Create Directories
    mkdir -p ~/authelia-stack/authelia/{config,secrets}
    mkdir -p ~/authelia-stack/traefik/{config,data,logs}
    touch ~/authelia-stack/traefik/data/acme.json
    chmod 600 ~/authelia-stack/traefik/data/acme.json
    cd ~/authelia-stack

    Expected Directory Tree

    Directory Structure
    authelia-stack/
    โ”œโ”€โ”€ compose.yml
    โ”œโ”€โ”€ authelia/
    โ”‚   โ”œโ”€โ”€ config/
    โ”‚   โ”‚   โ”œโ”€โ”€ configuration.yml
    โ”‚   โ”‚   โ””โ”€โ”€ users.yml
    โ”‚   โ””โ”€โ”€ secrets/
    โ””โ”€โ”€ traefik/
        โ”œโ”€โ”€ config/
        โ”‚   โ””โ”€โ”€ traefik.yml
        โ”œโ”€โ”€ data/
        โ”‚   โ””โ”€โ”€ acme.json
        โ””โ”€โ”€ logs/
    5

    Generate Secrets

    Authelia requires several secret values for secure operation. Generate them using the built-in crypto utility:

    Generate Secrets
    docker run --rm authelia/authelia:latest authelia \
      crypto rand --length 64 --charset alphanumeric \
      > ~/authelia-stack/authelia/secrets/jwt_secret
    
    docker run --rm authelia/authelia:latest authelia \
      crypto rand --length 64 --charset alphanumeric \
      > ~/authelia-stack/authelia/secrets/session_secret
    
    docker run --rm authelia/authelia:latest authelia \
      crypto rand --length 64 --charset alphanumeric \
      > ~/authelia-stack/authelia/secrets/storage_encryption_key

    Set Permissions

    Secure Secrets
    chmod 600 ~/authelia-stack/authelia/secrets/*

    โš ๏ธ Warning: Never commit secret files to version control. Add the secrets/ directory to your .gitignore if using Git.

    6

    Configure Traefik

    Static Traefik Configuration

    Create traefik/config/traefik.yml:

    traefik/config/traefik.yml
    api:
      dashboard: true
    
    entryPoints:
      http:
        address: ':80'
        http:
          redirections:
            entryPoint:
              to: https
              scheme: https
      https:
        address: ':443'
    
    certificatesResolvers:
      letsencrypt:
        acme:
          email: your-email@example.com
          storage: /data/acme.json
          httpChallenge:
            entryPoint: http
    
    providers:
      docker:
        exposedByDefault: false
        network: proxy
    
    log:
      level: INFO
      filePath: /logs/traefik.log

    โ„น๏ธ Replace your-email@example.com with your actual email for Let's Encrypt certificate notifications.

    7

    Configure Authelia

    Main Configuration

    Create authelia/config/configuration.yml:

    authelia/config/configuration.yml
    ---
    theme: 'auto'
    
    server:
      address: 'tcp://:9091'
    
    log:
      level: 'info'
    
    totp:
      issuer: 'auth.example.com'
      period: 30
      skew: 1
    
    identity_validation:
      reset_password:
        jwt_secret: 'REPLACE_WITH_JWT_SECRET'
    
    authentication_backend:
      file:
        path: '/config/users.yml'
        password:
          algorithm: 'argon2'
          argon2:
            variant: 'argon2id'
            iterations: 3
            memory: 65536
            parallelism: 4
            key_length: 32
            salt_length: 16
    
    access_control:
      default_policy: 'deny'
      rules:
        - domain: 'public.example.com'
          policy: 'bypass'
        - domain: 'traefik.example.com'
          policy: 'one_factor'
        - domain: '*.example.com'
          policy: 'two_factor'
    
    session:
      secret: 'REPLACE_WITH_SESSION_SECRET'
      cookies:
        - name: 'authelia_session'
          domain: 'example.com'
          authelia_url: 'https://auth.example.com'
          expiration: '1 hour'
          inactivity: '5 minutes'
      default_redirection_url: 'https://app.example.com'
    
    regulation:
      max_retries: 3
      find_time: '2 minutes'
      ban_time: '5 minutes'
    
    storage:
      encryption_key: 'REPLACE_WITH_ENCRYPTION_KEY'
      local:
        path: '/data/db.sqlite3'
    
    notifier:
      filesystem:
        filename: '/data/notification.txt'

    โ„น๏ธ Replace all REPLACE_WITH_* values with the contents of the secret files generated in Step 5. For production, replace the filesystem notifier with SMTP.

    User Database

    First, generate a password hash for your user:

    Generate Password Hash
    docker run --rm authelia/authelia:latest authelia \
      crypto hash generate argon2 --password 'YourSecurePassword'

    Create authelia/config/users.yml with the generated hash:

    authelia/config/users.yml
    ---
    users:
      admin:
        displayname: 'Admin User'
        password: '$argon2id$v=19$m=65536,t=3,p=4$...'
        email: 'admin@example.com'
        groups:
          - 'admins'
          - 'dev'

    โš ๏ธ Warning: Replace the password hash with the actual output from the hash generation command. Never store plaintext passwords.

    8

    Docker Compose Configuration

    Create compose.yml in the project root:

    compose.yml
    ---
    services:
      traefik:
        image: traefik:v3.3
        container_name: traefik
        restart: unless-stopped
        ports:
          - '80:80'
          - '443:443'
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - ./traefik/config/traefik.yml:/traefik.yml:ro
          - ./traefik/data:/data
          - ./traefik/logs:/logs
        networks:
          - proxy
        labels:
          - 'traefik.enable=true'
          - 'traefik.http.routers.traefik.rule=Host(`traefik.example.com`)'
          - 'traefik.http.routers.traefik.entrypoints=https'
          - 'traefik.http.routers.traefik.tls.certresolver=letsencrypt'
          - 'traefik.http.routers.traefik.service=api@internal'
          - 'traefik.http.routers.traefik.middlewares=authelia@docker'
    
      authelia:
        image: docker.io/authelia/authelia:latest
        container_name: authelia
        restart: unless-stopped
        volumes:
          - ./authelia/config:/config:ro
          - ./authelia/data:/data
        networks:
          - proxy
        environment:
          TZ: 'America/Chicago'
        labels:
          - 'traefik.enable=true'
          - 'traefik.http.routers.authelia.rule=Host(`auth.example.com`)'
          - 'traefik.http.routers.authelia.entrypoints=https'
          - 'traefik.http.routers.authelia.tls.certresolver=letsencrypt'
          - 'traefik.http.middlewares.authelia.forwardAuth.address=http://authelia:9091/api/authz/forward-auth'
          - 'traefik.http.middlewares.authelia.forwardAuth.trustForwardHeader=true'
          - 'traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Email,Remote-Name'
    
      # Example protected service
      whoami:
        image: traefik/whoami
        container_name: whoami
        restart: unless-stopped
        networks:
          - proxy
        labels:
          - 'traefik.enable=true'
          - 'traefik.http.routers.whoami.rule=Host(`app.example.com`)'
          - 'traefik.http.routers.whoami.entrypoints=https'
          - 'traefik.http.routers.whoami.tls.certresolver=letsencrypt'
          - 'traefik.http.routers.whoami.middlewares=authelia@docker'
    
    networks:
      proxy:
        name: proxy
        driver: bridge
    9

    Deploy the Stack

    Create Data Directory & Launch

    Deploy
    mkdir -p ~/authelia-stack/authelia/data
    cd ~/authelia-stack
    docker compose up -d

    Monitor Logs

    View Logs
    docker compose logs -f authelia

    โ„น๏ธ You should see Authelia report it is listening on port 9091. Verify all containers are running with docker compose ps.

    10

    Verify the Deployment

    Test the Authelia Portal

    Navigate to https://auth.example.com in your browser to access the login portal.

    Test a Protected Service

    1. 1.Navigate to https://app.example.com
    2. 2.You should be redirected to the Authelia login page
    3. 3.After authentication, you'll be redirected back to the protected service
    4. 4.The whoami service will display Remote-User and Remote-Groups headers

    Verify Access Control Policies

    DomainPolicyExpected Behavior
    public.example.combypassNo authentication required
    traefik.example.comone_factorUsername + password only
    *.example.comtwo_factorUsername + password + TOTP/WebAuthn
    11

    Production Hardening

    Enable SMTP Notifications

    Replace the filesystem notifier with SMTP for production email delivery:

    SMTP Notifier Configuration
    notifier:
      smtp:
        address: 'submissions://smtp.example.com:465'
        username: 'authelia@example.com'
        password: 'your-smtp-password'
        sender: 'Authelia <noreply@example.com>'

    Use Redis for Session Storage

    For high-availability deployments, add Redis for sessions:

    Session Redis Configuration
    session:
      redis:
        host: 'redis'
        port: 6379

    Add a Redis service to your compose.yml:

    Redis Service
    redis:
      image: redis:7-alpine
      container_name: redis
      restart: unless-stopped
      volumes:
        - redis_data:/data
      networks:
        - proxy

    Upgrade to PostgreSQL Storage

    For production workloads, migrate from SQLite to PostgreSQL:

    PostgreSQL Storage Configuration
    storage:
      encryption_key: 'REPLACE_WITH_ENCRYPTION_KEY'
      postgres:
        address: 'tcp://postgres:5432'
        database: 'authelia'
        username: 'authelia'
        password: 'your-db-password'

    Additional Security Recommendations

    • Enable automatic security updates with unattended-upgrades
    • Configure fail2ban to protect SSH access
    • Use Docker secrets instead of inline passwords
    • Set up regular automated backups of the authelia/data directory
    • Keep Docker images updated by periodically pulling latest tags
    12

    Troubleshooting

    Common Issues

    IssueSolution
    502 Bad GatewayEnsure Authelia container is running. Check Docker network name matches in compose.yml and Traefik config.
    Certificate errorsVerify DNS records point to your VPS IP. Check acme.json permissions (must be 600).
    Login loop / redirectsEnsure session cookie domain matches your root domain. Verify authelia_url is accessible.
    TOTP codes not workingVerify server time is synced with NTP. Authelia checks NTP on startup.
    Permission deniedCheck file ownership and permissions. Authelia must read config and write to data directory.

    Useful Commands

    View Authelia Logs
    docker compose logs -f authelia
    Validate Configuration
    docker run --rm -v $(pwd)/authelia/config:/config \
      authelia/authelia:latest authelia config validate \
      --config /config/configuration.yml
    Restart After Config Changes
    docker compose restart authelia
    Check Container Health
    docker inspect --format='{{.State.Health.Status}}' authelia
    Generate New User Password Hash
    docker run --rm authelia/authelia:latest authelia \
      crypto hash generate argon2 --password 'NewPassword'
    13

    Protecting Additional Services

    To protect any new service behind Authelia, add the following Traefik labels to its Docker Compose service definition:

    Traefik Labels for New Services
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.myapp.rule=Host(`myapp.example.com`)'
      - 'traefik.http.routers.myapp.entrypoints=https'
      - 'traefik.http.routers.myapp.tls.certresolver=letsencrypt'
      - 'traefik.http.routers.myapp.middlewares=authelia@docker'

    Then add a corresponding access control rule to your Authelia configuration.yml to define the authentication policy for the new domain.

    ๐Ÿš€ Next Steps

    • Configure OpenID Connect 1.0 for SSO with Gitea, Portainer, and Grafana
    • Set up LDAP authentication backend for centralized user management
    • Implement WebAuthn/FIDO2 hardware key support for passwordless auth
    • Add per-user and per-group access control rules