Compare commits

...

1 Commits

4 changed files with 529 additions and 5 deletions

View File

@@ -3,10 +3,15 @@ slug: Windows Git Bash 改用 Zsh
title: Windows Git Bash 改用 Zsh
description:
toc: true
authors: []
tags: []
categories: []
series: []
authors:
- awin
tags:
- windows
- terminal
categories:
- System
series:
- Windows
date: 2026-01-16T00:00:00
lastmod: 2026-01-16T00:00:00
featuredVideo:

View File

@@ -0,0 +1,519 @@
---
slug: 用 Caddy 做反向代理 + 用 Authentik 管理帳號(以 Gitea 為例)
title: 用 Caddy 做反向代理 + 用 Authentik 管理帳號(以 Gitea 為例)
description:
toc: true
authors:
- awin
tags:
- linux
- selfhosted
categories:
- System
series:
- Linux
date: 2026-02-01T00:00:00
lastmod: 2026-02-01T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
本篇會帶你用 **Caddy** 當反向代理Reverse Proxy與自動 TLS並用 **Authentik** 當身分提供者IdP / SSO來管理帳號最後以 **Gitea** 當範例,完成「反向代理 + 單一登入OIDC」整合。
這張可愛的圖是 Gemini 生成的。
<!--more-->
本文參考文件:
- Caddy 文件:[https://caddyserver.com/docs/](https://caddyserver.com/docs/)
- Authentik 文件:[https://docs.goauthentik.io/](https://docs.goauthentik.io/)
- Authentik 整合文件:[https://integrations.goauthentik.io/](https://integrations.goauthentik.io/)
- Authentik × Gitea以官方整合為主[https://integrations.goauthentik.io/development/gitea/](https://integrations.goauthentik.io/development/gitea/)
範例網域:
- Authentik`auth.www.myapp.example`
- Gitea`git.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、與把流量分流到 `Authentik``Gitea`
---
## 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.example``git.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_id``redirect_uri``scope``state` 等參數。
3. 使用者在 Authentik 完成登入(可能含 MFA
4. Authentik 將瀏覽器導回 Gitea 的 `redirect_uri`callback並附上 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`
```yaml
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`
```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 的 `9000`HTTP即可避免 `9443` 牽涉到後端 TLS 憑證驗證問題。
> 如果你堅持要反向代理到 Authentik 的 `9443`HTTPS才需要在 Caddy 端處理後端 TLS例如自簽憑證可能需要 `tls_insecure_skip_verify`)。但這會讓設定更複雜,也比較不建議。
---
## 6) Authentikdocker-compose 與 .env
### 6.1 Authentik 的 .env範例請自行填值
檔案位置示意:`docker/authentik/.env`
```dotenv
# Database
PG_PASS=請填入強密碼
PG_USER=authentik
PG_DB=authentik
# Authentik
AUTHENTIK_SECRET_KEY=請填入長度足夠的隨機字串
# 版本(可固定,避免 latest 帶來不可預期變更)
AUTHENTIK_TAG=2025.12.2
```
安全提醒:
- `.env` 不要上傳到公開 repo。
- `PG_PASS``AUTHENTIK_SECRET_KEY` 請使用密碼管理器產生。
### 6.2 Authentik 的 docker-compose.yml範例
檔案位置示意:`docker/authentik/docker-compose.yml`
```yaml
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`
```yaml
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.ini``ROOT_URL`,或在管理介面可調),原則是「以使用者實際從瀏覽器進入的網址」為準。
如果你要讓 `git.www.myapp.example` 對外提供 SSH22而不是用 2244也可以改成 `"22:22"`,但請確認主機上沒有其他 SSH 服務衝突(例如 OpenSSH
---
## 8) 啟動順序與驗證
分開三份 compose 時,建議啟動順序:
1) Authentik含 DB/Redis
2) Gitea
3) Caddy最後再把入口打開
範例指令(在各自資料夾):
```bash
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/](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**
- 重要欄位(名稱以示意為主):
- Name`gitea-oidc`
- Client type通常選 ConfidentialGitea 是 server-side
- Redirect URIs填入 Gitea 的 callback URL下一小節會說怎麼確定
- Scopes至少包含 `openid`, `email`, `profile`
2. 建立 Application
- Applications → Create
- Name`Gitea`
- Slug`gitea`
- 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 URL`https://auth.www.myapp.example/application/o/gitea/.well-known/openid-configuration`
- Client ID從 Authentik 複製
- Client Secret從 Authentik 複製
- Scopes`openid 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 驗證問題
如果你用:
```caddyfile
reverse_proxy https://...:9443
```
而 Authentik 端使用自簽憑證或內部憑證Caddy 會因為無法驗證而拒絕。
解法:
- 最簡單:反向代理到 `host.docker.internal:9000`HTTP把 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 proxy`、`trusted proxy`、`X-Forwarded-Proto`。
---
## 11) 小結
Authentik 解決了自己架站一個站就要建一次帳號的問題。
1. **Caddy**:負責自動化 TLS 與反向代理解決了惱人的憑證問題並統一了對外入口80/443
2. **Authentik**:作為核心的身分驗證中心,未來若要新增其他服務(如 Portainer、Grafana、Nextcloud 等),只要它們支援 OIDC/OAuth2 或 ForwardAuth都能輕鬆接入實現真正的單一登入SSO
3. **Gitea**:成功展示了從「各服務獨立帳號」轉向「集中式帳號管理」的整合流程。
雖然初期在理解 OIDC 流程與反向代理設定上需要花點時間,但建立起這套基礎設施後,未來的維護與擴充將會變得非常輕鬆且安全。希望這篇文章能幫助你順利搭建出自己的 Authentik 單一登入環境!
希望這篇文章有幫到你,謝謝你的閱讀。

View File

@@ -1,6 +1,6 @@
#!/bin/bash
CONTAINER_DIR="/lvm1/docker/blog"
CONTAINER_DIR="/DATA01/dockers/blog"
IP_ADDR="192.168.1.24"
../../bin/0.100.1_extend/hugo.exe