Compare commits
6 Commits
bba920d758
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 557b0eca33 | |||
| 8c7eddbaee | |||
| 9473a98165 | |||
| 5e113476b6 | |||
| c90649e642 | |||
| de50e47c76 |
+23
@@ -26,4 +26,27 @@ frpc/frpc.toml
|
|||||||
|
|
||||||
# 忽略 Traefik 证书
|
# 忽略 Traefik 证书
|
||||||
traefik/letsencrypt/
|
traefik/letsencrypt/
|
||||||
|
|
||||||
|
# 忽略数据库持久化数据
|
||||||
|
authentik/pgdata/
|
||||||
|
authentik/redis/
|
||||||
|
authentik/media/
|
||||||
|
gitea/db_data/
|
||||||
|
hedgedoc/data_pg11_backup/
|
||||||
|
|
||||||
|
# 忽略旧 MinIO(已迁移至 SeaweedFS)
|
||||||
|
minio/
|
||||||
|
|
||||||
|
# 忽略 SeaweedFS 运行时数据
|
||||||
|
seaweedfs/data/
|
||||||
|
|
||||||
|
# 忽略 AI 工具
|
||||||
.aider*
|
.aider*
|
||||||
|
|
||||||
|
# 忽略 remark42 数据
|
||||||
|
remark42/var/
|
||||||
|
remark42/.env
|
||||||
|
|
||||||
|
# 忽略 OpenWebUI 数据和密钥
|
||||||
|
openwebui/data/
|
||||||
|
openwebui/.env
|
||||||
|
|||||||
@@ -7,43 +7,75 @@
|
|||||||
```
|
```
|
||||||
公网用户
|
公网用户
|
||||||
│
|
│
|
||||||
├─ Web (443) ──→ Cloudflare Tunnel ──→ cloudflared (Docker) ──→ Traefik (反向代理)
|
├─ Web (443) ──→ Cloudflare Tunnel ──→ cloudflared (Docker, HTTP/2)
|
||||||
│ │
|
│ │
|
||||||
└─ SSH (22) ──→ 阿里云 VPS (frps) ──→ frpc (Docker) ──→ Gitea │
|
└─ SSH (22) ──→ 阿里云 VPS (frps) ──→ frpc (Docker) ──→ Gitea
|
||||||
│
|
│
|
||||||
┌───────────────┤
|
Traefik v3.7.1 (反向代理)
|
||||||
▼ ▼
|
│
|
||||||
各 Web 服务 Gitea SSH
|
┌───────────────┼───────────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
(有 Authentik SSO) (ForwardAuth) (免认证)
|
||||||
|
Gitea / HedgeDoc SeaweedFS / Gitea SSH
|
||||||
|
Homepage / OpenWebUI Uptime Kuma
|
||||||
```
|
```
|
||||||
|
|
||||||
| 入口 | 域名 | 传输 | 延迟 |
|
| 入口 | 域名 | 传输 | 延迟 |
|
||||||
|------|------|------|:--:|
|
|------|------|------|:--:|
|
||||||
| Web | `*.xiteng.site` | Cloudflare Tunnel → Traefik | ~50ms |
|
| Web | `*.xiteng.site` | Cloudflare Tunnel (HTTP/2) → Traefik | ~50ms |
|
||||||
| Git SSH | `git.xiteng.site` | 阿里云 VPS → frp → Gitea | ~5ms |
|
| Git SSH | `git.xiteng.site` | 阿里云 VPS → frp → Gitea | ~5ms |
|
||||||
|
|
||||||
## 服务一览
|
## 服务一览
|
||||||
|
|
||||||
| 服务 | 地址 | 说明 |
|
| 服务 | 地址 | 认证 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|------|
|
||||||
| Homepage | [xiteng.site](https://xiteng.site) | 导航面板 |
|
| Homepage | [home.xiteng.site](https://home.xiteng.site) | Authentik OIDC | 导航面板 |
|
||||||
| Gitea | [gitea.xiteng.site](https://gitea.xiteng.site) | 代码托管, `git clone git@git.xiteng.site:…` |
|
| Authentik | [auth.xiteng.site](https://auth.xiteng.site) | 自身 | 统一 SSO (v2026.5.0) |
|
||||||
| HedgeDoc | [notes.xiteng.site](https://notes.xiteng.site) | Markdown 协作 |
|
| Gitea | [gitea.xiteng.site](https://gitea.xiteng.site) | Authentik OAuth2 | 代码托管 |
|
||||||
| Uptime Kuma | [uptime.xiteng.site](https://uptime.xiteng.site) | 服务监控 |
|
| HedgeDoc | [notes.xiteng.site](https://notes.xiteng.site) | Authentik OIDC | Markdown 协作 |
|
||||||
| MinIO | 内网 | 对象存储(不暴露公网) |
|
| OpenWebUI | [ai.xiteng.site](https://ai.xiteng.site) | Authentik OIDC | AI 对话界面 (v0.9.5) |
|
||||||
| Traefik | 内网 | 反向代理 |
|
| SeaweedFS | [file.xiteng.site](https://file.xiteng.site) | Authentik ForwardAuth | 对象存储 (v4.28) |
|
||||||
|
| SeaweedFS S3 | [minio-api.xiteng.site](https://minio-api.xiteng.site) | Access Key | S3 API |
|
||||||
|
| Uptime Kuma | [uptime.xiteng.site](https://uptime.xiteng.site) | Authentik ForwardAuth | 服务监控 |
|
||||||
|
| Remark42 | [remark.xiteng.site](https://remark.xiteng.site) | Authentik OAuth2 | 评论系统 |
|
||||||
|
| Traefik | 内网 | — | 反向代理 |
|
||||||
|
|
||||||
|
> **注意**: SeaweedFS 已替代原 MinIO。域名于 2026-05-27 从 `s3.xiteng.site` 迁移至 `file.xiteng.site`。
|
||||||
|
|
||||||
|
## 认证架构
|
||||||
|
|
||||||
|
```
|
||||||
|
用户请求 → Cloudflare → cloudflared → Traefik
|
||||||
|
│
|
||||||
|
┌─────────────┤
|
||||||
|
▼ ▼
|
||||||
|
ForwardAuth OAuth2/OIDC
|
||||||
|
(中间件子请求) (应用层重定向)
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
Authentik Outpost Authentik Server
|
||||||
|
(proxy container) (Django)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **OAuth2/OIDC**: Gitea、HedgeDoc、Homepage、OpenWebUI 各自持有 client_id/secret,用户从应用发起登录
|
||||||
|
- **ForwardAuth**: SeaweedFS、Uptime Kuma 由 Traefik 中间件在请求到达前拦截验证
|
||||||
|
- **独立 Outpost**: SeaweedFS 和 Uptime Kuma 各用独立 proxy outpost 容器(避免 cookie domain 冲突)
|
||||||
|
|
||||||
## 目录结构
|
## 目录结构
|
||||||
|
|
||||||
```
|
```
|
||||||
homelab/
|
homelab/
|
||||||
├── compose.yml # 共享网络定义 (homelab_net)
|
├── compose.yml # 共享网络定义 (homelab_net)
|
||||||
├── .env # 统一环境变量(敏感,gitignore)
|
├── .env # 统一环境变量(敏感,gitignore)
|
||||||
|
├── authentik/
|
||||||
|
│ ├── compose.yml
|
||||||
|
│ └── data/
|
||||||
├── cloudflared/
|
├── cloudflared/
|
||||||
│ ├── compose.yml
|
│ ├── compose.yml
|
||||||
│ └── config.yml
|
│ └── config.yml
|
||||||
├── frpc/
|
├── frpc/
|
||||||
│ ├── compose.yml
|
│ ├── compose.yml
|
||||||
│ └── frpc.toml # 敏感,gitignore
|
│ └── frpc.toml # 敏感,gitignore
|
||||||
├── gitea/
|
├── gitea/
|
||||||
│ ├── compose.yml
|
│ ├── compose.yml
|
||||||
│ └── data/
|
│ └── data/
|
||||||
@@ -53,12 +85,25 @@ homelab/
|
|||||||
├── homepage/
|
├── homepage/
|
||||||
│ ├── compose.yml
|
│ ├── compose.yml
|
||||||
│ └── config/
|
│ └── config/
|
||||||
├── minio/
|
├── openwebui/
|
||||||
│ ├── compose.yml
|
│ ├── compose.yml
|
||||||
|
│ ├── .env # OPENWEBUI_SECRET_KEY
|
||||||
|
│ └── data/ # gitignore
|
||||||
|
├── outpost/
|
||||||
|
│ ├── compose.yml # Uptime Kuma outpost
|
||||||
|
│ └── ...
|
||||||
|
├── outpost-seaweedfs/
|
||||||
|
│ └── compose.yml # SeaweedFS 独立 outpost
|
||||||
|
├── remark42/
|
||||||
|
│ ├── compose.yml
|
||||||
|
│ └── var/ # gitignore
|
||||||
|
├── seaweedfs/
|
||||||
|
│ ├── compose.yml
|
||||||
|
│ ├── security.toml # JWT 已全部注释(社区版 UI 不支持 OIDC)
|
||||||
│ └── data/
|
│ └── data/
|
||||||
├── traefik/
|
├── traefik/
|
||||||
│ ├── compose.yml
|
│ ├── compose.yml
|
||||||
│ └── letsencrypt/ # gitignore
|
│ └── letsencrypt/ # gitignore
|
||||||
└── uptime-kuma/
|
└── uptime-kuma/
|
||||||
├── compose.yml
|
├── compose.yml
|
||||||
└── data/
|
└── data/
|
||||||
@@ -74,10 +119,16 @@ homelab/
|
|||||||
# 按依赖顺序启动
|
# 按依赖顺序启动
|
||||||
docker compose -f compose.yml up -d # 创建网络
|
docker compose -f compose.yml up -d # 创建网络
|
||||||
docker compose -f traefik/compose.yml up -d
|
docker compose -f traefik/compose.yml up -d
|
||||||
|
docker compose -f authentik/compose.yml up -d
|
||||||
docker compose -f gitea/compose.yml up -d
|
docker compose -f gitea/compose.yml up -d
|
||||||
docker compose -f hedgedoc/compose.yml up -d
|
docker compose -f hedgedoc/compose.yml up -d
|
||||||
|
docker compose -f seaweedfs/compose.yml up -d
|
||||||
docker compose -f uptime-kuma/compose.yml up -d
|
docker compose -f uptime-kuma/compose.yml up -d
|
||||||
docker compose -f homepage/compose.yml up -d
|
docker compose -f homepage/compose.yml up -d
|
||||||
|
docker compose -f openwebui/compose.yml up -d
|
||||||
|
docker compose -f remark42/compose.yml up -d
|
||||||
|
docker compose -f outpost/compose.yml up -d
|
||||||
|
docker compose -f outpost-seaweedfs/compose.yml up -d
|
||||||
docker compose -f cloudflared/compose.yml up -d
|
docker compose -f cloudflared/compose.yml up -d
|
||||||
docker compose -f frpc/compose.yml up -d
|
docker compose -f frpc/compose.yml up -d
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
services:
|
||||||
|
authentik:
|
||||||
|
image: ghcr.io/goauthentik/server:2026.5.0
|
||||||
|
container_name: authentik
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: postgres
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
||||||
|
AUTHENTIK_AVATARS: none
|
||||||
|
AUTHENTIK_LOG_LEVEL: info
|
||||||
|
AUTHENTIK_SECURITY__TRUSTED_PROXY_CIDR: 172.18.0.0/16
|
||||||
|
volumes:
|
||||||
|
- ./media:/media
|
||||||
|
- ./custom-templates:/templates
|
||||||
|
labels:
|
||||||
|
# --- Traefik 路由 ---
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.authentik.rule=Host(`auth.xiteng.site`)"
|
||||||
|
- "traefik.http.services.authentik.loadbalancer.server.port=9000"
|
||||||
|
- "traefik.http.routers.authentik.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.authentik.tls=true"
|
||||||
|
- "traefik.http.routers.authentik.tls.certresolver=cfresolver"
|
||||||
|
# 强制 X-Forwarded-Proto 为 https(Tunnel 走 HTTP:80 入口,Traefik 不知道外层是 HTTPS)
|
||||||
|
- "traefik.http.middlewares.force-https-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.routers.authentik.middlewares=force-https-headers"
|
||||||
|
- "traefik.http.routers.authentik-http.middlewares=force-https-headers"
|
||||||
|
# --- HTTP 入口 ---
|
||||||
|
- "traefik.http.routers.authentik-http.rule=Host(`auth.xiteng.site`)"
|
||||||
|
- "traefik.http.routers.authentik-http.service=authentik"
|
||||||
|
- "traefik.http.routers.authentik-http.entrypoints=web"
|
||||||
|
# --- Homepage ---
|
||||||
|
- "homepage.group=我的服务"
|
||||||
|
- "homepage.name=Authentik"
|
||||||
|
- "homepage.icon=authentik"
|
||||||
|
- "homepage.href=https://auth.xiteng.site"
|
||||||
|
- "homepage.description=统一认证"
|
||||||
|
# --- AutoKuma ---
|
||||||
|
- "kuma.authentik.http.name=Authentik"
|
||||||
|
- "kuma.authentik.http.url=http://authentik:9000/-/health/ready/"
|
||||||
|
- "kuma.authentik.http.interval=60"
|
||||||
|
- "kuma.authentik.http.max_retries=3"
|
||||||
|
networks:
|
||||||
|
- homelab_net
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: authentik-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: authentik
|
||||||
|
POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
||||||
|
POSTGRES_DB: authentik
|
||||||
|
volumes:
|
||||||
|
- ./pgdata:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- homelab_net
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
container_name: authentik-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./redis:/data
|
||||||
|
networks:
|
||||||
|
- homelab_net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
homelab_net:
|
||||||
|
external: true
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
cloudflared:
|
cloudflared:
|
||||||
image: cloudflare/cloudflared:latest
|
image: cloudflare/cloudflared:2025.5.0
|
||||||
container_name: cloudflared
|
container_name: cloudflared
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: tunnel --protocol http2 run
|
command: tunnel --protocol http2 run
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ services:
|
|||||||
- "traefik.tcp.routers.gitea-ssh.entrypoints=ssh"
|
- "traefik.tcp.routers.gitea-ssh.entrypoints=ssh"
|
||||||
- "traefik.tcp.services.gitea-ssh.loadbalancer.server.port=22"
|
- "traefik.tcp.services.gitea-ssh.loadbalancer.server.port=22"
|
||||||
# --- 2. Homepage 自动发现设置 ---
|
# --- 2. Homepage 自动发现设置 ---
|
||||||
- "homepage.group=生产力工具" # 分组名称
|
- "homepage.group=我的服务" # 分组名称
|
||||||
- "homepage.name=Gitea" # 显示名称
|
- "homepage.name=Gitea" # 显示名称
|
||||||
- "homepage.icon=gitea" # 图标 (支持 si, mdi 等前缀)
|
- "homepage.icon=gitea" # 图标 (支持 si, mdi 等前缀)
|
||||||
- "homepage.href=https://gitea.xiteng.site" # 点击跳转的链接
|
- "homepage.href=https://gitea.xiteng.site" # 点击跳转的链接
|
||||||
|
|||||||
+26
-9
@@ -1,8 +1,10 @@
|
|||||||
services:
|
services:
|
||||||
db:
|
hedgedoc-db:
|
||||||
image: postgres:11.6-alpine
|
image: postgres:16-alpine
|
||||||
env_file:
|
environment:
|
||||||
- ../.env
|
- POSTGRES_USER=$POSTGRES_USER
|
||||||
|
- POSTGRES_PASSWORD=$POSTGRES_PASSWORD
|
||||||
|
- POSTGRES_DB=$POSTGRES_DB
|
||||||
container_name: hedgedoc_db
|
container_name: hedgedoc_db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
@@ -14,17 +16,32 @@ services:
|
|||||||
image: quay.io/hedgedoc/hedgedoc:latest
|
image: quay.io/hedgedoc/hedgedoc:latest
|
||||||
container_name: hedgedoc
|
container_name: hedgedoc
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
|
||||||
- ../.env
|
|
||||||
environment:
|
environment:
|
||||||
|
- CMD_DB_HOST=hedgedoc_db
|
||||||
|
- CMD_DB_PORT=5432
|
||||||
|
- CMD_DB_DATABASE=$POSTGRES_DB
|
||||||
|
- CMD_DB_USERNAME=$POSTGRES_USER
|
||||||
|
- CMD_DB_PASSWORD=$POSTGRES_PASSWORD
|
||||||
|
- CMD_DB_DIALECT=postgres
|
||||||
- CMD_DOMAIN=notes.xiteng.site
|
- CMD_DOMAIN=notes.xiteng.site
|
||||||
- CMD_URL_ADDPORT=false
|
- CMD_URL_ADDPORT=false
|
||||||
- CMD_ALLOW_ORIGIN=localhost,notes.xiteng.site
|
- CMD_ALLOW_ORIGIN=localhost,notes.xiteng.site
|
||||||
- CMD_PROTOCOL_USESSL=true
|
- CMD_PROTOCOL_USESSL=true
|
||||||
|
- CMD_OAUTH2_PROVIDERNAME=Authentik
|
||||||
|
- CMD_OAUTH2_CLIENT_ID=hedgedoc-280baa8d
|
||||||
|
- CMD_OAUTH2_CLIENT_SECRET=0630f01b111d4ad68ff9b2d174028994decb5b55b51a4556bda24768d11b4586
|
||||||
|
- CMD_OAUTH2_AUTHORIZATION_URL=https://auth.xiteng.site/application/o/authorize/
|
||||||
|
- CMD_OAUTH2_TOKEN_URL=https://auth.xiteng.site/application/o/token/
|
||||||
|
- CMD_OAUTH2_USER_PROFILE_URL=https://auth.xiteng.site/application/o/userinfo/
|
||||||
|
- CMD_OAUTH2_SCOPE=openid profile email
|
||||||
|
- CMD_OAUTH2_ISSUER=https://auth.xiteng.site/application/o/hedgedoc/
|
||||||
|
- CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR=preferred_username
|
||||||
|
- CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR=name
|
||||||
|
- CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR=email
|
||||||
volumes:
|
volumes:
|
||||||
- ./uploads:/hedgedoc/public/uploads
|
- ./uploads:/hedgedoc/public/uploads
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- hedgedoc-db
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
labels:
|
labels:
|
||||||
@@ -46,9 +63,9 @@ services:
|
|||||||
- "traefik.http.routers.hedgedoc.tls=true"
|
- "traefik.http.routers.hedgedoc.tls=true"
|
||||||
- "traefik.http.routers.hedgedoc.tls.certresolver=cfresolver"
|
- "traefik.http.routers.hedgedoc.tls.certresolver=cfresolver"
|
||||||
# --- 2. Homepage 自动发现设置 ---
|
# --- 2. Homepage 自动发现设置 ---
|
||||||
- "homepage.group=生产力工具" # 分组名称
|
- "homepage.group=我的服务" # 分组名称
|
||||||
- "homepage.name=HedgeDoc" # 显示名称
|
- "homepage.name=HedgeDoc" # 显示名称
|
||||||
- "homepage.icon=hedgedoc" # 图标 (支持 si, mdi 等前缀)
|
- "homepage.icon=si-hedgedoc" # 图标 (支持 si, mdi 等前缀)
|
||||||
- "homepage.href=https://notes.xiteng.site" # 点击跳转的链接
|
- "homepage.href=https://notes.xiteng.site" # 点击跳转的链接
|
||||||
- "homepage.description=实时 Markdown 协作" # 副标题描述
|
- "homepage.description=实时 Markdown 协作" # 副标题描述
|
||||||
# --- 3. AutoKuma 自动发现设置 ---
|
# --- 3. AutoKuma 自动发现设置 ---
|
||||||
|
|||||||
+13
-1
@@ -5,11 +5,17 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./config:/app/config
|
- ./config:/app/config
|
||||||
|
- ./config/icons:/app/public/icons:ro
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
ports:
|
ports:
|
||||||
- "3003:3000"
|
- "3003:3000"
|
||||||
environment:
|
environment:
|
||||||
- HOMEPAGE_ALLOWED_HOSTS=home.xiteng.site,xiteng.site
|
- HOMEPAGE_ALLOWED_HOSTS=home.xiteng.site,xiteng.site
|
||||||
|
- HOMEPAGE_AUTH_PROVIDER=oidc
|
||||||
|
- HOMEPAGE_AUTH_OIDC_ISSUER=https://auth.xiteng.site/application/o/homepage/
|
||||||
|
- HOMEPAGE_AUTH_OIDC_CLIENT_ID=homepage-64bfd7a7
|
||||||
|
- HOMEPAGE_AUTH_OIDC_CLIENT_SECRET=b5d710941dba4a4694a92fe7bc381f3c853a248b5114467d9b82b0953928326b
|
||||||
|
- HOMEPAGE_AUTH_OIDC_SCOPE=openid profile email
|
||||||
labels:
|
labels:
|
||||||
# --- 1. Traefik 路由设置 ---
|
# --- 1. Traefik 路由设置 ---
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
@@ -29,7 +35,13 @@ services:
|
|||||||
# --- 新增:开启 TLS 并指定解析器 ---
|
# --- 新增:开启 TLS 并指定解析器 ---
|
||||||
- "traefik.http.routers.homepage.tls=true"
|
- "traefik.http.routers.homepage.tls=true"
|
||||||
- "traefik.http.routers.homepage.tls.certresolver=cfresolver"
|
- "traefik.http.routers.homepage.tls.certresolver=cfresolver"
|
||||||
# --- 3. AutoKuma 自动发现设置 ---
|
# --- 3. Homepage 自动发现设置 ---
|
||||||
|
- "homepage.group=我的服务"
|
||||||
|
- "homepage.name=HomePage"
|
||||||
|
- "homepage.icon=homepage"
|
||||||
|
- "homepage.href=https://home.xiteng.site"
|
||||||
|
- "homepage.description=导航主页"
|
||||||
|
# --- 4. AutoKuma 自动发现设置 ---
|
||||||
# 格式: kuma.<自定义ID>.<监控类型>.<属性>
|
# 格式: kuma.<自定义ID>.<监控类型>.<属性>
|
||||||
- "kuma.homepage.http.name=HomePage" # 监控项名称
|
- "kuma.homepage.http.name=HomePage" # 监控项名称
|
||||||
- "kuma.homepage.http.url=http://homepage:3000" # 内网直连
|
- "kuma.homepage.http.url=http://homepage:3000" # 内网直连
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Serve NVIDIA GPU stats as JSON for Homepage customapi widget."""
|
||||||
|
import subprocess, json
|
||||||
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
|
|
||||||
|
class GPUHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
try:
|
||||||
|
r = subprocess.run(
|
||||||
|
['nvidia-smi', '--query-gpu=utilization.gpu,memory.used,memory.total,temperature.gpu,fan.speed',
|
||||||
|
'--format=csv,noheader,nounits'],
|
||||||
|
capture_output=True, text=True, timeout=5
|
||||||
|
)
|
||||||
|
parts = [p.strip() for p in r.stdout.strip().split(',')]
|
||||||
|
data = {
|
||||||
|
'gpu_util': parts[0] + '%',
|
||||||
|
'mem_used': parts[1],
|
||||||
|
'mem_total': parts[2],
|
||||||
|
'mem': f'{parts[1]} / {parts[2]} MiB',
|
||||||
|
'temp': parts[3] + '°C',
|
||||||
|
'fan': parts[4] + '%',
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
data = {'error': str(e)}
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-Type', 'application/json')
|
||||||
|
self.send_header('Access-Control-Allow-Origin', '*')
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(json.dumps(data).encode())
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
pass # suppress logs
|
||||||
|
|
||||||
|
HTTPServer(('0.0.0.0', 9999), GPUHandler).serve_forever()
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
services:
|
|
||||||
minio:
|
|
||||||
image: minio/minio:latest
|
|
||||||
env_file:
|
|
||||||
- ../.env
|
|
||||||
container_name: minio
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
command: server /data --console-address ":9001"
|
|
||||||
ports:
|
|
||||||
- "9000:9000"
|
|
||||||
- "9001:9001"
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.minio.rule=Host(`minio.homelab`)"
|
|
||||||
- "traefik.http.services.minio.loadbalancer.server.port=9001"
|
|
||||||
networks:
|
|
||||||
- homelab_net
|
|
||||||
|
|
||||||
networks:
|
|
||||||
homelab_net:
|
|
||||||
external: true
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
services:
|
||||||
|
openwebui:
|
||||||
|
image: ghcr.io/open-webui/open-webui:v0.9.5
|
||||||
|
container_name: openwebui
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./data:/app/backend/data
|
||||||
|
environment:
|
||||||
|
# --- OIDC 认证 (Authentik) ---
|
||||||
|
- WEBUI_AUTH=true
|
||||||
|
- ENABLE_OAUTH_SIGNUP=true
|
||||||
|
- OAUTH_CLIENT_ID=openwebui-63f6865e
|
||||||
|
- OAUTH_CLIENT_SECRET=65cecaf8cc974c7fad55c749c65e50ee06bae0a9c8614252b4a44707a700c188
|
||||||
|
- OPENID_PROVIDER_URL=https://auth.xiteng.site/application/o/openwebui/.well-known/openid-configuration
|
||||||
|
- OAUTH_SCOPES=openid email profile
|
||||||
|
- OAUTH_PROVIDER_NAME=Authentik
|
||||||
|
- WEBUI_URL=https://ai.xiteng.site
|
||||||
|
# --- Session ---
|
||||||
|
- WEBUI_SECRET_KEY=${OPENWEBUI_SECRET_KEY}
|
||||||
|
# --- 网络 (解决国内 IPv6/ghcr 访问问题) ---
|
||||||
|
- HF_ENDPOINT=https://hf-mirror.com
|
||||||
|
dns:
|
||||||
|
- 223.5.5.5
|
||||||
|
- 114.114.114.114
|
||||||
|
labels:
|
||||||
|
# ========== Traefik ==========
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# HTTPS router (cert management)
|
||||||
|
- "traefik.http.routers.openwebui.rule=Host(`ai.xiteng.site`)"
|
||||||
|
- "traefik.http.routers.openwebui.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.openwebui.tls=true"
|
||||||
|
- "traefik.http.routers.openwebui.tls.certresolver=cfresolver"
|
||||||
|
- "traefik.http.services.openwebui.loadbalancer.server.port=8080"
|
||||||
|
# HTTP router (Cloudflare Tunnel ingress)
|
||||||
|
- "traefik.http.routers.openwebui-http.rule=Host(`ai.xiteng.site`)"
|
||||||
|
- "traefik.http.routers.openwebui-http.service=openwebui"
|
||||||
|
- "traefik.http.routers.openwebui-http.entrypoints=web"
|
||||||
|
# X-Forwarded-Proto middleware
|
||||||
|
- "traefik.http.middlewares.force-https.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.routers.openwebui.middlewares=force-https"
|
||||||
|
- "traefik.http.routers.openwebui-http.middlewares=force-https"
|
||||||
|
# ========== Homepage ==========
|
||||||
|
- "homepage.group=我的服务"
|
||||||
|
- "homepage.name=OpenWebUI"
|
||||||
|
- "homepage.icon=si-openwebui"
|
||||||
|
- "homepage.href=https://ai.xiteng.site"
|
||||||
|
- "homepage.description=AI Chat 界面"
|
||||||
|
# ========== AutoKuma ==========
|
||||||
|
- "kuma.openwebui.http.name=OpenWebUI"
|
||||||
|
- "kuma.openwebui.http.url=http://openwebui:8080"
|
||||||
|
- "kuma.openwebui.http.interval=60"
|
||||||
|
- "kuma.openwebui.http.max_retries=3"
|
||||||
|
networks:
|
||||||
|
- homelab_net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
homelab_net:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
outpost:
|
||||||
|
image: ghcr.io/goauthentik/proxy:2026.5.0
|
||||||
|
container_name: authentik-outpost-seaweedfs
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_HOST: https://auth.xiteng.site
|
||||||
|
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_SEAWEEDFS_TOKEN}
|
||||||
|
AUTHENTIK_INSECURE: "true"
|
||||||
|
ports:
|
||||||
|
- "9003:9000"
|
||||||
|
networks:
|
||||||
|
- homelab_net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
homelab_net:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
services:
|
||||||
|
outpost:
|
||||||
|
image: ghcr.io/goauthentik/proxy:2026.5.0
|
||||||
|
container_name: authentik-outpost
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_HOST: https://auth.xiteng.site
|
||||||
|
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}
|
||||||
|
AUTHENTIK_INSECURE: "true"
|
||||||
|
ports:
|
||||||
|
- "9002:9000"
|
||||||
|
- "9443:9443"
|
||||||
|
labels:
|
||||||
|
# --- Outpost 自身管理界面 ---
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.outpost.rule=Host(`outpost.xiteng.site`)"
|
||||||
|
- "traefik.http.services.outpost.loadbalancer.server.port=9000"
|
||||||
|
- "traefik.http.routers.outpost.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.outpost.tls=true"
|
||||||
|
- "traefik.http.routers.outpost.tls.certresolver=cfresolver"
|
||||||
|
- "traefik.http.routers.outpost-http.rule=Host(`outpost.xiteng.site`)"
|
||||||
|
- "traefik.http.routers.outpost-http.service=outpost"
|
||||||
|
- "traefik.http.routers.outpost-http.entrypoints=web"
|
||||||
|
networks:
|
||||||
|
- homelab_net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
homelab_net:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
services:
|
||||||
|
seaweedfs:
|
||||||
|
image: chrislusf/seaweedfs:latest
|
||||||
|
container_name: seaweedfs
|
||||||
|
restart: unless-stopped
|
||||||
|
command: "server -s3 -s3.port=8333 -master.port=9333 -volume.port=8080 -filer -filer.port=8888 -dir=/data -s3.domainName=file.xiteng.site"
|
||||||
|
environment:
|
||||||
|
- WEED_SECURITY_CONFIG=/etc/seaweedfs/security.toml
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./security.toml:/etc/seaweedfs/security.toml:ro
|
||||||
|
ports:
|
||||||
|
- "9333:9333" # master
|
||||||
|
- "8081:8080" # volume
|
||||||
|
- "8888:8888" # filer
|
||||||
|
- "8333:8333" # s3
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# --- Traefik: S3 Console (带 Authentik ForwardAuth) ---
|
||||||
|
- "traefik.http.routers.minio.rule=Host(`file.xiteng.site`)"
|
||||||
|
- "traefik.http.services.minio.loadbalancer.server.port=8888"
|
||||||
|
- "traefik.http.routers.minio.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.minio.tls=true"
|
||||||
|
- "traefik.http.routers.minio.tls.certresolver=cfresolver"
|
||||||
|
- "traefik.http.routers.minio-http.rule=Host(`file.xiteng.site`)"
|
||||||
|
- "traefik.http.routers.minio-http.service=minio"
|
||||||
|
- "traefik.http.routers.minio-http.entrypoints=web"
|
||||||
|
# --- ForwardAuth:显式转发 Cookie 头给 outpost ---
|
||||||
|
- "traefik.http.middlewares.minio-scheme.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.middlewares.minio-auth.forwardauth.address=http://authentik-outpost-seaweedfs:9000/outpost.goauthentik.io/auth/traefik"
|
||||||
|
- "traefik.http.middlewares.minio-auth.forwardauth.trustForwardHeader=true"
|
||||||
|
- "traefik.http.middlewares.minio-auth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name"
|
||||||
|
- "traefik.http.routers.minio.middlewares=minio-scheme,minio-auth"
|
||||||
|
- "traefik.http.routers.minio-http.middlewares=minio-scheme,minio-auth"
|
||||||
|
# --- Traefik: S3 API (8333) ---
|
||||||
|
- "traefik.http.routers.minio-api.rule=Host(`minio-api.xiteng.site`)"
|
||||||
|
- "traefik.http.services.minio-api.loadbalancer.server.port=8333"
|
||||||
|
- "traefik.http.routers.minio-api.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.minio-api.tls=true"
|
||||||
|
- "traefik.http.routers.minio-api.tls.certresolver=cfresolver"
|
||||||
|
- "traefik.http.routers.minio-api-http.rule=Host(`minio-api.xiteng.site`)"
|
||||||
|
- "traefik.http.routers.minio-api-http.service=minio-api"
|
||||||
|
- "traefik.http.routers.minio-api-http.entrypoints=web"
|
||||||
|
# --- Homepage ---
|
||||||
|
- "homepage.group=我的服务"
|
||||||
|
- "homepage.name=SeaweedFS"
|
||||||
|
- "homepage.icon=/icons/seaweedfs-local.png"
|
||||||
|
- "homepage.href=https://file.xiteng.site"
|
||||||
|
- "homepage.description=对象存储"
|
||||||
|
# --- AutoKuma ---
|
||||||
|
- "kuma.minio.http.name=SeaweedFS"
|
||||||
|
- "kuma.minio.http.url=http://seaweedfs:8888"
|
||||||
|
- "kuma.minio.http.interval=60"
|
||||||
|
- "kuma.minio.http.max_retries=3"
|
||||||
|
networks:
|
||||||
|
- homelab_net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
homelab_net:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Homelab Security Configuration
|
||||||
|
# All JWT sections are commented out — filer UI auth is handled by Authentik ForwardAuth.
|
||||||
|
# See README.md for architecture details.
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v3.6
|
image: traefik:v3.7
|
||||||
container_name: traefik
|
container_name: traefik
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: ../.env
|
env_file: ../.env
|
||||||
|
|||||||
@@ -17,14 +17,20 @@ services:
|
|||||||
- "traefik.http.routers.uptime.rule=Host(`uptime.xiteng.site`)"
|
- "traefik.http.routers.uptime.rule=Host(`uptime.xiteng.site`)"
|
||||||
- "traefik.http.services.uptime.loadbalancer.server.port=3001"
|
- "traefik.http.services.uptime.loadbalancer.server.port=3001"
|
||||||
- "traefik.http.routers.uptime.entrypoints=websecure"
|
- "traefik.http.routers.uptime.entrypoints=websecure"
|
||||||
|
# ForwardAuth via Authentik Outpost
|
||||||
|
- "traefik.http.middlewares.authentik-auth.forwardauth.address=http://authentik-outpost:9000/outpost.goauthentik.io/auth/traefik"
|
||||||
|
- "traefik.http.middlewares.authentik-auth.forwardauth.trustForwardHeader=true"
|
||||||
|
- "traefik.http.middlewares.authentik-auth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name"
|
||||||
|
- "traefik.http.routers.uptime.middlewares=authentik-auth"
|
||||||
|
- "traefik.http.routers.uptime-http.middlewares=authentik-auth"
|
||||||
- "traefik.http.routers.uptime-http.rule=Host(`uptime.xiteng.site`)"
|
- "traefik.http.routers.uptime-http.rule=Host(`uptime.xiteng.site`)"
|
||||||
- "traefik.http.routers.uptime-http.service=uptime"
|
- "traefik.http.routers.uptime-http.service=uptime"
|
||||||
- "traefik.http.routers.uptime-http.entrypoints=web"
|
- "traefik.http.routers.uptime-http.entrypoints=web"
|
||||||
- "traefik.http.routers.uptime.tls=true"
|
- "traefik.http.routers.uptime.tls=true"
|
||||||
- "traefik.http.routers.uptime.tls.certresolver=cfresolver"
|
- "traefik.http.routers.uptime.tls.certresolver=cfresolver"
|
||||||
- "homepage.group=生产力工具"
|
- "homepage.group=我的服务"
|
||||||
- "homepage.name=Uptime Kuma"
|
- "homepage.name=Uptime Kuma"
|
||||||
- "homepage.icon=uptime"
|
- "homepage.icon=uptime-kuma"
|
||||||
- "homepage.href=https://uptime.xiteng.site"
|
- "homepage.href=https://uptime.xiteng.site"
|
||||||
- "homepage.description=网站监控工具"
|
- "homepage.description=网站监控工具"
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
Reference in New Issue
Block a user