点击展开更新日志

2026

title

xxxxx

nexttime

会有些什么呢(❁´◡`❁)

源起

起因是部署的应用太多,逐个记密码太麻烦,上个月某次登录“微软积分”的时候弹了个Passkey认证(b玩意还跳不过去,安卓客户端还不支持,直接整红温了,好不容易才跳过去),后面了解之后发觉配置好了很方便,在iPhone上的客户端能直接添加,体验非常好,登录于是想着能不能用 passkey 的方式简化其他应用的登录流程,于是兜兜转转,发现很多应用并不支持 passkey,但是可以支持 SSO,然后经过 Deepseek 解答,可以部署一套支持 passkey 的 SSO 系统做统一认证。

本来最初的主角应该是 authekia ,但被 Authentik 后来居上了(别急,都有),所以折腾了几天,基本跑通了几个(immich、Portainer),后面其他应用再接进来自然也就是水到渠成的事了。

介绍

官网:Welcome | authentik

Authentik:是一个IdP(Identity Provider,身份提供者)和SSO(Single Sign On,单点登录)平台,支持 OAuth2,SAML,LDAP等协议集成,主要是解决多个独立系统各自一套帐密维护繁琐的问题。提供开源社区版和企业版。

官网文档提供了详细的部署及支持文档,有疑问可以先查询文档,或者问AI。

环境要求

官方文档:https://docs.goauthentik.io/

官方提供了 Docker 部署方式,本文使用且推荐个人用户使用这种方式,规格要求:

  • Docker Compose v2
  • 主机不低于2CPU 2G内存(我这里还是用的之前的软路由做,专门分了4CPU16G跑Docker)

image-20260128230813535

需要注意的是,部署之前,我的环境中已经有一套独立的 PostgreSQL 数据库和 traefik 做代理,因此对原 docker-compose.yml 做了较大更改,仅供参考,以实际本地环境为准。如果拿不准,可以直接用官方的 yml 文件,重新起一套容器。

本地环境介绍

  • 几乎所有服务基于Docker Compose部署
  • 统一使用 traefik V3 作为代理入口,强制 https,内部使用 http(这里强调一句,容器内部不建议也搞https,容易出问题,要么http,要么统一https走traefik入口进去,如果实在要,那就祝一切顺利)
  • 域名
  • 使用 socket-proxy 做权限限制,不介意可以就直接挂载 /var/run/docker.sock ,取消注释即可。如果要使用,请参照本文末尾辅助容器部分。

部署

最终使用域名:

  • authentik:auth.domain.top
  1. 下载 docker-compose.yml :

    1
    wget https://docs.goauthentik.io/docker-compose.yml
  2. 创建 .env 环境变量:

    1
    2
    3
    4
    5
    # echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
    echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
    # 关闭错误报告
    echo "AUTHENTIK_ERROR_REPORTING__ENABLED=false" >> .env

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    # Settings
    # Cookie 签名密钥
    AUTHENTIK_SECRET_KEY=abcd
    # 关闭错误报错,启用会发送给 https://sentry.io做分析
    AUTHENTIK_ERROR_REPORTING__ENABLED=false
    # 启用后会发送错误报告给开发者
    AUTHENTIK_ERROR_REPORTING__SEND_PII=false
    # 禁止发送个人数据
    AUTHENTIK_ERROR_REPORTING__SEND_PII=false
    # 日志级别,支持 debug trace info warning error
    AUTHENTIK_LOG_LEVEL=info
    # Cookie 域
    AUTHENTIK_COOKIE_DOMAIN=auth.domain.top


    # PostgreSQL 数据库配置
    # 数据库地址
    AUTHENTIK_POSTGRESQL__HOST=192.168.7.22
    # 数据库端口,默认 5432
    AUTHENTIK_POSTGRESQL__PORT=5432
    # 数据库用户
    AUTHENTIK_POSTGRESQL__USER=authentik
    # 数据库密码
    AUTHENTIK_POSTGRESQL__PASSWORD=Authentik
    # 数据库名
    AUTHENTIK_POSTGRESQL__NAME=authentik
    # 禁用 SSL,默认是 verify-ca
    AUTHENTIK_POSTGRESQL__SSLMODE=disable


    # 数据库连接管理
    # 数据库连接保持时间,默认为0:每次请求后关闭连接
    AUTHENTIK_POSTGRESQL__CONN_MAX_AGE=0
    # 复用前对持久性连接做健康检查,防止数据库连接超时报错。因为上面设置为0,实际这行无效。
    AUTHENTIK_POSTGRESQL__CONN_HEALTH_CHECKS=false
    # 禁用服务器端游标,默认为 false
    AUTHENTIK_POSTGRESQL__DISABLE_SERVER_SIDE_CURSORS=false

    # Cache 缓存设置
    # 缓存超时时间,默认300s
    AUTHENTIK_CACHE__TIMEOUT=300
    # 没看懂啥意思 timeout for cached flow plans
    AUTHENTIK_CACHE__TIMEOUT_FLOWS=300
    # 缓存策略超时时间,默认300s
    AUTHENTIK_CACHE__TIMEOUT_POLICIES=300

    # Worker 工作进程设置
    # 工作进程数,默认为1
    AUTHENTIK_WORKER__PROCESSES=1
    # 每个工作进程线程数,默认2
    AUTHENTIK_WORKER__THREADS=2
    AUTHENTIK_WORKER__CONSUMER_LISTEN_TIMEOUT="seconds=30"
    # 任务失败重试次数
    AUTHENTIK_WORKER__TASK_MAX_RETRIES=3
    AUTHENTIK_WORKER__TASK_DEFAULT_TIME_LIMIT="minutes=10" # min
    AUTHENTIK_WORKER__TASK_PURGE_INTERVAL="days=1" # 1d
    AUTHENTIK_WORKER__TASK_EXPIRATION="days=30" # 30d
    AUTHENTIK_WORKER__SCHEDULER_INTERVAL="seconds=60" # 60s


    # Listening 监听配置
    # 容器HTTP监听地址
    AUTHENTIK_LISTEN__HTTP=0.0.0.0:9000
    # 容器暴露端口,我这里是因为和portainer冲突了
    COMPOSE_PORT_HTTPS=19443
    # 容器HTTPS监听地址
    AUTHENTIK_LISTEN__HTTPS=0.0.0.0:9443
    AUTHENTIK_LISTEN__LDAP=0.0.0.0:23389
    AUTHENTIK_LISTEN__LDAPS=0.0.0.0:26636
    AUTHENTIK_LISTEN__METRICS=0.0.0.0:9300
    AUTHENTIK_LISTEN__DEBUG=0.0.0.1:9900
    AUTHENTIK_LISTEN__DEBUG_PY=0.0.0.0:9901
    # 可信代理地址,默认,局域网地址
    AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS=127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fe80::/10, ::1/128


    # Storage 存储设置,默认值
    # 文件存储位置,支持 文件存储:file s3存储:3
    AUTHENTIK_STORAGE__BACKEND=file # file/s3
    AUTHENTIK_STORAGE__FILE__PATH=/data
    AUTHENTIK_STORAGE__FILE__URL_EXPIRY=10 # min

    # Email 邮箱设置
    # 邮件服务器地址,这里是阿里云企业邮箱,买域名送的
    AUTHENTIK_EMAIL__HOST=smtp.qiye.aliyun.com
    # SMTP 端口,SSL加密端口
    AUTHENTIK_EMAIL__PORT=465
    [email protected]
    AUTHENTIK_EMAIL__PASSWORD=abcd
    AUTHENTIK_EMAIL__USE_TLS=true
    AUTHENTIK_EMAIL__USE_SSL=true
    AUTHENTIK_EMAIL__TIMEOUT=10
    [email protected]

    提醒:阿里云企业邮箱会检查登录邮箱(USERNAME)和发信邮箱(FROM)是否一致,不一致会拒绝发信,包括大小写不一致,知悉。

  3. 下载 docker-compose.yml 并修改:

    🍁:这里做的修改:

    • 删除了 postgresql 容器部分

    • 删除了 server 和 worker 中 depends 数据库的部分

    • 修改了 server 和 worker 容器默认名称,加了 authentik- 前缀

    • 修改了 server 容器 environment 变量,使用 .env 中定义的值

    • 注释了端口,统一使用 traefik

    • 新增 traefik labels

    • 新增 authentik_net 独立网络

    需要强调,注释了的部分不要开,建议直接删,这里留着只是为了给自己做提醒:

    • https 统一交给 traefik 做,内部转发不要开,不然 https://ip:9443 的自签名证书traefik不认,单独做配置很麻烦,也不建议做,反而搞复杂了
    • 不要开白名单,除非只是在内网使用可以加,有ddns外网访问需求就不建议加了
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    services:
    authentik-server:
    container_name: Authentik-server
    command: server
    env_file:
    - .env
    environment:
    AUTHENTIK_POSTGRESQL__HOST: ${AUTHENTIK_POSTGRESQL__HOST}
    AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRESQL__NAME:-authentik}
    AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD}
    AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRESQL__USER:-authentik}
    AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.12.1}
    # ports:
    # - ${AUTHENTIK_LISTEN__HTTP:-9000}:9000
    # - ${COMPOSE_PORT__HTTPS:-9443}:9443
    restart: unless-stopped
    volumes:
    - ./data:/data
    - ./custom-templates:/templates
    labels:
    # Traefik 路由配置
    - "traefik.enable=true"

    # HTTPS 主路由
    - "traefik.http.routers.authentik-https.rule=Host(`auth.evergard.top`)"
    - "traefik.http.routers.authentik-https.entrypoints=websecure"
    - "traefik.http.routers.authentik-https.tls=true"
    - "traefik.http.routers.authentik-https.service=authentik-server"

    # 服务配置
    - "traefik.http.services.authentik-server.loadbalancer.server.port=9000"
    - "traefik.http.services.authentik-server.loadbalancer.server.scheme=http"

    # 中间件配置
    - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
    - "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true"

    # 安全头部
    - "traefik.http.middlewares.security-headers.headers.browserxssfilter=true"
    - "traefik.http.middlewares.security-headers.headers.contenttypenosniff=true"
    - "traefik.http.middlewares.security-headers.headers.framedeny=true"
    - "traefik.http.middlewares.security-headers.headers.sslredirect=true"
    - "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-Robots-Tag=none"

    # 添加安全中间件到路由
    - "traefik.http.routers.authentik-https.middlewares=security-headers"

    # 如果需要 IP 白名单
    # - "traefik.http.middlewares.ip-whitelist.ipwhitelist.sourcerange=192.168.1.0/24"
    # - "traefik.http.routers.authentik-https.middlewares=security-headers,ip-whitelist"
    networks:
    - authentik_net
    authentik-worker:
    container_name: Authentik-worker
    command: worker
    env_file:
    - .env
    environment:
    AUTHENTIK_POSTGRESQL__HOST: ${AUTHENTIK_POSTGRESQL__HOST}
    AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRESQL__NAME:-authentik}
    AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD}
    AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRESQL__USER:-authentik}
    AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    DOCKER_HOST: http://socket-proxy:2375
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.12.1}
    restart: unless-stopped
    user: root
    volumes:
    # - /var/run/docker.sock:/var/run/docker.sock
    - ./data:/data
    - ./certs:/certs
    - ./custom-templates:/templates
    networks:
    - authentik_net
    networks:
    authentik_net:
    name: authentik_net
  4. 创建数据库
    使用 pgAdmin 连接到 PostgreSQL 数据库,创建用户:

    1
    create user 'authentik' with password 'Authentik';

    然后在界面中创建同名数据库并赋权给 authentik 用户。

  5. 检查配置:

    1
    docker compose run --rm worker ak dump_config

    检查配置是否合法,是否存在配置错误。

  6. 启动服务

    1
    docker compose up -d
  7. 初始化设置
    初始化管理地址:http://<your server's IP or hostname>:9000/if/flow/initial-setup/

    末尾有个斜杠,没有会报错 404!

系统配置

第一次初始化配置之后设置好管理员邮箱和密码就可以进入系统了,后续就可以直接使用域名访问,默认是用户界面 User interface,右上角切换到管理员界面 Admin interface

设置中文就不必提了吧~

开启Webauthn

这才是我搭建 Authentik 最主要的目的。右上角进入【设置】-【MFA设备】-【注册】,选择 WebAuthn device ,注册即可。

开启 TOTP

保险起见,一切支持TOTP的应用都建议开启,如果只是内网使用就看需要了,我的情况是部分应用需要暴露到公网,因此习惯给各个系统都开。

应用接入

关于接入OIDC,可以参考官方文档的例子 ,这里以我的几个应用进行说明。

Portainer

新建应用

进入管理员界面,选择【应用程序】菜单,进入页面选择【以提供程序创建】同时创建应用和Provider:

  1. 【应用程序】:输入应用名,如 Portainer,slug 会自动填充;
  2. 【选择提供程序】:选择 OAuth2/OpenID Provider
  3. 【配置提供程序】:
    1. 【提供程序名】:可以保持默认
    2. 【授权流程】:建议选择 explict 显式授权,登录成功会要求确认授权,显示需要授权的信息,比如用户名、邮箱等;implict 隐式授权登录成功后自动授权。
    3. 【协议类型】:默认选择机密,这里的客户端ID客户端Secret复制记一下,添加客户端会使用到
    4. 重定向URL:设置严格重定向URL地址为: https://portainer.company/,末尾有斜杠
  4. 【配置绑定】:绑定到已有用户/组。我这里因为只有一个用户因此就没有建组了,直接添加用户;
  5. 检查提交:如果没有绑定用户组可能提交报错,强烈建议报错了看日志,看不懂就复制全问AI就行。

授权信息

从左侧导航栏进入【应用程序-提供程序】页面,选择刚才创建的提供程序 Provider for Portainer 进入,可以看到各个配置地址:配置URL、授权URL、令牌URL等。每个客户端的要求不一样,不一定每个都会使用,建议能配置的都配上。

Portainer 接入配置

可以参考官方文档:Integrate with Portainer | authentik

以下例子中:

  • Portainer FQDN(Fully Qualified Domain Name,就是完整域名)为 portainer.company
  • Authentik FQDN 为 authentik,company
  1. 管理员登录Portainer,进入【Settings-Authentication】;
  2. 配置项:
    1. 【Authentication method】:OAuth
    2. 【Provider】:Custom 自定义
    3. 【Oauth Configuration】:
      1. 【Client ID】:创建应用的客户端ID
      2. 【Client Secret】:创建应用的密钥
      3. 【Authorization URL】:授权URL,https://authentik.company/application/o/authorize/
      4. 【Access Token URL】:访问令牌URL,https://authentik.company/application/o/token/
      5. 【Resource URL】:用户信息URL,https://authentik.company/application/o/userinfo/
      6. 【Redirect URL】:重定向URL,默认自动填充,https://portainer.company/
      7. 【Logout URL】:登出/注销URL,https://authentik.company/application/o/portainer/end-session/
      8. 【User Identifier】:用户标识,使用 preferred_username,也可以试一下 email,我用email会有问题
      9. 【Scopes】:范围,固定 email openid profile
  3. 保存。

如果一切正常,保存成功后就可以开始验证了。

测试验证

打开无痕模式,打开portainer,可以看到页面登录选项会存在 Login with OAuth,点击之后会跳转 Authentik 做登录认证,如果顺利自然就会登录成功,这里说两个我遇到的问题避坑。

Q:点击 Login wth OAuth 跳转之后返回json数据,没有到认证页面

A:大概率是上面Portainer配置中 【User Identifier】配置有问题,找不到对应用户表示,比如我开始写成了 username

Q:点击跳转之后到了 Authentik,但是显示 Not Found

A:这大概是因为Portainer找不到 Authentik ,域名无法解析。解决方案是在创建 Portainer 容器时指定 extra_hosts 或指定DNS(我本地是用的AdGuard Home做统一DNS的)。

Grafana

辅助容器

socket-proxy

官方文档:socket-proxy - LinuxServer.io

Socket Proxy 是一个安全增强的代理,限制容器对 Docker socket 的使用权限,避免滥用及攻击。

以本项目实际使用为例:

  1. 创建 docker-compose.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    ---
    services:
    socket-proxy:
    image: lscr.io/linuxserver/socket-proxy:latest
    container_name: socket-proxy
    environment:
    - ALLOW_START=0 #optional
    - ALLOW_STOP=0 #optional
    - ALLOW_RESTARTS=0 #optional
    - AUTH=0 #optional
    - BUILD=0 #optional
    - COMMIT=0 #optional
    - CONFIGS=0 #optional
    - CONTAINERS=1 #optional
    - DISABLE_IPV6=0 #optional
    - DISTRIBUTION=0 #optional
    - EVENTS=1 #optional
    - EXEC=0 #optional
    - IMAGES=1 #optional
    - INFO=0 #optional
    - LOG_LEVEL=info #optional
    - NETWORKS=1 #optional
    - NODES=0 #optional
    - PING=1 #optional
    - PLUGINS=0 #optional
    - POST=0 #optional
    - SECRETS=0 #optional
    - SERVICES=0 #optional
    - SESSION=0 #optional
    - SWARM=0 #optional
    - SYSTEM=1 #optional
    - TASKS=0 #optional
    - TZ=Asia/Shanghai #optional
    - VERSION=1 #optional
    - VOLUMES=0 #optional
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped
    read_only: true
    tmpfs:
    - /run
    networks:
    - socket-proxy-net
    networks:
    socket-proxy-net:
    name: socket-proxy-net
    internal: true

    与官方配置差异:

    • 根据实际需要启用了部分权限
    • 更改时区为 Asia/Shanghai
    • 新增专用网络
  2. 使用方式

    将容器添加入 socket-proxy-net ,一般可以作为环境变量使用:

    1
    2
    environment:
    DOCKER_HOST: "tcp://socket-proxy:2375"

    authentik 需要作为 http使用,参考: Docker |真实性 — Docker | authentik

    1
    DOCKER_HOST: http://socket-proxy:2375