Files

18 KiB
Raw Permalink Blame History

slug, title, description, toc, authors, tags, categories, series, date, lastmod, featuredVideo, featuredImage, draft, enableComment
slug title description toc authors tags categories series date lastmod featuredVideo featuredImage draft enableComment
用 Caddy 做反向代理 + 用 Authentik 管理帳號(以 Gitea 為例) 用 Caddy 做反向代理 + 用 Authentik 管理帳號(以 Gitea 為例) true
awin
linux
selfhosted
System
Linux
2026-02-01T00:00:00 2026-02-01T00:00:00 false true

本篇會帶你用 Caddy 當反向代理Reverse Proxy與自動 TLS並用 Authentik 當身分提供者IdP / SSO來管理帳號最後以 Gitea 當範例,完成「反向代理 + 單一登入OIDC」整合。

這張可愛的圖是 Gemini 生成的。

本文參考文件:

範例網域:

  • Authentikauth.www.myapp.example
  • Giteagit.www.myapp.example

(以上都以 www.myapp.example 為「示意域名」。實作時請換成你自己的可解析網域,並確保 DNS A/AAAA 指向你的主機 IP。

本文所有服務都以 Docker 方式部署,並以「分開三份 docker-compose」為主。為了降低複雜度本文不使用共用 Docker networkCaddy 會透過 host.docker.internal 反向代理到宿主機上已 publish 的服務埠。


1) Caddy 的優點與功能

Caddy 是現代化的 Web Server / 反向代理,特別適合「自架服務入口」:

  • 自動 HTTPS:內建 ACME例如 Lets Encrypt只要網域與 80/443 可用Caddy 會自動申請與續期憑證。
  • 設定檔簡潔Caddyfile 可讀性高反向代理、gzip/zstd、header、redirect 等都很直覺。
  • 反向代理體驗好reverse_proxy 直接把請求轉送到後端服務HTTP/HTTPS/Unix socket 都可)。
  • 可擴充:模組化(插件)設計,常見需求如 forward auth、rate limit、WAF 等都有社群方案(是否採用依你需求而定)。
  • 適合容器化:用 Docker 跑 Caddy 非常普遍,資料(憑證、設定)用 volume 掛載即可。

在這篇架構裡Caddy 的角色很單純:

  • 對外只有一個入口80/443
  • 負責 TLS、HTTP→HTTPS、與把流量分流到 AuthentikGitea

2) Authentik 的優點與功能

Authentik 是一個自架的身分與存取管理IAM/ 單一登入SSO平台你可以把它當成「你自己的 Google/Microsoft/Okta Login」。

常見價值:

  • 統一帳號來源:帳號、群組、權限集中管理,不用每個服務都自己養帳。
  • 多種整合方式OIDCOpenID Connect、OAuth2、SAML、LDAP、Proxy/ForwardAuth 等。
  • 安全能力MFA、條件式存取、登入流程flow可控。
  • 自架友善Docker 部署成熟,社群整合文件多。

在這篇裡 Authentik 的角色是:

  • OIDC Provider(發行 token / 提供 userinfo
  • Gitea 透過 OIDC 把「登入」交給 Authentik

3) 以 Gitea 為例Caddy、Authentik、Gitea 的角色與登入流程

三方關係(誰做什麼)

  • Caddy反向代理 / 門口)

    • 接收瀏覽器對 auth.www.myapp.examplegit.www.myapp.example 的連線
    • 依網域把請求轉送到對應容器
  • Authentik身分提供者 IdP / SSO

    • 管理使用者
    • 提供 OIDC discovery / authorization / token / userinfo
  • Gitea應用服務 / Relying Party

    • 提供 Git service 與 Web UI
    • 使用者點「用 Authentik 登入」→ 把驗證交給 Authentik

登入流程OIDC 概念流程)

以使用者從 git.www.myapp.example 進入為例:

  1. 使用者進入 Gitea選擇「用 Authentik 登入」OIDC/OAuth2
  2. Gitea 將瀏覽器導向 Authentik 的授權端點authorize並帶上 client_idredirect_uriscopestate 等參數。
  3. 使用者在 Authentik 完成登入(可能含 MFA
  4. Authentik 將瀏覽器導回 Gitea 的 redirect_uricallback並附上 code。
  5. Gitea 以 server-to-server 方式向 Authentik 的 token endpoint 換取 token。
  6. Gitea 用 token 取得使用者資訊(或驗證 ID Token建立/綁定本地帳號並完成登入。

重點:

  • Caddy 不負責「帳號驗證」,它只是把流量導到 Authentik/Gitea。
  • Authentik 负责身份Gitea 負責「使用 Authentik 身份」來登入。

4) 實作:用 Docker 部署三套服務並完成整合

4.1 先準備DNS 與防火牆

  • DNS

    • auth.www.myapp.example → 你的主機 IP
    • git.www.myapp.example → 你的主機 IP
  • 對外開放:

    • TCP 80、443給 Caddy 申請/使用 TLS
  • 建議不要「對外網」放行(但會在主機上 publish 給 Caddy 用):

    • Authentik 的 9000本文用它讓 Caddy 反向代理)
    • Authentik 的 9443通常不需要除非你自己另外 publish 來除錯)
    • Gitea 的 8020本文用它讓 Caddy 反向代理)
    • 2244/22SSH是否對外開放依你需求可先不開

