Files
fail2ban-ui/development/oidc/container-compose.yml

297 lines
11 KiB
YAML

services:
# Keycloak: OIDC Provider (Recommended)
keycloak:
image: quay.io/keycloak/keycloak:latest
container_name: DEV_keycloak
environment:
# Admin credentials (change for production!)
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
# Database settings
KC_DB: postgres
KC_DB_URL_HOST: postgres
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
# Hostname configuration for development
# Using full URL so issuer matches what fail2ban-ui expects
# When using KC_HOSTNAME_BACKCHANNEL_DYNAMIC=true, hostname must be a full URL
# Set KEYCLOAK_PUBLIC_URL environment variable to your server's public URL
# If not set, defaults to http://localhost:3000
KC_HOSTNAME: ${KEYCLOAK_PUBLIC_URL:-http://localhost:3000}
KC_HOSTNAME_STRICT: "false"
KC_HOSTNAME_BACKCHANNEL_DYNAMIC: "true"
# Development mode (use "start" for production)
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
command:
- start-dev
- --http-host=0.0.0.0
- --http-port=8080
ports:
- "0.0.0.0:3000:8080"
- "0.0.0.0:9000:9000" # Management port for health checks
depends_on:
postgres:
condition: service_healthy
volumes:
- ./keycloak-data:/opt/keycloak/data:z
healthcheck:
# Keycloak v26+ uses port 9000 for health endpoints (management port)
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/9000 && echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3 && cat <&3 | grep -q '200 OK' || exit 1"]
interval: 10s
timeout: 5s
retries: 30
start_period: 90s
restart: unless-stopped
networks:
- oidc-network
# PostgreSQL: Database for Keycloak
postgres:
image: postgres:15-alpine
container_name: DEV_keycloak-db
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak
volumes:
- ./keycloak-db:/var/lib/postgresql/data:z
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- oidc-network
# Pocket-ID: OIDC Provider (Alternative 1) - Not fully tested
# Uncomment to use Pocket-ID instead of Keycloak
# pocket-id:
# image: ghcr.io/pocket-id/pocket-id:latest
# container_name: DEV_pocket-id
# environment:
# - APP_URL=http://localhost:3005
# # Encryption key (choose one method):
# # Method 1: Direct key (simple but less secure)
# # Generate with: openssl rand -base64 32
# - ENCRYPTION_KEY=aF98qjUZuCJ_j_9Bh8hXx5U832ZpYQW
# # Method 2: File-based key (recommended)
# # Put the base64 key in a file and point to it here.
# # ENCRYPTION_KEY_FILE=/path/to/encryption_key
# - TRUST_PROXY=false
# - MAXMIND_LICENSE_KEY=
# - PUID=1000
# - PGID=1000
# - DB_PROVIDER=sqlite
# - DB_CONNECTION_STRING=sqlite:///pocket-id/var/db.sqlite
# - PORT=1411
# volumes:
# - ./pocket-id-data:/pocket-id/var:z
# ports:
# - "3005:1411"
# restart: unless-stopped
# networks:
# - oidc-network
# Authentik: OIDC Provider (Alternative 2) - Not fully tested
# Uncomment to use Authentik instead of Keycloak
# Note: Authentik requires additional setup (migrations, initial admin user)
# authentik-server:
# image: ghcr.io/goauthentik/server:latest
# container_name: DEV_authentik-server
# environment:
# - AUTHENTIK_SECRET_KEY=dev-secret-key-change-in-production-generate-with-openssl-rand-base64-60
# - AUTHENTIK_ERROR_REPORTING__ENABLED=false
# - AUTHENTIK_DISABLE_UPDATE_CHECK=true
# - AUTHENTIK_DISABLE_STARTUP_ANALYTICS=true
# - PG_PASS=authentik
# - AUTHENTIK_REDIS__HOST=redis
# - AUTHENTIK_POSTGRESQL__HOST=postgresql
# - AUTHENTIK_POSTGRESQL__USER=authentik
# - AUTHENTIK_POSTGRESQL__PASSWORD=authentik
# - AUTHENTIK_POSTGRESQL__NAME=authentik
# ports:
# - "3007:9000"
# - "3008:9443"
# depends_on:
# - authentik-postgresql
# - authentik-redis
# volumes:
# - ./authentik-media:/media:z
# restart: unless-stopped
# networks:
# - oidc-network
#
# authentik-worker:
# image: ghcr.io/goauthentik/server:latest
# container_name: DEV_authentik-worker
# environment:
# - AUTHENTIK_SECRET_KEY=dev-secret-key-change-in-production-generate-with-openssl-rand-base64-60
# - AUTHENTIK_ERROR_REPORTING__ENABLED=false
# - AUTHENTIK_DISABLE_UPDATE_CHECK=true
# - AUTHENTIK_DISABLE_STARTUP_ANALYTICS=true
# - PG_PASS=authentik
# - AUTHENTIK_REDIS__HOST=redis
# - AUTHENTIK_POSTGRESQL__HOST=postgresql
# - AUTHENTIK_POSTGRESQL__USER=authentik
# - AUTHENTIK_POSTGRESQL__PASSWORD=authentik
# - AUTHENTIK_POSTGRESQL__NAME=authentik
# command: ["authentik", "worker"]
# depends_on:
# - authentik-postgresql
# - authentik-redis
# volumes:
# - ./authentik-media:/media:z
# restart: unless-stopped
# networks:
# - oidc-network
#
# authentik-postgresql:
# image: postgres:15-alpine
# container_name: DEV_authentik-db
# environment:
# POSTGRES_PASSWORD: authentik
# POSTGRES_USER: authentik
# POSTGRES_DB: authentik
# volumes:
# - ./authentik-db:/var/lib/postgresql/data:z
# restart: unless-stopped
# networks:
# - oidc-network
#
# authentik-redis:
# image: redis:7-alpine
# container_name: DEV_authentik-redis
# restart: unless-stopped
# networks:
# - oidc-network
# Keycloak Client Auto-Configuration
# This container automatically creates the OIDC client in Keycloak
# Set PUBLIC_FRONTEND_URL environment variable to your server's public URL (e.g., http://192.168.1.100:3080)
# If not set, defaults to http://localhost:3080
keycloak-init:
image: curlimages/curl:latest
container_name: DEV_keycloak-init
depends_on:
keycloak:
condition: service_healthy
environment:
- KEYCLOAK_URL=http://keycloak:8080
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_PASSWORD=admin
- REALM=master
- CLIENT_ID=fail2ban-ui
# PUBLIC_FRONTEND_URL: Set this to your server's public URL (IP or hostname)
# If not set, defaults to http://localhost:3080
- PUBLIC_FRONTEND_URL=${PUBLIC_FRONTEND_URL:-http://localhost:3080}
- SECRET_FILE=/config/keycloak-client-secret
volumes:
- ./init-keycloak.sh:/init-keycloak.sh:ro
- ./config:/config:z
# Run as root to avoid permission issues
user: "0:0"
command: ["/bin/sh", "-c", "apk add --no-cache jq 2>/dev/null && /bin/sh /init-keycloak.sh 2>&1"]
networks:
- oidc-network
restart: "no" # Only run once
# Fail2ban-UI: Main application with OIDC authentication
fail2ban-ui:
image: localhost/fail2ban-ui:dev
container_name: DEV_fail2ban-ui-oidc
privileged: true
# Use host network to access Keycloak on localhost:3000
# This allows issuer URL to match Keycloak's discovery document
network_mode: host
# ports:
# - "3080:8080" # Not needed with host network
environment:
- PORT=3080
- BIND_ADDRESS=0.0.0.0
# OIDC Configuration for Keycloak (default)
# PUBLIC_FRONTEND_URL: Server's public URL for redirects (if not set, defaults to http://localhost:3080)
# KEYCLOAK_URL: Server's public URL for Keycloak (if not set, defaults to http://localhost:3000)
# Create a .env file with these variables for remote server access
- PUBLIC_FRONTEND_URL=${PUBLIC_FRONTEND_URL:-http://localhost:3080}
- KEYCLOAK_URL=${KEYCLOAK_URL:-http://localhost:3000}
# OIDC settings
- OIDC_ENABLED=true
- OIDC_PROVIDER=keycloak
- OIDC_ISSUER_URL=${KEYCLOAK_URL}/realms/master
- OIDC_CLIENT_ID=fail2ban-ui
- OIDC_CLIENT_SECRET=auto-configured
- OIDC_CLIENT_SECRET_FILE=/config/keycloak-client-secret
- OIDC_REDIRECT_URL=${PUBLIC_FRONTEND_URL}/auth/callback
- OIDC_SCOPES=openid,profile,email
- OIDC_SESSION_MAX_AGE=7200
- OIDC_USERNAME_CLAIM=preferred_username
- OIDC_SKIP_VERIFY=true
# Optional: Skip login page and redirect directly to OIDC provider (default: false)
# When set to true, users are immediately redirected to the OIDC provider without showing the login page
#- OIDC_SKIP_LOGINPAGE=true
# Optional: Logout URL
#- OIDC_LOGOUT_URL=${KEYCLOAK_URL}/realms/master/protocol/openid-connect/logout
# Alternative OIDC Configuration Examples (uncomment and adjust as needed):
# For Pocket-ID:
# - OIDC_PROVIDER=pocketid
# - OIDC_ISSUER_URL=http://localhost:3005
# - OIDC_LOGOUT_URL=http://localhost:3005/logout
#
# For Authentik:
# - OIDC_PROVIDER=authentik
# - OIDC_ISSUER_URL=http://localhost:3007/application/o/fail2ban-ui/
volumes:
# Required for fail2ban-ui: Stores SQLite database, application settings, and SSH keys
- ./config:/config:z
# Required for fail2ban-ui: Used for testing logpath before enabling jails
- /var/log:/var/log:ro
# Required for compose-local fail2ban instance: We mount the same Fail2Ban config as the linuxserver-fail2ban container (under /config/fail2ban to fail2ban-ui can modify configs)
- ./fail2ban-config-local/fail2ban:/etc/fail2ban:z
# Required for compose-local fail2ban instance: Mount the same run directory that contains fail2ban.sock for communication between fail2ban-ui and the linuxserver-fail2ban container
- ./f2b-run-local:/var/run/fail2ban:z
restart: unless-stopped
# Wait for Keycloak to be healthy before starting
# Note: keycloak-init runs as a one-time job, so we only wait for Keycloak
# The application will retry connecting to Keycloak if needed
# Note: With host network mode, depends_on still works but network isolation is bypassed
depends_on:
- keycloak
# Fail2ban-Local: Local Fail2ban instance for testing local connector
fail2ban-local:
image: lscr.io/linuxserver/fail2ban:latest
container_name: DEV_fail2ban-local
cap_add:
# Required for fail2ban container: Allows to manage network interfaces and iptables from the container
- NET_ADMIN
# Required for fail2ban container: Allows to create raw sockets (needed for fail2ban.sock)
- NET_RAW
# Required for fail2ban container: Allows to run as root (needed to manage network interfaces and raw sockets)
- SYS_ADMIN
#privileged: true
network_mode: host # needed to add iptables rules to the host network
environment:
- TZ=Europe/Zurich
- VERBOSITY=-vv
volumes:
# To make sure linuxserver-fail2ban configs are persistent across container restarts (also needed by fail2ban-ui to modify configs)
- ./fail2ban-config-local:/config:z
# Directory that contains fail2ban.sock for communication between fail2ban-ui and fail2ban container
- ./f2b-run-local:/var/run/fail2ban:z
# Log sources for fail2ban container
- /var/log:/var/log:ro
- /var/log/httpd:/remotelogs/apache2:ro
restart: unless-stopped
networks:
oidc-network:
driver: bridge