tinyauth v5.2.0 Docker Compose 部署指南
用 Docker Compose 单机部署 tinyauth v5.2.0 认证网关并完成 Traefik/Nginx/Caddy 三类反代 forward auth 集成,401→登录→200+Remote-User 全链路实测通过。
tinyauth v5.2.0 Docker Compose 部署指南
目标:用 Docker Compose 在单台 Ubuntu 22.04 服务器上部署 tinyauth v5.2.0 统一认证网关,并完成 Traefik、Nginx、Caddy 三类反向代理的 forward auth 集成,实现「未登录访问 → 302/401 跳登录页 → 登录后携带
Remote-User等身份头回到应用」的完整认证链路。本文全部命令与回显已在 Docker Engine 29.8.1(Compose v5.5.1)环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.4 LTS(x86_64)
- Docker Engine:29.8.1,Docker Compose 插件 v5.5.1
- tinyauth 版本:v5.2.0(2026-09-07 发布,官方镜像
ghcr.io/tinyauthapp/tinyauth) - 反向代理镜像:
traefik:v3.5、nginx:1.29-alpine、caddy:2.10-alpine - 受保护示例应用:
traefik/whoami:v1.10.4 - 端口规划:tinyauth 服务宿主端口
8131(服务端口 3000);三套反代宿主端口8135(Traefik)、8147(Caddy)、8149(Nginx)。生产环境建议反代直接监听 80/443,本文端口取值仅为与实测环境保持一致,可按需替换 - 域名规划:
auth.example.com(tinyauth 登录入口)、whoami.example.com(受保护应用示例)。两个均为子域.主域.顶级域三段式域名,这是 tinyauth 会话 Cookie 的硬性要求(见第十二章常见问题) - 编排目录:
/opt/tinyauth/(示例路径,含docker-compose.yml与三个反代配置子目录) - 独立网络:
tinyauth-net(bridge,网段10.89.57.0/24)
二、镜像选型说明
tinyauth 官方只发布单一官方镜像,不提供多变体,选型要点集中在仓库地址与标签策略两点:
| 项目 | 取值 | 说明 |
|---|---|---|
| 官方镜像仓库 | ghcr.io/tinyauthapp/tinyauth | GitHub Container Registry;项目仓库已由 steveiliop56/tinyauth 迁移为 tinyauthapp/tinyauth,旧路径镜像仍可拉取但新路径为官方现行地址 |
| 精确版本标签 | v5.2.0 | 与 GitHub Release 一一对应,生产推荐,升级可控 |
| 浮动主版本标签 | v5 | 跟随 v5.x 最新补丁,docker compose pull 即升级小版本 |
| 滚动预发布标签 | nightly | 滚动构建,含未发布改动,仅测试用 |
💡 说明:本文全部使用
v5.2.0精确标签,保证文中回显可复现。镜像内以非 root 用户tinyauth运行,数据目录为/data,服务监听0.0.0.0:3000。
由于 tinyauth 本身只负责认证,必须搭配反向代理使用才能保护后端应用。三类主流反代的集成方式对比(本文三类全部实测,配置见第十章):
💡 技术拓展:反向代理接入 tinyauth 的三种主流方式——
反向代理 接入机制 配置位置 特点 Traefik forwardAuth中间件动态配置文件或标签 原生 forwardAuth,tinyauth 官方默认集成对象;声明式配置 Nginx auth_request子请求server/location 配置 需要手动拼装 auth_request+error_page+ 头透传三件套,步骤最多但最通用Caddy forward_auth指令Caddyfile 语法最简,一行指令完成认证与头复制 三者最终都调用 tinyauth 暴露的对应端点:
/api/auth/traefik、/api/auth/nginx、/api/auth/caddy(Nginx 端点为 v5.2.0 新增)。本文三类反代均实测部署并逐条验证,生产按既有技术栈选择即可。
三、前置条件
- 服务器已安装 Docker Engine 与 Compose 插件,验证:
docker version --format 'Engine {{.Server.Version}}'
实测输出:
Engine 29.8.1
docker compose version
实测输出:
Docker Compose version v5.5.1
- 域名解析就绪:
auth.example.com与whoami.example.com需能解析到服务器 IP。生产环境配置 DNS A 记录;本地验证环境可在执行验证命令的服务器/etc/hosts中加入:
127.0.0.1 auth.example.com whoami.example.com
⚠️ tinyauth 的会话 Cookie 写在主域(
example.com)上,三套反代下的受保护应用才能共享登录态。因此两个域名必须是同一主域下的子域,且TINYAUTH_APPURL必须是子域.主域.顶级域三段式格式。裸域(如example.com本身)或两段式域名(如auth.localtest)会导致受保护应用侧无法携带 Cookie,实测会直接拒绝访问(见第十二章常见问题 3)。
- 管理员账号的 bcrypt 哈希:不需要手工计算,tinyauth 自带
user create命令生成(见第四章 4.1)。
四、部署步骤
本章按「创建网络 → 生成管理员账号 → 编写编排文件 → 启动 → 验证」的顺序完成 0→1 部署。预期结果:tinyauth 服务健康运行,登录页可访问,管理员可登录。
4.1 创建独立网络
为整套认证栈创建独立 bridge 网络并显式指定网段,避免与其他业务网段冲突:
docker network create -d bridge --subnet 10.89.57.0/24 tinyauth-net
实测输出:
01d9b1f9a3c4be0dcf7691ab0e39f0e2f83b0c1b8b8e0f6f9a1b2c3d4e5f6a7b8
💡 说明:显式
--subnet便于在TINYAUTH_AUTH_TRUSTEDPROXIES中精确填写反代网段(见第十二章常见问题 5)。若网段与现有网络冲突,换一个空闲/24即可,同时同步修改编排文件与可信代理配置。
4.2 生成管理员账号
用 user create 命令生成 username:bcrypt_hash 格式的账号串。本文演示账号为 admin,密码 q1w2e3r4:
docker run -i -t --rm ghcr.io/tinyauthapp/tinyauth:v5.2.0 \
user create --username admin --password q1w2e3r4 --docker
实测输出:
Created user 'admin'.
Environment variable:
TINYAUTH_AUTH_USERS=admin:$$2a$$10$$znGmVq.l0UmU91D7g5irQOwBY.HohGn8vNEahjCEgwnh/NzMWmWuC
CLI flags:
--auth.users=admin:$2a$10$znGmVq.l0UmU91D7g5irQOwBY.HohGn8vNEahjCEgwnh/NzMWmWuC
YAML config:
auth:
users:
- admin:$2a$10$znGmVq.l0UmU91D7g5irQOwBY.HohGn8vNEahjCEgwnh/NzMWmWuC
Use your config option of choice to add the user to Tinyauth and then restart.
💡 说明:
--docker参数让输出的环境变量值把 bcrypt 哈希中的$转义成$$——这是 Compose 环境变量专属的转义规则;CLI flags与YAML config两种形态保持单$。按所用配置方式选取对应段落,不要混用。- bcrypt 每次生成使用随机盐,同一密码多次执行的哈希值不同且都有效,以自己实际执行结果为准。
- 该命令只在本地计算哈希,不启动服务、不落库,输出的串需要填进编排文件后随服务生效。
4.3 编写编排文件
创建部署目录 /opt/tinyauth/,写入 docker-compose.yml。本文一套编排同时拉起 tinyauth、受保护示例应用 whoami 与三套反代,便于逐套验证:
mkdir -p /opt/tinyauth/{traefik,nginx/inc,caddy}
/opt/tinyauth/docker-compose.yml 完整内容:
name: tinyauth-v520-stack
networks:
tinyauth-net:
external: true
volumes:
tinyauth-data:
services:
tinyauth:
image: ghcr.io/tinyauthapp/tinyauth:v5.2.0
container_name: tinyauth-v5.2.0-app
restart: unless-stopped
ports:
- "8131:3000"
environment:
- TINYAUTH_APPURL=http://auth.example.com
- TINYAUTH_AUTH_USERS=admin:$$2a$$10$$Edf9Rb8EMGOjyXIf1.yLCur3593A9DlmuZyi5tTeT0./1dmWv62UK
- TINYAUTH_AUTH_TRUSTEDPROXIES=10.89.57.0/24
volumes:
- tinyauth-data:/data
networks:
- tinyauth-net
whoami:
image: traefik/whoami:v1.10.4
container_name: tinyauth-v5.2.0-whoami
restart: unless-stopped
networks:
- tinyauth-net
traefik:
image: traefik:v3.5
container_name: tinyauth-v5.2.0-traefik
restart: unless-stopped
ports:
- "8135:80"
volumes:
- ./traefik:/etc/traefik/dynamic:ro
command:
- --providers.file.directory=/etc/traefik/dynamic
- --entrypoints.web.address=:80
networks:
- tinyauth-net
nginx:
image: nginx:1.29-alpine
container_name: tinyauth-v5.2.0-nginx
restart: unless-stopped
ports:
- "8149:80"
volumes:
- ./nginx:/etc/nginx/conf.d:ro
- ./nginx/inc:/etc/nginx/inc:ro
networks:
- tinyauth-net
caddy:
image: caddy:2.10-alpine
container_name: tinyauth-v5.2.0-caddy
restart: unless-stopped
ports:
- "8147:80"
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
networks:
- tinyauth-net
逐项说明关键配置:
| 配置项 | 取值与作用 |
|---|---|
name: tinyauth-v520-stack | Compose 项目名。多套编排共存时显式命名,避免 docker compose down 误删同名项目的其他资源;数据卷也会带上该前缀(见第五章) |
networks.tinyauth-net.external: true | 复用 4.1 手工创建的网络,不随 down 删除 |
TINYAUTH_APPURL | 对外登录入口 URL,用于生成登录跳转地址与会话 Cookie 域。必须三段式域名,且与实际访问协议一致(HTTPS 部署时写 https://) |
TINYAUTH_AUTH_USERS | 4.2 生成的账号串,$$ 为 Compose 转义形态 |
TINYAUTH_AUTH_TRUSTEDPROXIES | 可信反代网段;tinyauth 据此信任 X-Forwarded-* 头,取值与 4.1 网段一致 |
tinyauth-data:/data | 命名卷持久化数据库、OIDC 密钥等全部状态数据(见第五章) |
| 反代三服务 | 分别挂载各自配置目录,配置内容见第十章 |
4.4 启动与验证
先写入第十章的三个反代配置文件,再启动整套编排:
cd /opt/tinyauth && docker compose up -d
实测输出(首次启动节选):
Network tinyauth-v520-stack_default Creating
Network tinyauth-v520-stack_default Created
Container tinyauth-v5.2.0-traefik Creating
Container tinyauth-v5.2.0-nginx Creating
Container tinyauth-v5.2.0-caddy Creating
Container tinyauth-v5.2.0-whoami Creating
Container tinyauth-v5.2.0-app Creating
Container tinyauth-v5.2.0-app Created
Container tinyauth-v5.2.0-whoami Created
Container tinyauth-v5.2.0-caddy Created
Container tinyauth-v5.2.0-nginx Created
Container tinyauth-v5.2.0-traefik Created
Container tinyauth-v5.2.0-app Starting
Container tinyauth-v5.2.0-whoami Starting
Container tinyauth-v5.2.0-traefik Starting
Container tinyauth-v5.2.0-nginx Starting
Container tinyauth-v5.2.0-caddy Starting
Container tinyauth-v5.2.0-app Started
Container tinyauth-v5.2.0-whoami Started
Container tinyauth-v5.2.0-traefik Started
Container tinyauth-v5.2.0-nginx Started
Container tinyauth-v5.2.0-caddy Started
确认全部服务运行状态(tinyauth 带内置健康检查,约 30 秒内转为 healthy):
docker compose ps
实测输出:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
tinyauth-v5.2.0-app ghcr.io/tinyauthapp/tinyauth:v5.2.0 "/app/tinyauth" tinyauth About a minute ago Up About a minute (healthy) 0.0.0.0:8131->3000/tcp, [::]:8131->3000/tcp
tinyauth-v5.2.0-caddy caddy:2.10-alpine "caddy run --config …" caddy About a minute ago Up About a minute 0.0.0.0:8147->80/tcp, [::]:8147->80/tcp
tinyauth-v5.2.0-nginx nginx:1.29-alpine "/docker-entrypoint.…" nginx About a minute ago Up About a minute 0.0.0.0:8149->80/tcp, [::]:8149->80/tcp
tinyauth-v5.2.0-traefik traefik:v3.5 "entrypoint.sh --pro…" traefik About a minute ago Up About a minute 0.0.0.0:8135->80/tcp, [::]:8135->80/tcp
tinyauth-v5.2.0-whoami traefik/whoami:v1.10.4 "/whoami" whoami About a minute ago Up About a minute 80/tcp
验证 1:登录页直连可访问(HTTP 200 即服务就绪):
curl -sI http://127.0.0.1:8131/ | head -4
实测输出:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: public, max-age=900
Content-Type: text/html; charset=utf-8
验证 2:用 tinyauth healthcheck 命令做应用层健康确认:
docker exec tinyauth-v5.2.0-app tinyauth healthcheck
实测输出:
2026-10-23T21:23:16Z INF Performing health check app_url=http://127.0.0.1:3000 stream=app
2026-10-23T21:23:16Z INF Tinyauth is healthy response={"message":"Healthy","status":200} stream=app
验证 3:确认版本无误:
docker exec tinyauth-v5.2.0-app tinyauth version
实测输出:
Version: v5.2.0
Commit Hash: 653b747829cc72b5ad5232db63b075fb66f81796
Build Timestamp: 2026-09-07T17:15:08
三步验证全部通过,tinyauth 服务本体部署完成。反向代理集成与端到端认证链路验证见第十章。
五、数据持久化说明
tinyauth 把全部状态数据集中在 /data 目录,编排中已用命名卷 tinyauth-data 挂载。查看卷内数据:
docker exec tinyauth-v5.2.0-app ls -la /data/
实测输出:
total 72
drwxr-xr-x 5 tinyauth tinyauth 4096 Oct 23 21:30 .
drwxr-xr-x 1 root root 4096 Oct 23 21:30 ..
drwxr-xr-x 2 tinyauth tinyauth 4096 Sep 7 17:16 oidc
drwxr-xr-x 2 tinyauth tinyauth 4096 Sep 7 17:16 resources
drwxr-xr-x 2 tinyauth tinyauth 4096 Sep 7 17:16 tailscale
-rw-r--r-- 1 root root 53248 Oct 23 21:30 tinyauth.db
| 路径 | 内容 |
|---|---|
tinyauth.db | SQLite 主数据库(默认驱动),存放用户、会话等数据 |
oidc/ | OIDC 提供方功能的 RSA 私钥/公钥(key.pem、key.pub),首次启用 OIDC 时生成 |
resources/ | 资源服务器目录(自定义背景图等 UI 资源) |
tailscale/ | Tailscale 集成缓存数据 |
命名卷在宿主机上的实际名称带 Compose 项目前缀,可确认:
docker volume ls --filter name=tinyauth
实测输出:
DRIVER VOLUME NAME
local tinyauth-v520-stack_tinyauth-data
重启服务后验证持久化效果:账号数据完整保留(重新登录成功),旧会话 Cookie 失效需重新登录:
docker restart tinyauth-v5.2.0-app
实测输出:
tinyauth-v5.2.0-app
重启后用重启前的旧 Cookie 访问受保护应用,返回 401(会话已失效):
HTTP/1.1 401 Unauthorized
Content-Length: 39
Content-Type: application/json; charset=utf-8
X-Tinyauth-Location: http://auth.example.com/login?login_for=app&redirect_uri=http%3A%2F%2Fwhoami.example.com%3A8135%2F
{"message":"Unauthorized","status":401}
重新登录(携带正确账号)返回 200,账号与配置均从数据卷恢复:
HTTP/1.1 200 OK
Content-Length: 43
Content-Type: application/json; charset=utf-8
Set-Cookie: tinyauth-session-26742baf=684cad9b-ed07-48ce-b3c4-37b64cade101; Path=/; Domain=example.com; Expires=Sat, 24 Oct 2026 21:31:04 GMT; Max-Age=86399; HttpOnly; SameSite=Lax
{"message":"Login successful","status":200}
💡 说明:备份即备份该命名卷(或直接备份卷内
tinyauth.db);若改用 PostgreSQL 作为外部数据库(TINYAUTH_DATABASE_DRIVER=postgres),备份对象转为对应数据库(参数说明见第七章)。
六、环境变量表
tinyauth 支持环境变量与 CLI 标志两种等价配置方式,环境变量命名规则为 TINYAUTH_ 前缀 + 分层参数名大写下划线(如标志 --auth.sessionexpiry 对应 TINYAUTH_AUTH_SESSIONEXPIRY)。下表列出部署阶段最常用的一批(全量参数与分组详解见配置参数详解篇):
| 环境变量 | 默认值 | 说明 |
|---|---|---|
TINYAUTH_APPURL | 空 | 对外访问基础 URL。必配;决定登录跳转地址与会话 Cookie 域,须三段式域名 |
TINYAUTH_AUTH_USERS | 空 | 用户列表,逗号分隔的 username:bcrypt_hash[:totp_secret] |
TINYAUTH_AUTH_USERSFILE | 空 | 用户文件路径,替代环境变量内联用户列表 |
TINYAUTH_SERVER_PORT | 3000 | 服务监听端口 |
TINYAUTH_SERVER_ADDRESS | 0.0.0.0 | 服务监听地址 |
TINYAUTH_DATABASE_DRIVER | sqlite | 数据库驱动,可选 sqlite、postgres、memory |
TINYAUTH_DATABASE_PATH | 发行形态 /data/tinyauth.db | SQLite 文件路径;驱动为 postgres 时此值为连接 URL |
TINYAUTH_AUTH_TRUSTEDPROXIES | 空 | 可信反代地址/CIDR 列表,逗号分隔 |
TINYAUTH_AUTH_SESSIONEXPIRY | 86400 | 会话有效期(秒),实测设 120 时 Cookie Max-Age=119 |
TINYAUTH_AUTH_SESSIONMAXLIFETIME | 0 | 会话最长存活时间(秒),0 表示不限 |
TINYAUTH_AUTH_SECURECOOKIE | false | Cookie 仅经 HTTPS 传输;生产 HTTPS 部署应设 true |
TINYAUTH_AUTH_SUBDOMAINSENABLED | true | 子域共享登录态开关 |
TINYAUTH_AUTH_LOGINTIMEOUT | 300 | 登录流程超时(秒) |
TINYAUTH_AUTH_LOGINMAXRETRIES | 3 | 最大登录重试次数 |
TINYAUTH_APPS_<NAME>_CONFIG_DOMAIN | 空 | 应用 ACL:应用 <NAME> 的域名 |
TINYAUTH_APPS_<NAME>_USERS_ALLOW | 空 | 应用 ACL:允许的用户列表(逗号分隔) |
TINYAUTH_APPS_<NAME>_USERS_BLOCK | 空 | 应用 ACL:拒绝的用户列表 |
TINYAUTH_UI_TITLE | Tinyauth | 登录页标题 |
TINYAUTH_CONFIGFILE | 空 | YAML 配置文件路径(见第八章) |
💡 说明:Compose 中写 bcrypt 哈希必须把
$写成$$(Compose 层转义),漏转义是「登录一直失败」的高频原因(见第十二章常见问题 6)。多用户写法(逗号分隔,示例中两段哈希均为实测生成):TINYAUTH_AUTH_USERS=admin:$$2a$$10$$Edf9Rb8EMGOjyXIf1.yLCur3593A9DlmuZyi5tTeT0./1dmWv62UK,user2:$$2a$$10$$znGmVq.l0UmU91D7g5irQOwBY.HohGn8vNEahjCEgwnh/NzMWmWuC。
七、配置参数说明
第四章编排文件中的三个环境变量是「能跑起来」的最小集,逐项展开:
TINYAUTH_APPURL=http://auth.example.com:tinyauth 以此推导会话 Cookie 的作用域(主域example.com)与登录跳转地址。未认证访问受保护应用时,反代收到的跳转地址就来自它(实测跳转X-Tinyauth-Location: http://auth.example.com/login?login_for=app&redirect_uri=http%3A%2F%2Fwhoami.example.com%3A8135%2F)。HTTPS 上线后同步改为https://auth.example.com并开启TINYAUTH_AUTH_SECURECOOKIE=true。TINYAUTH_AUTH_USERS=admin:$$2a$$10$$Edf9Rb8EMGOjyXIf1.yLCur3593A9DlmuZyi5tTeT0./1dmWv62UK:本地账号体系的唯一定义处。账号密码不落 tinyauth 数据库,而是随环境变量注入;修改账号 = 改环境变量 + 重启服务。TINYAUTH_AUTH_TRUSTEDPROXIES=10.89.57.0/24:把三套反代所在网段声明为可信来源,tinyauth 才采信请求里的X-Forwarded-For等头并回写正确的跳转地址。实测配置转储可见其已生效:
docker exec tinyauth-v5.2.0-app tinyauth config | grep -A 1 trustedProxies
实测输出(ANSI 着色符已剥离):
trustedProxies:
- 10.89.57.0/24
进一步需要关注的分档:最小可用(上表三个变量);生产 HTTPS(追加 SECURECOOKIE=true、反代侧启用 TLS);按应用管控(追加 TINYAUTH_APPS_<NAME>_* 系列,实现「登录了也不能访问指定应用」的应用级 ACL,实测验证见第十二章常见问题 7)。完整参数矩阵、取值细节与生产配置模板见参数详解篇《tinyauth v5.2.0 配置参数详解》。
八、配置文件挂载
除环境变量外,tinyauth 支持从 YAML 配置文件读取全部参数,适合参数多、需要纳入配置管理的场景。用法两步:
- 编写配置文件
/opt/tinyauth/config.yaml(键名为驼峰式分层结构,与tinyauth config命令转储出的格式一致):
appUrl: http://auth.example.com
server:
port: 3000
address: 0.0.0.0
auth:
users:
- admin:$2a$10$Edf9Rb8EMGOjyXIf1.yLCur3593A9DlmuZyi5tTeT0./1dmWv62UK
trustedProxies:
- 10.89.57.0/24
sessionExpiry: 86400
database:
driver: sqlite
path: /data/tinyauth.db
⚠️ YAML 文件形态下 bcrypt 哈希保持单
$,不做$$转义(转义仅适用于 Compose 环境变量)。
- 挂载并在编排中指定路径:
services:
tinyauth:
environment:
- TINYAUTH_CONFIGFILE=/data/config.yaml
volumes:
- ./config.yaml:/data/config.yaml:ro
- tinyauth-data:/data
修改配置文件后重启服务生效:
docker compose restart tinyauth
实测输出:
[+] Restarting 1/1
✔ Container tinyauth-v5.2.0-app Started
💡 说明:三种配置途径(环境变量 / CLI 标志 / YAML 文件)内容完全等价,
tinyauth config命令会把当前生效的合并结果以 YAML 转储出来,是排查「配置到底生效没有」的第一工具。建议同一参数只走一种途径,避免多来源歧义。
九、等价 docker run
不用 Compose 时,以下单条 docker run 与第四章中 tinyauth 服务的编排等价(网络与数据卷复用同一套):
docker run -d --name tinyauth-app --network tinyauth-net -p 8131:3000 \
-e TINYAUTH_APPURL=http://auth.example.com \
-e 'TINYAUTH_AUTH_USERS=admin:$2a$10$Edf9Rb8EMGOjyXIf1.yLCur3593A9DlmuZyi5tTeT0./1dmWv62UK' \
-v tinyauth-data:/data \
ghcr.io/tinyauthapp/tinyauth:v5.2.0
⚠️
docker run直跑时-e传参不做 Compose 的$$转义,bcrypt 哈希保持单$(与 Compose 相反),并建议像上例一样给变量值加单引号,防止 shell 把$2a展开成位置参数。
该形态已在同环境实测:实例正常启动并转为健康状态,登录页返回 200,tinyauth version 回显 Version: v5.2.0,与 Compose 形态行为一致。
十、三类反向代理集成实测
本章把 Traefik、Nginx、Caddy 三套反代逐一接到 tinyauth 上,保护同一个 whoami 应用,并对每套完成「未认证 → 登录 → 已认证」全链路实测。三套配置目录已挂载进对应反代(见第四章编排文件)。
10.1 Traefik 集成(forwardAuth 中间件)
/opt/tinyauth/traefik/dynamic.yml:
http:
routers:
tinyauth:
rule: "Host(`auth.example.com`)"
service: tinyauth-svc
entryPoints:
- web
whoami:
rule: "Host(`whoami.example.com`)"
service: whoami-svc
entryPoints:
- web
middlewares:
- tinyauth-fw
middlewares:
tinyauth-fw:
forwardAuth:
address: "http://tinyauth:3000/api/auth/traefik"
authResponseHeaders:
- Remote-User
- Remote-Name
- Remote-Email
- Remote-Groups
services:
tinyauth-svc:
loadBalancer:
servers:
- url: "http://tinyauth:3000"
whoami-svc:
loadBalancer:
servers:
- url: "http://whoami:80"
配置要点:tinyauth 路由把登录入口反代到 tinyauth;whoami 路由挂 tinyauth-fw 中间件,forwardAuth.address 指向 tinyauth 的 Traefik 专用端点 /api/auth/traefik;authResponseHeaders 声明认证成功后要从 tinyauth 响应复制给后端应用的四个身份头。
10.2 Nginx 集成(auth_request 子请求)
/opt/tinyauth/nginx/default.conf:
server {
listen 80;
server_name auth.example.com;
location / {
proxy_pass http://tinyauth:3000;
proxy_set_header Host $host;
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
proxy_set_header x-real-ip $remote_addr;
}
}
server {
listen 80;
server_name whoami.example.com;
include /etc/nginx/inc/tinyauth-server.conf;
location / {
include /etc/nginx/inc/tinyauth-location.conf;
proxy_pass http://whoami:80;
}
}
/opt/tinyauth/nginx/inc/tinyauth-location.conf(认证子请求定义):
location /tinyauth {
internal;
resolver 127.0.0.11;
set $upstream_tinyauth tinyauth;
proxy_pass http://$upstream_tinyauth:3000/api/auth/nginx;
proxy_pass_request_body off;
proxy_set_header content-length "";
proxy_set_header x-original-url $scheme://$host$request_uri;
proxy_set_header x-original-method $request_method;
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
proxy_set_header x-real-ip $remote_addr;
}
/opt/tinyauth/nginx/inc/tinyauth-server.conf(认证挂接与身份头透传):
auth_request /tinyauth;
auth_request_set $redirection_url $upstream_http_x_tinyauth_location;
error_page 401 403 =302 $redirection_url;
auth_request_set $email $upstream_http_remote_email;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $user $upstream_http_remote_user;
proxy_set_header remote-email $email;
proxy_set_header remote-groups $groups;
proxy_set_header remote-name $name;
proxy_set_header remote-user $user;
配置要点:Nginx 走 auth_request 子请求模式——location /tinyauth(internal,仅内部可用)把每个请求转成对 tinyauth 端点 /api/auth/nginx 的子请求,并回传原始 URL 与方法(x-original-url / x-original-method);子请求返回 401/403 时由 error_page 401 403 =302 $redirection_url 重定向到 tinyauth 返回的登录地址(x-tinyauth-location 响应头,经 auth_request_set 捕获);认证通过后把四个 remote-* 身份头透传给后端。
10.3 Caddy 集成(forward_auth 指令)
/opt/tinyauth/caddy/Caddyfile:
{
admin off
auto_https off
}
auth.example.com:80 {
reverse_proxy tinyauth:3000
}
whoami.example.com:80 {
forward_auth tinyauth:3000 {
uri /api/auth/caddy
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
}
reverse_proxy whoami:80
}
配置要点:forward_auth 是 Caddy 对认证子请求的封装,uri 指向 tinyauth 的 Caddy 专用端点 /api/auth/caddy,copy_headers 把认证成功响应中的四个身份头复制给后端请求。语法量最少,等价于 Nginx 的一整段 auth_request 拼装。
10.4 端到端认证链路实测(三反代逐一验证)
验证方法:curl --resolve 把两个域名指向反代端口,模拟浏览器访问。三步走:未认证访问(应跳登录)→ 调登录 API 拿会话 Cookie → 带 Cookie 再访问(应 200 且拿到身份头)。
第 1 步:未认证访问。 Traefik(8135)返回 401 并在 X-Tinyauth-Location 头给出登录跳转地址:
curl -sI --resolve whoami.example.com:8135:127.0.0.1 http://whoami.example.com:8135/
实测输出:
HTTP/1.1 401 Unauthorized
Content-Length: 39
Content-Type: application/json; charset=utf-8
X-Tinyauth-Location: http://auth.example.com/login?login_for=app&redirect_uri=http%3A%2F%2Fwhoami.example.com%3A8135%2F
{"message":"Unauthorized","status":401}
Nginx(8149)返回 302 直接跳登录页(error_page 401 =302 的效果):
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.29.8
Location: http://auth.example.com/login?login_for=app&redirect_uri=http%3A%2F%2Fwhoami.example.com%2F
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.29.8</center>
</body>
Caddy(8147)与 Traefik 同型,401 + X-Tinyauth-Location(另带 Via: 1.1 Caddy 头):
HTTP/1.1 401 Unauthorized
Content-Length: 39
Content-Type: application/json; charset=utf-8
Via: 1.1 Caddy
X-Tinyauth-Location: http://auth.example.com/login?login_for=app&redirect_uri=http%3A%2F%2Fwhoami.example.com%3A8147%2F
{"message":"Unauthorized","status":401}
💡 说明:三种反代跳转形态不同(Traefik/Caddy 透传 401 由前端处理跳转,Nginx 服务端 302),但登录地址都指向
auth.example.com/login且带redirect_uri回跳参数,浏览器访问体验一致。
第 2 步:登录拿 Cookie。 调 tinyauth 登录 API(POST /api/user/login,JSON 体),经登录入口域名访问,Cookie 写入 example.com 主域:
curl -s --resolve auth.example.com:8131:127.0.0.1 \
-c /tmp/tinyauth-cookies.txt \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}' \
-i http://auth.example.com:8131/api/user/login
实测输出:
HTTP/1.1 200 OK
Content-Length: 43
Content-Type: application/json; charset=utf-8
Set-Cookie: tinyauth-session-26742baf=aac628e6-e7d3-4fa9-9db4-176bed051667; Path=/; Domain=example.com; Expires=Sat, 24 Oct 2026 21:29:27 GMT; Max-Age=86399; HttpOnly; SameSite=Lax
{"message":"Login successful","status":200}
Cookie 文件内容(会话 Cookie 已落在主域):
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_.example.com TRUE / FALSE 1792877366 tinyauth-session-26742baf aac628e6-e7d3-4fa9-9db4-176bed051667
第 3 步:带 Cookie 访问三套反代。 全部返回 200,且后端 whoami 回显中都能看到 tinyauth 注入的三个身份头(Remote-User: admin、Remote-Name: Admin、Remote-Email: admin@example.com):
Traefik(8135):
curl -s --resolve whoami.example.com:8135:127.0.0.1 \
-b /tmp/tinyauth-cookies.txt http://whoami.example.com:8135/
实测输出:
Hostname: b1421f51062f
IP: 127.0.0.1
IP: ::1
IP: 10.89.57.5
RemoteAddr: 10.89.57.2:45592
GET / HTTP/1.1
Host: whoami.example.com:8135
User-Agent: curl/7.81.0
Accept: */*
Accept-Encoding: gzip
Cookie: tinyauth-session-26742baf=aac628e6-e7d3-4fa9-9db4-176bed051667
Remote-Email: admin@example.com
Remote-Name: Admin
Remote-User: admin
X-Forwarded-For: 10.89.57.1
X-Forwarded-Host: whoami.example.com:8135
X-Forwarded-Port: 8135
X-Forwarded-Proto: http
X-Forwarded-Server: f3e9025d43d7
X-Real-Ip: 10.89.57.1
Nginx(8149):
curl -s --resolve whoami.example.com:8149:127.0.0.1 \
-b /tmp/tinyauth-cookies.txt http://whoami.example.com:8149/
实测输出:
Hostname: b1421f51062f
IP: 127.0.0.1
IP: ::1
IP: 10.89.57.5
RemoteAddr: 10.89.57.3:57500
GET / HTTP/1.1
Host: whoami
User-Agent: curl/7.81.0
Accept: */*
Cookie: tinyauth-session-26742baf=aac628e6-e7d3-4fa9-9db4-176bed051667
Remote-Email: admin@example.com
Remote-Name: Admin
Remote-User: admin
Caddy(8147):
curl -s --resolve whoami.example.com:8147:127.0.0.1 \
-b /tmp/tinyauth-cookies.txt http://whoami.example.com:8147/
实测输出:
Hostname: b1421f51062f
IP: 127.0.0.1
IP: ::1
IP: 10.89.57.5
RemoteAddr: 10.89.57.6:42106
GET / HTTP/1.1
Host: whoami.example.com:8147
User-Agent: curl/7.81.0
Accept: */*
Accept-Encoding: gzip
Cookie: tinyauth-session-26742baf=aac628e6-e7d3-4fa9-9db4-176bed051667
Remote-Email: admin@example.com
Remote-Name: Admin
Remote-User: admin
Via: 1.1 Caddy
X-Forwarded-For: 10.89.57.1
X-Forwarded-Host: whoami.example.com:8147
X-Forwarded-Proto: http
三套反代全链路验证结论:
| 反向代理 | 未认证 | 登录后 | 身份头透传 |
|---|---|---|---|
| Traefik v3.5 | 401 + X-Tinyauth-Location | 200 | Remote-User/Name/Email 齐全 |
| Nginx 1.29 | 302 跳登录页 | 200 | Remote-User/Name/Email 齐全 |
| Caddy 2.10 | 401 + X-Tinyauth-Location | 200 | Remote-User/Name/Email 齐全 |
10.5 Basic 认证与补充说明
tinyauth 同时支持 HTTP Basic 认证直打反代(适合脚本、命令行工具场景),凭据为 tinyauth 用户账号:
curl -s --resolve whoami.example.com:8135:127.0.0.1 -u admin:q1w2e3r4 http://whoami.example.com:8135/ | grep -E 'Remote-|Authorization'
实测输出:
Authorization: Basic YWRtaW46cTF3MmUzcjQ=
Remote-Email: admin@example.com
Remote-Name: Admin
Remote-User: admin
密码错误时返回 401 并给出登录跳转地址:
HTTP/1.1 401 Unauthorized
Content-Length: 39
Content-Type: application/json; charset=utf-8
X-Tinyauth-Location: http://auth.example.com/login?login_for=app&redirect_uri=http%3A%2F%2Fwhoami.example.com%3A8135%2F
{"message":"Unauthorized","status":401}
💡 说明:官方文档另提供 Nginx Proxy Manager 与 SWAG(linuxserver 反代镜像)两条图形化/模板化集成路线,以及 Kubernetes 与标签(labels)驱动的自动 ACL 方式;本文三套为手工配置的反代典型代表,覆盖了
traefik/nginx/caddy三个专用端点的用法,其余路线可在官方文档 Guides 分区按既有技术栈选用。
十一、常用运维命令
在编排目录 /opt/tinyauth/ 内执行:
# 查看服务状态(healthy 即正常)
docker compose ps
实测输出(稳定运行期):
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
tinyauth-v5.2.0-app ghcr.io/tinyauthapp/tinyauth:v5.2.0 "/app/tinyauth" tinyauth 7 hours ago Up 7 hours (healthy) 0.0.0.0:8131->3000/tcp, [::]:8131->3000/tcp
tinyauth-v5.2.0-caddy caddy:2.10-alpine "caddy run --config …" caddy 7 hours ago Up 7 hours 0.0.0.0:8147->80/tcp, [::]:8147->80/tcp
tinyauth-v5.2.0-nginx nginx:1.29-alpine "/docker-entrypoint.…" nginx 7 hours ago Up 7 hours 0.0.0.0:8149->80/tcp, [::]:8149->80/tcp
tinyauth-v5.2.0-traefik traefik:v3.5 "entrypoint.sh --pro…" traefik 7 hours ago Up 7 hours 0.0.0.0:8135->80/tcp, [::]:8135->80/tcp
tinyauth-v5.2.0-whoami traefik/whoami:v1.10.4 "/whoami" whoami 7 hours ago Up 7 hours 80/tcp
# 跟踪认证日志(登录成功/失败、forward auth 校验都在这里)
docker compose logs -f tinyauth
实测输出节选(一次完整的「未认证 401 → 登录成功 → 携 Cookie 校验 200」):
2026-10-23T21:24:52Z INF Starting Tinyauth version: v5.2.0 stream=app
2026-10-23T21:24:52Z INF Starting server on http://0.0.0.0:3000 stream=app
2026-10-23T21:24:57Z WRN Client Error address=10.89.57.2:40894 client_ip=10.89.57.1 latency="132.492µs" method=GET path=/api/auth/traefik status=401 stream=http
2026-10-23T21:24:57Z INF Login successful stream=app username=admin
2026-10-23T21:24:57Z INF Request address=10.89.57.2:40910 client_ip=10.89.57.1 latency=44.491023ms method=POST path=/api/user/login status=200 stream=http
2026-10-23T21:24:57Z INF Request address=10.89.57.2:40894 client_ip=10.89.57.1 latency="34.62µs" method=GET path=/api/auth/traefik status=200 stream=http
# 应用层健康检查
docker exec tinyauth-v5.2.0-app tinyauth healthcheck
实测输出:
2026-10-23T21:23:16Z INF Performing health check app_url=http://127.0.0.1:3000 stream=app
2026-10-23T21:23:16Z INF Tinyauth is healthy response={"message":"Healthy","status":200} stream=app
# 查看当前生效配置(YAML 转储,排障首选)
docker exec tinyauth-v5.2.0-app tinyauth config
实测输出节选(ANSI 着色符已剥离):
Your current configuration in YAML is:
appUrl: http://auth.example.com
labelProvider: auto
database:
driver: sqlite
path: /data/tinyauth.db
server:
port: 3000
address: 0.0.0.0
auth:
users:
- admin:$2a$10$Edf9Rb8EMGOjyXIf1.yLCur3593A9DlmuZyi5tTeT0./1dmWv62UK
subdomainsEnabled: true
sessionExpiry: 86400
loginTimeout: 300
loginMaxRetries: 3
trustedProxies:
- 10.89.57.0/24
acls:
policy: allow
# 升级版本:改镜像标签 → 拉取 → 重建(数据卷保留,账号/配置不丢)
docker compose pull tinyauth
docker compose up -d tinyauth
实测输出(升级重启节选):
Container tinyauth-v5.2.0-app Recreate
Container tinyauth-v5.2.0-app Recreated
Container tinyauth-v5.2.0-app Starting
Container tinyauth-v5.2.0-app Started
tinyauth-v5.2.0-app Up 5 seconds (healthy)
# 停止 / 清理整套编排(external 网络与命名卷不受影响)
docker compose down
实测输出:
Container tinyauth-v5.2.0-caddy Stopped
Container tinyauth-v5.2.0-caddy Removed
Container tinyauth-v5.2.0-nginx Stopped
Container tinyauth-v5.2.0-nginx Removed
Container tinyauth-v5.2.0-traefik Stopped
Container tinyauth-v5.2.0-traefik Removed
Container tinyauth-v5.2.0-whoami Stopped
Container tinyauth-v5.2.0-whoami Removed
Container tinyauth-v5.2.0-app Stopped
Container tinyauth-v5.2.0-app Removed
💡 说明:
docker compose down不会删除tinyauth-data命名卷与external网络,重新up -d后数据原样恢复;确认要彻底清空数据时再显式执行docker compose down -v。
十二、常见问题
Q1:按官方文档执行 docker compose exec tinyauth healthcheck 报错 exec: "healthcheck": executable file not found in $PATH?
实测报错原文:
OCI runtime exec failed: exec failed: unable to start container process: exec: "healthcheck": executable file not found in $PATH
定位:v5.2.0 官方镜像内二进制名为 tinyauth,healthcheck 是它的子命令而不是独立可执行文件。解决方案是把子命令完整写出来:
docker compose exec tinyauth tinyauth healthcheck
实测输出:
2026-10-23T21:23:16Z INF Performing health check app_url=http://127.0.0.1:3000 stream=app
2026-10-23T21:23:16Z INF Tinyauth is healthy response={"message":"Healthy","status":200} stream=app
Q2:直接用 curl 打 forward auth 端点(/api/auth/traefik 等)一直 400 Bad Request?
实测输出:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 38
{"message":"Bad request","status":400}
这不是故障:三个端点依赖反代注入的请求头(如 Nginx 的 x-original-url、Traefik 的 x-forwarded-host)来识别受保护应用,脱离反代裸打必然 400。tinyauth 日志中对应的错误也印证了这一点:
2026-10-23T21:24:57Z ERR Failed to get proxy context from request error="failed to get context from any auth module" stream=app
正确验证方式是走反代访问受保护应用(见 10.4)。
Q3:能登录,但受保护应用始终跳回登录页或直接 500?
排查 Cookie 作用域。tinyauth 从 TINYAUTH_APPURL 推导 Cookie 域,域名不是三段式时 Cookie 会写在登录入口自身域上,受保护子域拿不到。实测对比:APPURL=http://auth.localtest(两段式)时 Cookie 被写到 Domain=auth.localtest:
Set-Cookie: tinyauth-session-1d49dbcf=fdb727c6-1f2e-428f-aa0e-54a7b49b9ffd; Path=/; Domain=auth.localtest; Expires=Sat, 24 Oct 2026 21:23:16 GMT; Max-Age=86399; HttpOnly; SameSite=Lax
同为 localtest 后缀的受保护域名访问时直接被拒(HTTP 500)。改用 http://auth.example.com(三段式)后 Cookie 正确落到 Domain=example.com,全链路打通。结论:APPURL 与所有受保护应用域名必须共享同一三段式主域。
Q4:重启后要重新登录?
是正常行为。会话数据不跨重启保留:重启后旧 Cookie 校验返回 401(见第五章实测),重新登录即可;用户账号、OIDC 密钥等数据由 /data 数据卷持久化,不受重启影响。
Q5:反代转发的客户端 IP 不对或跳转地址异常?
检查 TINYAUTH_AUTH_TRUSTEDPROXIES 是否覆盖反代来源网段。该值必须包含实际发起转发请求的一方(本文为 10.89.57.0/24),未声明时 tinyauth 不信任 X-Forwarded-For 头。可用 tinyauth config 转储确认生效值(见第七章实测)。
Q6:账号密码确认无误却始终登录失败?
检查 Compose 中 bcrypt 哈希的 $$ 转义。Compose 环境变量把 $ 写成 $$ 才能得到真实值;漏写(单 $)或错写(在 docker run 场景用了 $$)都会导致哈希比对失败。用 user verify 可离线核对账号串与密码是否匹配:
docker exec tinyauth-v5.2.0-app tinyauth user verify \
--user 'admin:$2a$10$Edf9Rb8EMGOjyXIf1.yLCur3593A9DlmuZyi5tTeT0./1dmWv62UK' \
--username admin --password q1w2e3r4
实测输出:
✓ User verified
密码与哈希不匹配时的报错原文:
Failed to execute command: command verify error: password is incorrect: crypto/bcrypt: hashedPassword is not the hash of the given password
Q7:想限制「登录用户」里谁能访问某个应用?
用应用级 ACL。示例:仅允许 nobody 访问 whoami(TINYAUTH_APPS_WHOAMI_CONFIG_DOMAIN=whoami.example.com、TINYAUTH_APPS_WHOAMI_USERS_ALLOW=nobody),已登录的 admin 访问时被拒:
HTTP/1.1 403 Forbidden
Content-Length: 36
Content-Type: application/json; charset=utf-8
X-Tinyauth-Location: http://auth.example.com/unauthorized?groupErr=false&ip=&resource=whoami&username=admin
{"message":"Forbidden","status":403}
把 allow 列表改回 admin 后同一请求返回 200。ACL 全量参数(users/ip/path/oauth/ldap 维度)见配置参数详解篇。
Q8:登出怎么做?
浏览器端在登录页点登出;API 层调 POST /api/user/logout,实测返回 200 并以 Max-Age=0 立即清除 Cookie:
HTTP/1.1 200 OK
Set-Cookie: tinyauth-session-26742baf=; Path=/; Domain=example.com; Expires=Fri, 23 Oct 2026 21:31:04 GMT; Max-Age=0; HttpOnly; SameSite=Lax
登出后再访问受保护应用回到 401 跳登录。
十三、参考链接
- 官方文档站:https://tinyauth.app
- Getting Started:https://tinyauth.app/docs/getting-started
- Configuration 参考:https://tinyauth.app/docs/reference/configuration
- CLI 参考:https://tinyauth.app/docs/reference/cli
- GitHub 仓库(含 Releases):https://github.com/tinyauthapp/tinyauth
- 本专栏系列:《tinyauth v5.2.0 介绍与选型指南》(定位、架构与同类对比)