如果你用「Caddy 反向代理」模式,後端服務的 port 原則上不應對外網可達,避免繞過入口直接連到後端。

本文為了不使用共用 network後端服務會用 ports: publish 到主機;因此「不要對外放行」指的是:不要在路由器/NAT 或雲端安全群組把這些埠開給 Internet。


5) Caddydocker-compose 與 Caddyfile

5.1 Caddy 的 docker-compose.yml範例

檔案位置示意:docker/caddy/docker-compose.yml

services:
	caddy:
		image: caddy:2.10.2
		container_name: caddy
		restart: unless-stopped
		ports:
			- "80:80"
			- "443:443"
		extra_hosts:
			- "host.docker.internal:host-gateway"
		volumes:
			- ./config/Caddyfile:/etc/caddy/Caddyfile:ro
			- ./data/data:/data
			- ./data/config:/config

說明:

  • host.docker.internal 在 Docker DesktopWindows/macOS通常可用。
  • 在 Linux/Ubuntu 上常見需要加 extra_hosts: host.docker.internal:host-gateway,才能讓容器用 host.docker.internal 連到宿主機。

5.2 Caddyfile範例

檔案位置示意:docker/caddy/config/Caddyfile

{
	# 可選:管理者信箱,用於 ACME
	email admin@www.myapp.example
}

# Authentik對外入口
auth.www.myapp.example {
	encode zstd gzip
	# 反向代理到宿主機上 publish 的 Authentik 9000HTTP
	reverse_proxy host.docker.internal:9000
}

# Gitea對外入口
git.www.myapp.example {
	encode zstd gzip
	# 反向代理到宿主機上 publish 的 Gitea 8020
	reverse_proxy host.docker.internal:8020
}

說明:

  • 這份教學為了降低複雜度,讓 TLS 只由 Caddy 對外負責
  • 所以 Caddy 反向代理到 Authentik 的 9000HTTP即可避免 9443 牽涉到後端 TLS 憑證驗證問題。

如果你堅持要反向代理到 Authentik 的 9443HTTPS才需要在 Caddy 端處理後端 TLS例如自簽憑證可能需要 tls_insecure_skip_verify)。但這會讓設定更複雜,也比較不建議。


6) Authentikdocker-compose 與 .env

6.1 Authentik 的 .env範例請自行填值

檔案位置示意:docker/authentik/.env

# Database
PG_PASS=請填入強密碼
PG_USER=authentik
PG_DB=authentik

# Authentik
AUTHENTIK_SECRET_KEY=請填入長度足夠的隨機字串

# 版本(可固定,避免 latest 帶來不可預期變更)
AUTHENTIK_TAG=2025.12.2

安全提醒:

  • .env 不要上傳到公開 repo。
  • PG_PASSAUTHENTIK_SECRET_KEY 請使用密碼管理器產生。

6.2 Authentik 的 docker-compose.yml範例

檔案位置示意:docker/authentik/docker-compose.yml

