Auth Middleware
    Open Source

    Deploy Tinyauth on a VPS

    Lightweight authentication middleware (~20 MB) with local logins, OAuth, TOTP 2FA, LDAP, per-app ACLs, and OIDC server — protects any app behind Traefik, Nginx, or Caddy.

    At a Glance

    ProjectTinyauth v5
    LicenseMIT
    Recommended PlanRamNode Cloud VPS 1 GB+ (negligible resource usage)
    OSUbuntu 22.04 / 24.04 LTS
    StackDocker, Traefik v3, Let's Encrypt
    Estimated Setup Time15–20 minutes

    Prerequisites

    • A RamNode VPS with at least 1 GB RAM
    • Ubuntu 22.04 or 24.04 LTS with Docker and Docker Compose installed
    • A registered domain name with DNS managed through your provider
    • SSH access with a non-root sudo user
    1

    Configure DNS Records

    Tinyauth uses cookie-based auth scoped to the parent domain. All protected apps must share the same root domain.

    HostnameTypeValue
    tinyauth.example.comAYOUR_VPS_IP
    whoami.example.comAYOUR_VPS_IP
    2

    Create a Tinyauth User

    Generate user credentials
    docker run -i -t --rm ghcr.io/steveiliop56/tinyauth:v5 user create --interactive

    Select "format for docker" so bcrypt $ characters are escaped with $ for Docker Compose. Copy the output.

    3

    Docker Compose Setup

    Create project directory
    mkdir -p ~/tinyauth && cd ~/tinyauth
    docker-compose.yml
    services:
      traefik:
        image: traefik:v3.3
        container_name: traefik
        restart: unless-stopped
        command:
          - --api.dashboard=true
          - --providers.docker=true
          - --providers.docker.exposedbydefault=false
          - --entrypoints.web.address=:80
          - --entrypoints.websecure.address=:443
          - --certificatesresolvers.letsencrypt.acme.httpchallenge=true
          - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
          - --certificatesresolvers.letsencrypt.acme.email=you@example.com
          - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
          - --entrypoints.web.http.redirections.entrypoint.to=websecure
          - --entrypoints.web.http.redirections.entrypoint.scheme=https
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - letsencrypt:/letsencrypt
    
      tinyauth:
        image: ghcr.io/steveiliop56/tinyauth:v5
        container_name: tinyauth
        restart: unless-stopped
        environment:
          - TINYAUTH_APPURL=https://tinyauth.example.com
          - TINYAUTH_AUTH_USERS=admin:$2a$10$YOUR_BCRYPT_HASH
          - TINYAUTH_AUTH_SECURECOOKIE=true
          - TINYAUTH_AUTH_SESSIONEXPIRY=86400
          - TINYAUTH_AUTH_LOGINMAXRETRIES=5
          - TINYAUTH_AUTH_LOGINTIMEOUT=300
        labels:
          traefik.enable: true
          traefik.http.routers.tinyauth.rule: Host(`tinyauth.example.com`)
          traefik.http.routers.tinyauth.entrypoints: websecure
          traefik.http.routers.tinyauth.tls.certresolver: letsencrypt
          traefik.http.middlewares.tinyauth.forwardauth.address: http://tinyauth:3000/api/auth/traefik
    
      whoami:
        image: traefik/whoami:latest
        container_name: whoami
        restart: unless-stopped
        labels:
          traefik.enable: true
          traefik.http.routers.whoami.rule: Host(`whoami.example.com`)
          traefik.http.routers.whoami.entrypoints: websecure
          traefik.http.routers.whoami.tls.certresolver: letsencrypt
          traefik.http.routers.whoami.middlewares: tinyauth
    
    volumes:
      letsencrypt:
    4

    Launch the Stack

    Start services
    docker compose up -d
    docker compose ps

    All three containers should show Up. Visit https://whoami.example.com — you should be redirected to the Tinyauth login page.

    5

    Add GitHub OAuth (Optional)

    Create a GitHub OAuth App with callback URL: https://tinyauth.example.com/api/oauth/callback/github

    Add OAuth environment variables
    # Add to tinyauth service environment:
    - TINYAUTH_OAUTH_PROVIDERS_GITHUB_CLIENTID=your_client_id
    - TINYAUTH_OAUTH_PROVIDERS_GITHUB_CLIENTSECRET=your_client_secret
    - TINYAUTH_OAUTH_WHITELIST=yourgithub@email.com
    Restart stack
    docker compose up -d
    6

    Enable Two-Factor Authentication (Optional)

    Generate user with TOTP
    docker run -i -t --rm ghcr.io/steveiliop56/tinyauth:v5 user create --interactive --totp

    The CLI outputs a user string with a TOTP secret and a QR code for your authenticator app. Replace the TINYAUTH_AUTH_USERS value and restart.

    7

    Configure Per-App Access Controls

    Environment variable method
    # Restrict whoami to admin only:
    - TINYAUTH_APPS_WHOAMI_CONFIG_DOMAIN=whoami.example.com
    - TINYAUTH_APPS_WHOAMI_USERS_ALLOW=admin

    Additional ACL options include:

    • users.allow / users.block — by username
    • oauth.whitelist / oauth.groups — OAuth-based
    • ip.allow / ip.block / ip.bypass — IP filtering
    • path.allow / path.block — URL path restrictions
    8

    Protect Additional Applications

    Add middleware label to any service
    my-app:
      image: my-app-image:latest
      restart: unless-stopped
      labels:
        traefik.enable: true
        traefik.http.routers.my-app.rule: Host(`myapp.example.com`)
        traefik.http.routers.my-app.entrypoints: websecure
        traefik.http.routers.my-app.tls.certresolver: letsencrypt
        traefik.http.routers.my-app.middlewares: tinyauth

    The key line is middlewares: tinyauth — this routes auth through Tinyauth before reaching the app.

    9

    Production Hardening

    Docker socket proxy
    socket-proxy:
      image: tecnativa/docker-socket-proxy
      container_name: socket-proxy
      restart: unless-stopped
      environment:
        CONTAINERS: 1
        SERVICES: 0
        TASKS: 0
      volumes:
        - /var/run/docker.sock:/var/run/docker.sock:ro
      networks:
        - proxy
    Move secrets to .env file
    cat > .env << 'EOF'
    TINYAUTH_USERS=admin:$2a$10$YOUR_BCRYPT_HASH
    GITHUB_CLIENT_ID=your_client_id
    GITHUB_CLIENT_SECRET=your_client_secret
    OAUTH_WHITELIST=yourgithub@email.com
    EOF
    
    chmod 600 .env
    Firewall and auto-updates
    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable
    Watchtower for automatic updates
    watchtower:
      image: containrrr/watchtower
      container_name: watchtower
      restart: unless-stopped
      volumes:
        - /var/run/docker.sock:/var/run/docker.sock
      environment:
        - WATCHTOWER_CLEANUP=true
        - WATCHTOWER_SCHEDULE=0 0 4 * * *

    Troubleshooting

    • Login page not appearing: Verify the forwardauth middleware label matches in both the Tinyauth service and protected app's router
    • Cookie not working: Confirm all apps share the same root domain and SECURECOOKIE=true is set with HTTPS
    • OAuth redirect fails: Ensure GitHub callback URL matches exactly
    • Container won't start: Tinyauth v5 validates all env vars on startup — check docker compose logs tinyauth