{"id":1863,"date":"2026-02-06T20:16:11","date_gmt":"2026-02-06T18:16:11","guid":{"rendered":"https:\/\/cln.io\/blog\/?p=1863"},"modified":"2026-03-10T20:57:58","modified_gmt":"2026-03-10T18:57:58","slug":"notes-on-getting-authentik-working","status":"publish","type":"post","link":"https:\/\/cln.io\/blog\/notes-on-getting-authentik-working\/","title":{"rendered":"Notes on getting authentik working"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A collection of notes and fixes from setting up <a href=\"https:\/\/goauthentik.io\/\">authentik<\/a> as an identity provider with Active Directory LDAP sync, Traefik forward auth, and Docker Swarm. The two main gotchas: AD syncs computer objects as users by default, and group sync fails out of the box with a cryptic &#8220;run sync_groups first&#8221; error. Below are the fixes and a complete Docker Swarm playground to test it all.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">AD sync fixes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/docs.goauthentik.io\/users-sources\/sources\/directory-sync\/active-directory\/\">set <strong>User object filter<\/strong> to exclude computers <\/a><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">(&amp;(objectClass=user)(!(objectClass=computer)))<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">My groups were not syncing \u2014 authentik kept erroring with &#8220;Group does not exist in our DB yet, run sync_groups first.&#8221; <a href=\"https:\/\/github.com\/goauthentik\/authentik\/issues\/11427#issuecomment-2386066665\">This comment<\/a> on GitHub issue #11427 had the fix: change the group property mapping to use only &#8220;authentik default LDAP Mapping: Name&#8221; and set the object uniqueness field to &#8220;objectSid&#8221;.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"907\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/02\/authentik_groups-1024x907.png\" alt=\"\" class=\"wp-image-1864\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/02\/authentik_groups-1024x907.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/02\/authentik_groups-300x266.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/02\/authentik_groups-768x680.png 768w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/02\/authentik_groups.png 1101w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">My swarm demo playground<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">version: \"3.8\"\n\nservices:\n  postgres:\n    image: postgres:16-alpine\n    environment:\n      POSTGRES_DB: authentik\n      POSTGRES_USER: authentik\n      POSTGRES_PASSWORD: authentik_db_password\n    volumes:\n      - postgres_data:\/var\/lib\/postgresql\/data\n    networks:\n      - backend\n    deploy:\n      replicas: 1\n\n  redis:\n    image: redis:7-alpine\n    command: [\"redis-server\", \"--save\", \"60\", \"1\", \"--loglevel\", \"warning\"]\n    volumes:\n      - redis_data:\/data\n    networks:\n      - backend\n    deploy:\n      replicas: 1\n\n  server:\n    image: ghcr.io\/goauthentik\/server:2025.2.1\n    command: server\n    environment: &amp;authentik-env\n      AUTHENTIK_SECRET_KEY: \"\"\n      AUTHENTIK_POSTGRESQL__HOST: postgres\n      AUTHENTIK_POSTGRESQL__NAME: authentik\n      AUTHENTIK_POSTGRESQL__USER: authentik\n      AUTHENTIK_POSTGRESQL__PASSWORD: authentik_db_password\n      AUTHENTIK_REDIS__HOST: redis\n      AUTHENTIK_BOOTSTRAP_PASSWORD: \"admin\"\n      AUTHENTIK_BOOTSTRAP_TOKEN: \"admin-bootstrap-token\"\n      AUTHENTIK_BOOTSTRAP_EMAIL: \"admin@demo.local\"\n    networks:\n      - proxy\n      - backend\n    deploy:\n      replicas: 1\n      labels:\n        - \"traefik.enable=true\"\n        # Authentik UI\/API\n        - \"traefik.http.routers.authentik.rule=Host(`auth.localhost`)\"\n        - \"traefik.http.routers.authentik.entrypoints=websecure\"\n        - \"traefik.http.routers.authentik.tls=true\"\n        - \"traefik.http.services.authentik.loadbalancer.server.port=9000\"\n        # Embedded outpost: handles \/outpost.goauthentik.io on app.localhost\n        - \"traefik.http.routers.authentik-outpost.rule=Host(`app.localhost`) &amp;&amp; PathPrefix(`\/outpost.goauthentik.io`)\"\n        - \"traefik.http.routers.authentik-outpost.entrypoints=websecure\"\n        - \"traefik.http.routers.authentik-outpost.tls=true\"\n        - \"traefik.http.routers.authentik-outpost.service=authentik\"\n        # Reusable ForwardAuth middleware (points to embedded outpost on the server)\n        - \"traefik.http.middlewares.authentik-auth.forwardauth.address=http:\/\/authentik_server:9000\/outpost.goauthentik.io\/auth\/traefik\"\n        - \"traefik.http.middlewares.authentik-auth.forwardauth.trustForwardHeader=true\"\n        - \"traefik.http.middlewares.authentik-auth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid\"\n\n  worker:\n    image: ghcr.io\/goauthentik\/server:2025.2.1\n    command: worker\n    environment: *authentik-env\n    networks:\n      - backend\n    deploy:\n      replicas: 1\n\nvolumes:\n  postgres_data:\n  redis_data:\n\nnetworks:\n  proxy:\n    external: true\n    name: shared_proxy\n  backend:\n    external: true\n    name: shared_backend\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">My demo app<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">version: \"3.8\"\n\nservices:\n  demo-app:\n    image: traefik\/whoami:latest\n    networks:\n      - proxy\n    deploy:\n      replicas: 1\n      labels:\n        - \"traefik.enable=true\"\n        - \"traefik.http.routers.demo-app.rule=Host(`app.localhost`)\"\n        - \"traefik.http.routers.demo-app.entrypoints=websecure\"\n        - \"traefik.http.routers.demo-app.tls=true\"\n        - \"traefik.http.routers.demo-app.middlewares=authentik-auth@swarm\"\n        - \"traefik.http.services.demo-app.loadbalancer.server.port=80\"\n\nnetworks:\n  proxy:\n    external: true\n    name: shared_proxy\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Traefik (Swarm mode &#8211; for plain Docker Compose, use <code>providers.docker<\/code> instead of <code>providers.swarm<\/code>, move labels from <code>deploy<\/code> to the service directly, and reference middlewares as <code>@docker<\/code> instead of <code>@swarm<\/code>)<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">version: \"3.8\"\n\nservices:\n  traefik:\n    image: traefik:v3.6\n    command:\n      - \"--api.dashboard=true\"\n      - \"--api.insecure=true\"\n      - \"--providers.swarm.endpoint=unix:\/\/\/var\/run\/docker.sock\"\n      - \"--providers.swarm.exposedByDefault=false\"\n      - \"--providers.swarm.network=shared_proxy\"\n      - \"--providers.file.filename=\/etc\/traefik\/dynamic.yml\"\n      - \"--entrypoints.web.address=:80\"\n      - \"--entrypoints.web.http.redirections.entryPoint.to=websecure\"\n      - \"--entrypoints.web.http.redirections.entryPoint.scheme=https\"\n      - \"--entrypoints.websecure.address=:443\"\n      - \"--log.level=INFO\"\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n      - \"8080:8080\"\n    volumes:\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock:ro\n    configs:\n      - source: traefik_dynamic\n        target: \/etc\/traefik\/dynamic.yml\n      - source: tls_cert\n        target: \/certs\/cert.pem\n      - source: tls_key\n        target: \/certs\/key.pem\n    networks:\n      - proxy\n    deploy:\n      placement:\n        constraints:\n          - node.role == manager\n\nconfigs:\n  traefik_dynamic:\n    file: .\/dynamic.yml\n  tls_cert:\n    file: .\/certs\/cert.pem\n  tls_key:\n    file: .\/certs\/key.pem\n\nnetworks:\n  proxy:\n    external: true\n    name: shared_proxy\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">OpenLDAP demo<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">version: \"3.8\"\n\nservices:\n  openldap:\n    image: osixia\/openldap:1.5.0\n    environment:\n      LDAP_ORGANISATION: \"Demo Corp\"\n      LDAP_DOMAIN: \"demo.local\"\n      LDAP_BASE_DN: \"dc=demo,dc=local\"\n      LDAP_ADMIN_PASSWORD: \"admin_password\"\n      LDAP_READONLY_USER: \"true\"\n      LDAP_READONLY_USER_USERNAME: \"readonly\"\n      LDAP_READONLY_USER_PASSWORD: \"readonly_password\"\n    volumes:\n      - ldap_data:\/var\/lib\/ldap\n      - ldap_config:\/etc\/ldap\/slapd.d\n    networks:\n      default:\n        aliases:\n          - ldap\n    deploy:\n      replicas: 1\n\n  ldap-seed:\n    image: osixia\/openldap:1.5.0\n    entrypoint: \/bin\/bash\n    command:\n      - -c\n      - |\n        for i in $$(seq 1 30); do\n          ldapsearch -x -H ldap:\/\/openldap -D \"cn=admin,dc=demo,dc=local\" -w admin_password -b \"dc=demo,dc=local\" > \/dev\/null 2>&amp;1 &amp;&amp; break\n          echo \"Waiting for LDAP... ($$i\/30)\"\n          sleep 2\n        done\n\n        ldapsearch -x -H ldap:\/\/openldap -D \"cn=admin,dc=demo,dc=local\" -w admin_password -b \"ou=users,dc=demo,dc=local\" > \/dev\/null 2>&amp;1\n        if [ $$? -eq 0 ]; then\n          echo \"LDAP already seeded, skipping.\"\n          exit 0\n        fi\n\n        echo \"Seeding LDAP with demo accounts...\"\n\n        ldapadd -x -H ldap:\/\/openldap -D \"cn=admin,dc=demo,dc=local\" -w admin_password &lt;&lt;'LDIF'\n        dn: ou=users,dc=demo,dc=local\n        objectClass: organizationalUnit\n        ou: users\n\n        dn: ou=groups,dc=demo,dc=local\n        objectClass: organizationalUnit\n        ou: groups\n\n        dn: uid=alice,ou=users,dc=demo,dc=local\n        objectClass: inetOrgPerson\n        objectClass: posixAccount\n        objectClass: shadowAccount\n        cn: Alice Johnson\n        sn: Johnson\n        givenName: Alice\n        uid: alice\n        uidNumber: 1001\n        gidNumber: 1001\n        mail: alice@demo.local\n        homeDirectory: \/home\/alice\n        userPassword: alice123\n\n        dn: uid=bob,ou=users,dc=demo,dc=local\n        objectClass: inetOrgPerson\n        objectClass: posixAccount\n        objectClass: shadowAccount\n        cn: Bob Smith\n        sn: Smith\n        givenName: Bob\n        uid: bob\n        uidNumber: 1002\n        gidNumber: 1001\n        mail: bob@demo.local\n        homeDirectory: \/home\/bob\n        userPassword: bob123\n\n        dn: uid=charlie,ou=users,dc=demo,dc=local\n        objectClass: inetOrgPerson\n        objectClass: posixAccount\n        objectClass: shadowAccount\n        cn: Charlie Brown\n        sn: Brown\n        givenName: Charlie\n        uid: charlie\n        uidNumber: 1003\n        gidNumber: 1001\n        mail: charlie@demo.local\n        homeDirectory: \/home\/charlie\n        userPassword: charlie123\n\n        dn: cn=developers,ou=groups,dc=demo,dc=local\n        objectClass: groupOfNames\n        cn: developers\n        member: uid=alice,ou=users,dc=demo,dc=local\n        member: uid=bob,ou=users,dc=demo,dc=local\n\n        dn: cn=admins,ou=groups,dc=demo,dc=local\n        objectClass: groupOfNames\n        cn: admins\n        member: uid=alice,ou=users,dc=demo,dc=local\n        LDIF\n\n        echo \"LDAP seeding complete.\"\n    deploy:\n      restart_policy:\n        condition: on-failure\n        max_attempts: 5\n\nvolumes:\n  ldap_data:\n  ldap_config:\n\nnetworks:\n  default:\n    external: true\n    name: shared_backend\n<\/pre>\n\n","protected":false},"excerpt":{"rendered":"<p>A collection of notes and fixes from setting up authentik as an identity provider with Active Directory LDAP sync, Traefik forward auth, and Docker Swarm. The two main gotchas: AD syncs computer objects as users [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2042,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[63,48,26,58],"tags":[],"class_list":["post-1863","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-authentication","category-security","category-it","category-miscellaneous"],"_links":{"self":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts\/1863","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/comments?post=1863"}],"version-history":[{"count":6,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts\/1863\/revisions"}],"predecessor-version":[{"id":2089,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts\/1863\/revisions\/2089"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/media\/2042"}],"wp:attachment":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/media?parent=1863"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/categories?post=1863"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/tags?post=1863"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}