services:
	postgresql:
		image: postgres:16-alpine
		restart: unless-stopped
		healthcheck:
			test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
			start_period: 20s
			interval: 30s
			retries: 5
			timeout: 5s
		volumes:
			- ./data/postgresql_data:/var/lib/postgresql/data
		environment:
			POSTGRES_PASSWORD: ${PG_PASS:?database password required}
			POSTGRES_USER: ${PG_USER:-authentik}
			POSTGRES_DB: ${PG_DB:-authentik}
		env_file:
			- .env

	redis:
		image: redis:alpine
		command: --save 60 1 --loglevel warning
		restart: unless-stopped
		healthcheck:
			test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
			start_period: 20s
			interval: 30s
			retries: 5
			timeout: 3s
		volumes:
			- redis:/data

	server:
		image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.12.2}
		container_name: authentik-server
		restart: unless-stopped
		command: server
		environment:
			AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
			AUTHENTIK_REDIS__HOST: redis
			AUTHENTIK_POSTGRESQL__HOST: postgresql
			AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
			AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
			AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
		volumes:
			- ./data/authentik/media:/media
			- ./data/authentik/custom-templates:/templates
		env_file:
			- .env
		# 透過 ports publish 到宿主機,讓 Caddy 用 host.docker.internal 反向代理
		ports:
			- "9000:9000"
		depends_on:
			postgresql:
				condition: service_healthy
			redis:
				condition: service_healthy

	worker:
		image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.12.2}
		container_name: authentik-worker
		restart: unless-stopped
		command: worker
		environment:
			AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
			AUTHENTIK_REDIS__HOST: redis
			AUTHENTIK_POSTGRESQL__HOST: postgresql
			AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
			AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
			AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
		user: root
		volumes:
			- /var/run/docker.sock:/var/run/docker.sock
			- ./data/authentik/media:/media
			- ./data/authentik/certs:/certs
			- ./data/authentik/custom-templates:/templates
		env_file:
			- .env
		depends_on:
			postgresql:
				condition: service_healthy
			redis:
				condition: service_healthy

volumes:
	redis:
		driver: local

小提醒:

  • 這個「不共用 network」的做法後端服務需要透過 ports: publish 到宿主機,才能讓 Caddy 容器透過 host.docker.internal 連到它。
  • 安全性上要靠「不要在路由器/NAT/雲端安全群組把 9000/8020 對外放行」,只放行 80/443 給 Caddy。

7) Giteadocker-compose範例

檔案位置示意:docker/gitea/docker-compose.yml

services:
	gitea:
		image: gitea/gitea:latest
		container_name: gitea
		restart: unless-stopped
		environment:
			- USER_UID=1000
			- USER_GID=1000
		volumes:
			- ./data:/data
			- /etc/timezone:/etc/timezone:ro
			- /etc/localtime:/etc/localtime:ro
		ports:
			- "8020:3000"
			- "2244:22"  # SSH 是否對外開放依你需求;如果你要用 git@... 的方式推送才需要

反向代理補充(很重要,避免 OIDC callback 出現網址不一致):

  • 請確認 Gitea 的「對外 Base URL」是 https://git.www.myapp.example/
  • 若 Base URL 設錯常見症狀是Gitea 顯示的 callback URL 會是 http://... 或 host/port 不對,導致 Authentik 報 redirect_uri mismatch
  • 設定位置依你的 Gitea 部署方式而不同(例如 app.iniROOT_URL,或在管理介面可調),原則是「以使用者實際從瀏覽器進入的網址」為準。

如果你要讓 git.www.myapp.example 對外提供 SSH22而不是用 2244也可以改成 "22:22",但請確認主機上沒有其他 SSH 服務衝突(例如 OpenSSH


8) 啟動順序與驗證

分開三份 compose 時,建議啟動順序:

  1. Authentik含 DB/Redis
  2. Gitea
  3. Caddy最後再把入口打開

範例指令(在各自資料夾):

docker compose up -d

驗證:

  • 先確認 Authentik 後台能打開:https://auth.www.myapp.example/
  • 再確認 Gitea 能打開:https://git.www.myapp.example/

9) Authentik × Gitea 整合(以官方文件流程為準)

本段建議你同時開著官方整合頁:https://integrations.goauthentik.io/development/gitea/

整體思路:

  1. 在 Authentik 建立一個「對 Gitea 用的 OIDC Provider」
  2. 建立 Application把 provider 掛上去
  3. 把 Discovery URL / Client ID / Client Secret 填進 Gitea 的 Authentication Source

9.1 在 Authentik 建立 Provider + Application

在 Authentik 管理介面:

  1. 建立 Provider

    • Providers → Create → OAuth2/OpenID Provider
    • 重要欄位(名稱以示意為主):
      • Namegitea-oidc
      • Client type通常選 ConfidentialGitea 是 server-side
      • Redirect URIs填入 Gitea 的 callback URL下一小節會說怎麼確定
      • Scopes至少包含 openid, email, profile
  2. 建立 Application

    • Applications → Create
    • NameGitea
    • Sluggitea
    • Provider選剛剛建立的 gitea-oidc

建立完成後,你會得到:

  • Client ID
  • Client Secret -通常也會有OpenID Configuration / Discovery URL

建議使用「Discovery URL」方式整合因為端點與簽章金鑰都能自動跟上。

Discovery URL常見樣式請以你的 Authentik 介面顯示為準):

  • https://auth.www.myapp.example/application/o/gitea/.well-known/openid-configuration

9.2 在 Gitea 新增 Authentication SourceOIDC

