services: postgres: image: {{ authentik_postgres_image }} restart: unless-stopped environment: POSTGRES_DB: {{ authentik_postgres_db }} POSTGRES_USER: {{ authentik_postgres_user }} POSTGRES_PASSWORD: {{ authentik_postgres_password }} volumes: - {{ authentik_docker_volume_dir }}/postgresql:/var/lib/postgresql/data networks: - {{ authentik_backend_network }} healthcheck: test: ["CMD-SHELL", "pg_isready -d {{ authentik_postgres_db }} -U {{ authentik_postgres_user }}"] start_period: 20s interval: 30s retries: 5 timeout: 5s server: image: {{ authentik_image }} restart: unless-stopped command: server healthcheck: test: ["CMD", "ak", "healthcheck"] start_period: 30s interval: 10s retries: 5 timeout: 5s environment: AUTHENTIK_SECRET_KEY: {{ authentik_secret_key }} AUTHENTIK_POSTGRESQL__HOST: postgres AUTHENTIK_POSTGRESQL__NAME: {{ authentik_postgres_db }} AUTHENTIK_POSTGRESQL__USER: {{ authentik_postgres_user }} AUTHENTIK_POSTGRESQL__PASSWORD: {{ authentik_postgres_password }} AUTHENTIK_LOG_LEVEL: {{ authentik_log_level }} AUTHENTIK_ERROR_REPORTING__ENABLED: "{{ authentik_error_reporting_enabled | lower }}" volumes: - {{ authentik_docker_volume_dir }}/blueprints:/blueprints/custom - {{ authentik_docker_volume_dir }}/data:/data - {{ authentik_docker_volume_dir }}/templates:/templates depends_on: postgres: condition: service_healthy networks: {{ authentik_backend_network }}: {} # No alias for the public FQDN here: that would shadow `/etc/hosts` # pins (extra_hosts) in other containers sharing this network and # break OIDC discovery for Node-based clients (c-ares-based # resolvers consult Docker DNS before /etc/hosts). The URL-based # service below addresses this container by its compose service # name `server`, which Docker exposes as an alias on every network # the container joins. {{ authentik_traefik_network }}: {} labels: - traefik.enable=true - traefik.docker.network={{ authentik_traefik_network }} - traefik.http.routers.{{ authentik_service_name }}.rule={% for d in authentik_domains %}Host(`{{ d }}`){% if not loop.last %} || {% endif %}{% endfor +%} - traefik.http.routers.{{ authentik_service_name }}.service={{ authentik_service_name }} {% if authentik_use_ssl %} - traefik.http.routers.{{ authentik_service_name }}.entrypoints=websecure - traefik.http.routers.{{ authentik_service_name }}.tls=true {% if traefik_cert_mode | default('selfsigned') == 'acme' %} - traefik.http.routers.{{ authentik_service_name }}.tls.certresolver={{ traefik_ssl_cert_resolver | default('dns') }} {% endif %} {% else %} - traefik.http.routers.{{ authentik_service_name }}.entrypoints=web {% endif %} - traefik.http.services.{{ authentik_service_name }}.loadbalancer.server.port={{ authentik_port }} {% if authentik_host_rewrite_domains | length > 0 %} # Server-to-server entry: a separate service points at this very # container by its compose service name `server` and disables # passHostHeader so the upstream Host header becomes # `{{ authentik_domains[0] }}`. Authentik builds OIDC issuer URLs # from X-Forwarded-Host (not Host), so we also pin that header via # middleware. Together this keeps the iss claim aligned with the # public hostname browsers see during login, even when the request # itself arrived on an internal *.int.* FQDN. - traefik.http.services.{{ authentik_service_name }}-rewrite.loadbalancer.server.url=http://server:{{ authentik_port }} - traefik.http.services.{{ authentik_service_name }}-rewrite.loadbalancer.passhostheader=false - traefik.http.middlewares.{{ authentik_service_name }}-xfh-rewrite.headers.customrequestheaders.X-Forwarded-Host={{ authentik_domains[0] }} {% for d in authentik_host_rewrite_domains %} - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.rule=Host(`{{ d }}`) - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.priority=100 - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.service={{ authentik_service_name }}-rewrite - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.middlewares={{ authentik_service_name }}-xfh-rewrite {% if authentik_use_ssl %} - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.entrypoints=websecure - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.tls=true {% if traefik_cert_mode | default('selfsigned') == 'acme' %} - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.tls.certresolver={{ traefik_ssl_cert_resolver | default('dns') }} {% endif %} {% else %} - traefik.http.routers.{{ authentik_service_name }}-rewrite-{{ loop.index0 }}.entrypoints=web {% endif %} {% endfor %} {% endif %} worker: image: {{ authentik_image }} restart: unless-stopped command: worker user: root environment: AUTHENTIK_SECRET_KEY: {{ authentik_secret_key }} AUTHENTIK_POSTGRESQL__HOST: postgres AUTHENTIK_POSTGRESQL__NAME: {{ authentik_postgres_db }} AUTHENTIK_POSTGRESQL__USER: {{ authentik_postgres_user }} AUTHENTIK_POSTGRESQL__PASSWORD: {{ authentik_postgres_password }} AUTHENTIK_LOG_LEVEL: {{ authentik_log_level }} AUTHENTIK_ERROR_REPORTING__ENABLED: "{{ authentik_error_reporting_enabled | lower }}" volumes: - {{ authentik_docker_volume_dir }}/data:/data - {{ authentik_docker_volume_dir }}/certs:/certs - {{ authentik_docker_volume_dir }}/templates:/templates - {{ authentik_docker_volume_dir }}/blueprints:/blueprints/custom depends_on: postgres: condition: service_healthy networks: - {{ authentik_backend_network }} networks: {{ authentik_backend_network }}: {{ authentik_traefik_network }}: external: true