到 Gitea需管理者權限

  1. Site Administration → Authentication Sources → Add Authentication Source
  2. Type 選 OAuth2或 OpenID Connect依 Gitea 版本 UI
  3. Provider 選 OpenID Connect
  4. 填入:
    • Auto Discovery URLhttps://auth.www.myapp.example/application/o/gitea/.well-known/openid-configuration
    • Client ID從 Authentik 複製
    • Client Secret從 Authentik 複製
    • Scopesopenid email profile

建立後Gitea 通常會顯示 callback URL 類似:

  • https://git.www.myapp.example/user/oauth2/<SOURCE_NAME>/callback

把這個 callback URL 回填到 Authentik provider 的 Redirect URIs兩邊要一致

9.3 測試登入

回到 Gitea 登入頁:

  • 看到「用 Authentik 登入」的按鈕/選項
  • 點下去會跳到 auth.www.myapp.example 完成登入
  • 成功後回到 Gitea首次登入可能會建立/連結本地使用者

10) 常見踩雷整理(避免再踩一次)

你提供的 Perplexity 連結在這個環境下會遇到 403無法直接讀取頁面內容所以我沒辦法逐字引用你當時的對話但我可以把「你目前設定中已經出現/很常遇到」的坑整理成一章,讓你下次少繞路。

10.1 host.docker.internal 在 Linux/Ubuntu 不一定可用

  • 在 Docker DesktopWindows/macOS通常可以用 host.docker.internal
  • 在 Linux 常見情況是 預設沒有 這個 DNS 名稱。

可行解法(本文採用):在 Caddy container 加上:

  • extra_hosts: ["host.docker.internal:host-gateway"]

10.2 反向代理到 Authentik 的 9443 可能遇到 TLS 驗證問題

如果你用:

reverse_proxy https://...:9443

而 Authentik 端使用自簽憑證或內部憑證Caddy 會因為無法驗證而拒絕。

解法:

  • 最簡單:反向代理到 host.docker.internal:9000HTTP把 TLS 全交給 Caddy 對外處理。
  • 若必須反向代理到 :9443:才處理後端 TLS可能需要 tls_insecure_skip_verify),但要理解它是「跳過驗證」。

10.3 後端服務不要再對外暴露 port避免繞過 Caddy

在本文「不共用 network」的簡化架構裡Authentik/Gitea 必須 publish port 到宿主機Caddy 才連得到。

建議的安全作法是:

  • 路由器/NAT:只轉發 80/443 到這台機器
  • 雲端安全群組Security Group:只開 80/443 inbound
  • 讓 9000/8020 只留在「主機本地用途」(給 Caddy 反向代理),不要對外網暴露

10.4 OIDC 回呼網址Redirect URI最容易填錯

症狀通常是:

  • 登入後跳轉回來直接錯誤redirect_uri mismatch / invalid redirect

原則:

  • Gitea 顯示的 callback URL 為準
  • 100% 原樣貼到 Authentik Provider 的 Redirect URIs
  • domain、path、https 都要一致

10.5 反向代理後網址不對http/host/port 亂跳)

如果你發現登入流程中 URL 變成 http://、或 host/port 被改掉,通常是「應用程式不知道自己在反向代理後面」造成的。

  • Gitea先回頭檢查 Base URL/ROOT_URL 是否為 https://git.www.myapp.example/
  • Authentik確保你是透過 https://auth.www.myapp.example/ 存取管理介面,並檢查是否有「反向代理/受信任代理trusted proxy」或「外部 URLexternal host/url」相關設定需要調整。

這一段在不同 Authentik 版本/部署方式名稱會不一樣,遇到時建議直接依官方文件用關鍵字搜尋:reverse proxytrusted proxyX-Forwarded-Proto


11) 小結

Authentik 解決了自己架站一個站就要建一次帳號的問題。

  1. Caddy:負責自動化 TLS 與反向代理解決了惱人的憑證問題並統一了對外入口80/443
  2. Authentik:作為核心的身分驗證中心,未來若要新增其他服務(如 Portainer、Grafana、Nextcloud 等),只要它們支援 OIDC/OAuth2 或 ForwardAuth都能輕鬆接入實現真正的單一登入SSO
  3. Gitea:成功展示了從「各服務獨立帳號」轉向「集中式帳號管理」的整合流程。

雖然初期在理解 OIDC 流程與反向代理設定上需要花點時間,但建立起這套基礎設施後,未來的維護與擴充將會變得非常輕鬆且安全。希望這篇文章能幫助你順利搭建出自己的 Authentik 單一登入環境!

希望這篇文章有幫到你,謝謝你的閱讀。