{"repo": "bosens-china/blog", "files": {"apps/blog-server/.env.example": {"c93b26461d32bb4a85ea1744ee9f6bfd4a0a7414": {"t": 1785746730.6179855, "n": 982, "h": "1c36dfd5aa99d7bf", "c": "APP_NAME=\"Blog AI Server\"\nDEBUG=false\n\n# 登录用户限额\nENABLE_AI_RATE_LIMIT=true\nAI_DAILY_LIMIT_PER_USER=10\nCOMMENT_HOURLY_LIMIT_PER_USER=10\nCOMMENT_MODERATION_INTERVAL_SECONDS=3600\n\n# 输入与聊天历史\nMAX_MESSAGE_LENGTH=10000\nMAX_HISTORY_ROUNDS=10\nMAX_COMMENT_LENGTH=2000\n\n# 博客与请求来源\nALLOWED_ORIGINS=[\"http://localhost:4321\",\"http://127.0.0.1:4321\"]\nBLOG_FRONTEND_URL=http://localhost:4321\nBLOG_POSTS_BASE_URL=https://static.example.com/_posts/\nSESSION_COOKIE_SECURE=false\n\n# GitHub OAuth\nGITHUB_CLIENT_ID=\nGITHUB_CLIENT_SECRET=\nGITHUB_OAUTH_CALLBACK_URL=http://localhost:8000/api/auth/github/callback\nBLOG_AUTHOR_GITHUB_ID=\n\n# PostgreSQL 与 Redis\nPOSTGRES_PASSWORD=change-me\nDATABASE_URL=postgresql+asyncpg://blog:change-me@localhost:5543/blog\nREDIS_URL=redis://localhost:6380/0\n\n# 在线 LLM\nLLM_API_KEY=sk-xxxx\nLLM_API_BASE=https://api.deepseek.com\nLLM_API_MODEL=deepseek-v4-flash\nLLM_MAX_CONCURRENCY=200\n\n# Chrome Web Push\nVAPID_PUBLIC_KEY=\nVAPID_PRIVATE_KEY=\nVAPID_SUBJECT=mailto:admin@example.com\n"}, "f07934f70dffd655e9f364a7e6cb70bf5f36ac16": {"t": 1785767358.576812, "n": 982, "h": "1c36dfd5aa99d7bf", "c": "APP_NAME=\"Blog AI Server\"\nDEBUG=false\n\n# 登录用户限额\nENABLE_AI_RATE_LIMIT=true\nAI_DAILY_LIMIT_PER_USER=10\nCOMMENT_HOURLY_LIMIT_PER_USER=10\nCOMMENT_MODERATION_INTERVAL_SECONDS=3600\n\n# 输入与聊天历史\nMAX_MESSAGE_LENGTH=10000\nMAX_HISTORY_ROUNDS=10\nMAX_COMMENT_LENGTH=2000\n\n# 博客与请求来源\nALLOWED_ORIGINS=[\"http://localhost:4321\",\"http://127.0.0.1:4321\"]\nBLOG_FRONTEND_URL=http://localhost:4321\nBLOG_POSTS_BASE_URL=https://static.example.com/_posts/\nSESSION_COOKIE_SECURE=false\n\n# GitHub OAuth\nGITHUB_CLIENT_ID=\nGITHUB_CLIENT_SECRET=\nGITHUB_OAUTH_CALLBACK_URL=http://localhost:8000/api/auth/github/callback\nBLOG_AUTHOR_GITHUB_ID=\n\n# PostgreSQL 与 Redis\nPOSTGRES_PASSWORD=change-me\nDATABASE_URL=postgresql+asyncpg://blog:change-me@localhost:5543/blog\nREDIS_URL=redis://localhost:6380/0\n\n# 在线 LLM\nLLM_API_KEY=sk-xxxx\nLLM_API_BASE=https://api.deepseek.com\nLLM_API_MODEL=deepseek-v4-flash\nLLM_MAX_CONCURRENCY=200\n\n# Chrome Web Push\nVAPID_PUBLIC_KEY=\nVAPID_PRIVATE_KEY=\nVAPID_SUBJECT=mailto:admin@example.com\n"}, "19d8a30957226d5e0476922ba9405c031f816daf": {"t": 1785767360.2613735, "n": 892, "h": "364d72c84cb26bb4", "c": "APP_NAME=\"Blog AI Server\"\n# 生产环境必须为 false:DEBUG=true 会跳过所有 Origin/Referer 来源校验\nDEBUG=false\n\n# ===== 分层限流 =====\n# 生产环境必须为 true\nENABLE_RATE_LIMIT=true\n# 单 IP 每个窗口内的免费提问次数\nRATE_LIMIT_FREE_TIER=5\n# 配额窗口(秒),3600 = 每人每小时 5 次\nRATE_LIMIT_WINDOW=3600\n# 两次提问最小间隔(秒),0 关闭\nRATE_LIMIT_BURST_INTERVAL=3\n# 全站每日提问总上限(兜底 LLM 成本),按预算调整,0 关闭\nGLOBAL_DAILY_CAP=2000\n\n# ===== 输入约束 =====\n# 单条消息最大字符数\nMAX_MESSAGE_LENGTH=10000\n# 注入给 LLM 的最近历史轮数(1 轮 = 用户 + 助手 2 条)\nMAX_HISTORY_ROUNDS=10\n\n# 允许访问的域名,生产环境务必填写具体的博客域名,多个域名用逗号分隔\n# 示例: [\"https://blog.example.com\", \"http://localhost:4321\"]\nALLOWED_ORIGINS=[\"http://localhost:4321\"]\n\nREDIS_URL=\"redis://localhost:6379/0\"\n\n# OSS Data Source (AI 专用)\n# 必须配置,指向 OSS 上存储 posts/{id}.json 的基础路径\n# 请务必以斜杠结尾\nBLOG_POSTS_BASE_URL=\"https://static.your-blog.com/_posts/\"\n\nLLM_API_KEY=\"sk-xxxx\"\nLLM_API_BASE=\"https://api.deepseek.com\"\nLLM_API_MODEL=\"deepseek-chat\"\nLLM_MAX_CONCURRENCY=200\n"}, "00d6d7b52cd673ced30001025d2c7fee85446f60": {"t": 1785767361.4645653, "n": 868, "h": "b1d6c4c98f9285b2", "c": "APP_NAME=\"Blog AI Server\"\n# 生产环境必须为 false:DEBUG=true 会跳过所有 Origin/Referer 来源校验\nDEBUG=false\n\n# ===== 分层限流 =====\n# 生产环境必须为 true\nENABLE_RATE_LIMIT=true\n# 单 IP 每个窗口内的免费提问次数\nRATE_LIMIT_FREE_TIER=5\n# 配额窗口(秒),3600 = 每人每小时 5 次\nRATE_LIMIT_WINDOW=3600\n# 两次提问最小间隔(秒),0 关闭\nRATE_LIMIT_BURST_INTERVAL=3\n# 全站每日提问总上限(兜底 LLM 成本),按预算调整,0 关闭\nGLOBAL_DAILY_CAP=2000\n\n# ===== 输入约束 =====\n# 单条消息最大字符数\nMAX_MESSAGE_LENGTH=10000\n# 注入给 LLM 的最近历史轮数(1 轮 = 用户 + 助手 2 条)\nMAX_HISTORY_ROUNDS=10\n\n# 允许访问的域名,生产环境务必填写具体的博客域名,多个域名用逗号分隔\n# 示例: [\"https://blog.example.com\", \"http://localhost:4321\"]\nALLOWED_ORIGINS=[\"http://localhost:4321\"]\n\nREDIS_URL=\"redis://localhost:6379/0\"\n\n# OSS Data Source (AI 专用)\n# 必须配置,指向 OSS 上存储 posts/{id}.json 的基础路径\n# 请务必以斜杠结尾\nBLOG_POSTS_BASE_URL=\"https://static.your-blog.com/_posts/\"\n\nLLM_API_KEY=\"sk-xxxx\"\nLLM_API_BASE=\"https://api.deepseek.com\"\nLLM_API_MODEL=\"deepseek-chat\"\n"}, "43342d2487bfad3c60ab1a77af6793bbef286211": {"t": 1785767362.7511961, "n": 468, "h": "e194caa5f6127465", "c": "APP_NAME=\"Blog AI Server\"\nDEBUG=true\nENABLE_RATE_LIMIT=false\n\n# 允许访问的域名,生产环境务必填写具体的博客域名,多个域名用逗号分隔\n# 示例: [\"https://blog.example.com\", \"http://localhost:4321\"]\nALLOWED_ORIGINS=[\"http://localhost:4321\"]\n\nREDIS_URL=\"redis://localhost:6379/0\"\n\n# OSS Data Source (AI 专用)\n# 必须配置,指向 OSS 上存储 posts/{id}.json 的基础路径\n# 请务必以斜杠结尾\nBLOG_POSTS_BASE_URL=\"https://static.your-blog.com/_posts/\"\n\nLLM_API_KEY=\"sk-xxxx\"\nLLM_API_BASE=\"https://api.deepseek.com\"\nLLM_API_MODEL=\"deepseek-chat\"\n"}, "6fcb0ac0c0c267ecd5d7e4fd17f84791722b1bed": {"t": 1786067894.8851635, "n": 982, "h": "1c36dfd5aa99d7bf", "c": "APP_NAME=\"Blog AI Server\"\nDEBUG=false\n\n# 登录用户限额\nENABLE_AI_RATE_LIMIT=true\nAI_DAILY_LIMIT_PER_USER=10\nCOMMENT_HOURLY_LIMIT_PER_USER=10\nCOMMENT_MODERATION_INTERVAL_SECONDS=3600\n\n# 输入与聊天历史\nMAX_MESSAGE_LENGTH=10000\nMAX_HISTORY_ROUNDS=10\nMAX_COMMENT_LENGTH=2000\n\n# 博客与请求来源\nALLOWED_ORIGINS=[\"http://localhost:4321\",\"http://127.0.0.1:4321\"]\nBLOG_FRONTEND_URL=http://localhost:4321\nBLOG_POSTS_BASE_URL=https://static.example.com/_posts/\nSESSION_COOKIE_SECURE=false\n\n# GitHub OAuth\nGITHUB_CLIENT_ID=\nGITHUB_CLIENT_SECRET=\nGITHUB_OAUTH_CALLBACK_URL=http://localhost:8000/api/auth/github/callback\nBLOG_AUTHOR_GITHUB_ID=\n\n# PostgreSQL 与 Redis\nPOSTGRES_PASSWORD=change-me\nDATABASE_URL=postgresql+asyncpg://blog:change-me@localhost:5543/blog\nREDIS_URL=redis://localhost:6380/0\n\n# 在线 LLM\nLLM_API_KEY=sk-xxxx\nLLM_API_BASE=https://api.deepseek.com\nLLM_API_MODEL=deepseek-v4-flash\nLLM_MAX_CONCURRENCY=200\n\n# Chrome Web Push\nVAPID_PUBLIC_KEY=\nVAPID_PRIVATE_KEY=\nVAPID_SUBJECT=mailto:admin@example.com\n"}}, "apps/blog-server/docker-compose.yml": {"c93b26461d32bb4a85ea1744ee9f6bfd4a0a7414": {"t": 1785747419.0043972, "n": 2488, "h": "37187abad73ae41a", "c": "services:\n server:\n image: boses/ask-ai:latest\n networks:\n - web_network\n environment:\n - TZ=Asia/Shanghai\n - DEBUG=false\n - ENABLE_AI_RATE_LIMIT=true\n - REDIS_URL=redis://redis:6379/0\n - DATABASE_URL=postgresql+asyncpg://blog:${POSTGRES_PASSWORD}@postgres:5432/blog\n # 下面这些变量会自动读取同级目录下的 .env 文件\n - LLM_API_KEY=${LLM_API_KEY}\n - LLM_API_BASE=${LLM_API_BASE:-https://api.deepseek.com}\n - LLM_API_MODEL=${LLM_API_MODEL:-deepseek-v4-flash}\n - LLM_MAX_CONCURRENCY=${LLM_MAX_CONCURRENCY:-200}\n - AI_DAILY_LIMIT_PER_USER=${AI_DAILY_LIMIT_PER_USER:-10}\n - COMMENT_HOURLY_LIMIT_PER_USER=${COMMENT_HOURLY_LIMIT_PER_USER:-10}\n - COMMENT_MODERATION_INTERVAL_SECONDS=${COMMENT_MODERATION_INTERVAL_SECONDS:-3600}\n - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY}\n - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY}\n - VAPID_SUBJECT=${VAPID_SUBJECT}\n - ALLOWED_ORIGINS=${ALLOWED_ORIGINS}\n - BLOG_POSTS_BASE_URL=${BLOG_POSTS_BASE_URL}\n - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}\n - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}\n - GITHUB_OAUTH_CALLBACK_URL=${GITHUB_OAUTH_CALLBACK_URL}\n - BLOG_AUTHOR_GITHUB_ID=${BLOG_AUTHOR_GITHUB_ID}\n - BLOG_FRONTEND_URL=${BLOG_FRONTEND_URL}\n - SESSION_COOKIE_SECURE=${SESSION_COOKIE_SECURE:-true}\n labels:\n caddy: ask-ai.xiaowo.live\n caddy.reverse_proxy: '{{upstreams 8000}}'\n # 用 Caddy 看到的真实对端 IP 覆写 X-Real-IP,限流据此识别客户端。\n # 服务无对外端口、仅内网可达,客户端无法伪造此头。\n caddy.reverse_proxy.header_up: 'X-Real-IP {remote_host}'\n depends_on:\n redis:\n condition: service_healthy\n postgres:\n condition: service_healthy\n restart: always # 服务器重启后自动拉起\n\n redis:\n image: redis:7.2-alpine\n environment:\n - TZ=Asia/Shanghai\n volumes:\n - redis_data:/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 10s\n timeout: 3s\n retries: 5\n\n postgres:\n image: postgres:17-alpine\n environment:\n - POSTGRES_DB=blog\n - POSTGRES_USER=blog\n - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n volumes:\n - postgres_data:/var/lib/postgresql/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U blog -d blog']\n interval: 10s\n timeout: 5s\n retries: 5\n\nvolumes:\n redis_data:\n postgres_data:\n\nnetworks:\n web_network:\n external: true\n"}, "f07934f70dffd655e9f364a7e6cb70bf5f36ac16": {"t": 1785767358.2733836, "n": 2488, "h": "37187abad73ae41a", "c": "services:\n server:\n image: boses/ask-ai:latest\n networks:\n - web_network\n environment:\n - TZ=Asia/Shanghai\n - DEBUG=false\n - ENABLE_AI_RATE_LIMIT=true\n - REDIS_URL=redis://redis:6379/0\n - DATABASE_URL=postgresql+asyncpg://blog:${POSTGRES_PASSWORD}@postgres:5432/blog\n # 下面这些变量会自动读取同级目录下的 .env 文件\n - LLM_API_KEY=${LLM_API_KEY}\n - LLM_API_BASE=${LLM_API_BASE:-https://api.deepseek.com}\n - LLM_API_MODEL=${LLM_API_MODEL:-deepseek-v4-flash}\n - LLM_MAX_CONCURRENCY=${LLM_MAX_CONCURRENCY:-200}\n - AI_DAILY_LIMIT_PER_USER=${AI_DAILY_LIMIT_PER_USER:-10}\n - COMMENT_HOURLY_LIMIT_PER_USER=${COMMENT_HOURLY_LIMIT_PER_USER:-10}\n - COMMENT_MODERATION_INTERVAL_SECONDS=${COMMENT_MODERATION_INTERVAL_SECONDS:-3600}\n - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY}\n - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY}\n - VAPID_SUBJECT=${VAPID_SUBJECT}\n - ALLOWED_ORIGINS=${ALLOWED_ORIGINS}\n - BLOG_POSTS_BASE_URL=${BLOG_POSTS_BASE_URL}\n - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}\n - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}\n - GITHUB_OAUTH_CALLBACK_URL=${GITHUB_OAUTH_CALLBACK_URL}\n - BLOG_AUTHOR_GITHUB_ID=${BLOG_AUTHOR_GITHUB_ID}\n - BLOG_FRONTEND_URL=${BLOG_FRONTEND_URL}\n - SESSION_COOKIE_SECURE=${SESSION_COOKIE_SECURE:-true}\n labels:\n caddy: ask-ai.xiaowo.live\n caddy.reverse_proxy: '{{upstreams 8000}}'\n # 用 Caddy 看到的真实对端 IP 覆写 X-Real-IP,限流据此识别客户端。\n # 服务无对外端口、仅内网可达,客户端无法伪造此头。\n caddy.reverse_proxy.header_up: 'X-Real-IP {remote_host}'\n depends_on:\n redis:\n condition: service_healthy\n postgres:\n condition: service_healthy\n restart: always # 服务器重启后自动拉起\n\n redis:\n image: redis:7.2-alpine\n environment:\n - TZ=Asia/Shanghai\n volumes:\n - redis_data:/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 10s\n timeout: 3s\n retries: 5\n\n postgres:\n image: postgres:17-alpine\n environment:\n - POSTGRES_DB=blog\n - POSTGRES_USER=blog\n - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n volumes:\n - postgres_data:/var/lib/postgresql/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U blog -d blog']\n interval: 10s\n timeout: 5s\n retries: 5\n\nvolumes:\n redis_data:\n postgres_data:\n\nnetworks:\n web_network:\n external: true\n"}, "19d8a30957226d5e0476922ba9405c031f816daf": {"t": 1785767359.486189, "n": 2268, "h": "83b48cae2d71bbfd", "c": "services:\n server:\n image: boses/ask-ai:latest\n networks:\n - web_network\n environment:\n - TZ=Asia/Shanghai\n - REDIS_URL=redis://redis:6379/0\n - DATABASE_URL=postgresql+asyncpg://blog:${POSTGRES_PASSWORD}@postgres:5432/blog\n # 下面这些变量会自动读取同级目录下的 .env 文件\n - LLM_API_KEY=${LLM_API_KEY}\n - LLM_API_MODEL=${LLM_API_MODEL:-deepseek-v4-flash}\n - LLM_MAX_CONCURRENCY=${LLM_MAX_CONCURRENCY:-200}\n - COMMENT_HOURLY_LIMIT=${COMMENT_HOURLY_LIMIT:-10}\n - COMMENT_MODERATION_INTERVAL_SECONDS=${COMMENT_MODERATION_INTERVAL_SECONDS:-3600}\n - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY}\n - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY}\n - VAPID_SUBJECT=${VAPID_SUBJECT}\n - ALLOWED_ORIGINS=${ALLOWED_ORIGINS}\n - BLOG_POSTS_BASE_URL=${BLOG_POSTS_BASE_URL}\n - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}\n - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}\n - GITHUB_CALLBACK_URL=${GITHUB_CALLBACK_URL}\n - BLOG_AUTHOR_GITHUB_ID=${BLOG_AUTHOR_GITHUB_ID}\n - FRONTEND_URL=${FRONTEND_URL}\n - SESSION_COOKIE_SECURE=${SESSION_COOKIE_SECURE:-true}\n labels:\n caddy: ask-ai.xiaowo.live\n caddy.reverse_proxy: '{{upstreams 8000}}'\n # 用 Caddy 看到的真实对端 IP 覆写 X-Real-IP,限流据此识别客户端。\n # 服务无对外端口、仅内网可达,客户端无法伪造此头。\n caddy.reverse_proxy.header_up: 'X-Real-IP {remote_host}'\n depends_on:\n redis:\n condition: service_healthy\n postgres:\n condition: service_healthy\n restart: always # 服务器重启后自动拉起\n\n redis:\n image: redis:7.2-alpine\n environment:\n - TZ=Asia/Shanghai\n volumes:\n - redis_data:/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 10s\n timeout: 3s\n retries: 5\n\n postgres:\n image: postgres:17-alpine\n environment:\n - POSTGRES_DB=blog\n - POSTGRES_USER=blog\n - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n volumes:\n - postgres_data:/var/lib/postgresql/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U blog -d blog']\n interval: 10s\n timeout: 5s\n retries: 5\n\nvolumes:\n redis_data:\n postgres_data:\n\nnetworks:\n web_network:\n external: true\n"}, "0f06080ccc10bf897a1d70f8aa5e66deff0ff485": {"t": 1785767360.7744937, "n": 2212, "h": "b9da3047614176f9", "c": "services:\n server:\n image: boses/ask-ai:latest\n networks:\n - web_network\n environment:\n - TZ=Asia/Shanghai\n - REDIS_URL=redis://redis:6379/0\n - DATABASE_URL=postgresql+asyncpg://blog:${POSTGRES_PASSWORD}@postgres:5432/blog\n # 下面这些变量会自动读取同级目录下的 .env 文件\n - LLM_API_KEY=${LLM_API_KEY}\n - LLM_API_MODEL=${LLM_API_MODEL:-deepseek-v4-flash}\n - COMMENT_HOURLY_LIMIT=${COMMENT_HOURLY_LIMIT:-10}\n - COMMENT_MODERATION_INTERVAL_SECONDS=${COMMENT_MODERATION_INTERVAL_SECONDS:-3600}\n - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY}\n - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY}\n - VAPID_SUBJECT=${VAPID_SUBJECT}\n - ALLOWED_ORIGINS=${ALLOWED_ORIGINS}\n - BLOG_POSTS_BASE_URL=${BLOG_POSTS_BASE_URL}\n - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}\n - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}\n - GITHUB_CALLBACK_URL=${GITHUB_CALLBACK_URL}\n - BLOG_AUTHOR_GITHUB_ID=${BLOG_AUTHOR_GITHUB_ID}\n - FRONTEND_URL=${FRONTEND_URL}\n - SESSION_COOKIE_SECURE=${SESSION_COOKIE_SECURE:-true}\n labels:\n caddy: ask-ai.xiaowo.live\n caddy.reverse_proxy: '{{upstreams 8000}}'\n # 用 Caddy 看到的真实对端 IP 覆写 X-Real-IP,限流据此识别客户端。\n # 服务无对外端口、仅内网可达,客户端无法伪造此头。\n caddy.reverse_proxy.header_up: 'X-Real-IP {remote_host}'\n depends_on:\n redis:\n condition: service_healthy\n postgres:\n condition: service_healthy\n restart: always # 服务器重启后自动拉起\n\n redis:\n image: redis:7.2-alpine\n environment:\n - TZ=Asia/Shanghai\n volumes:\n - redis_data:/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 10s\n timeout: 3s\n retries: 5\n\n postgres:\n image: postgres:17-alpine\n environment:\n - POSTGRES_DB=blog\n - POSTGRES_USER=blog\n - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n volumes:\n - postgres_data:/var/lib/postgresql/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U blog -d blog']\n interval: 10s\n timeout: 5s\n retries: 5\n\nvolumes:\n redis_data:\n postgres_data:\n\nnetworks:\n web_network:\n external: true\n"}, "00d6d7b52cd673ced30001025d2c7fee85446f60": {"t": 1785767362.0128858, "n": 907, "h": "30b62cbb3e84bcbe", "c": "services:\n server:\n image: boses/ask-ai:latest\n networks:\n - web_network\n environment:\n - TZ=Asia/Shanghai\n - REDIS_URL=redis://redis:6379/0\n # 下面这些变量会自动读取同级目录下的 .env 文件\n - LLM_API_KEY=${LLM_API_KEY}\n - ALLOWED_ORIGINS=${ALLOWED_ORIGINS}\n - BLOG_POSTS_BASE_URL=${BLOG_POSTS_BASE_URL}\n labels:\n caddy: ask-ai.xiaowo.live\n caddy.reverse_proxy: '{{upstreams 8000}}'\n # 用 Caddy 看到的真实对端 IP 覆写 X-Real-IP,限流据此识别客户端。\n # 服务无对外端口、仅内网可达,客户端无法伪造此头。\n caddy.reverse_proxy.header_up: 'X-Real-IP {remote_host}'\n depends_on:\n - redis\n restart: always # 服务器重启后自动拉起\n\n redis:\n image: redis:7.2-alpine\n # 不映射端口,仅内部 server 可访问,防止被外部直连\n environment:\n - TZ=Asia/Shanghai\n volumes:\n - redis_data:/data\n networks:\n - web_network\n restart: always\n\nvolumes:\n redis_data:\n\nnetworks:\n web_network:\n external: true\n"}, "d3e87470bb61406141904e0add627e1bc50de617": {"t": 1785767363.353377, "n": 525, "h": "61d2d6fd5d7f2542", "c": "version: '3.8'\n\nservices:\n server:\n image: boses/ask-ai:latest\n ports:\n - '8000:8000'\n environment:\n - REDIS_URL=redis://redis:6379/0\n - LLM_API_KEY=${LLM_API_KEY}\n - ALLOWED_ORIGINS=${ALLOWED_ORIGINS}\n - BLOG_POSTS_BASE_URL=${BLOG_POSTS_BASE_URL}\n\n depends_on:\n - redis\n volumes:\n - ./src:/app/src\n restart: on-failure\n\n redis:\n image: redis:7.2-alpine\n ports:\n - '6379:6379'\n volumes:\n - redis_data:/data\n restart: always\n\nvolumes:\n redis_data:\n"}, "43342d2487bfad3c60ab1a77af6793bbef286211": {"t": 1785767364.7419372, "n": 420, "h": "a0e29d27cc54ac8a", "c": "version: '3.8'\n\nservices:\n # server:\n # build: .\n # ports:\n # - \"8000:8000\"\n # environment:\n # - REDIS_URL=redis://redis:6379/0\n # - DEBUG=true\n # depends_on:\n # - redis\n # volumes:\n # - ./src:/app/src\n # restart: on-failure\n\n redis:\n image: redis:7.2-alpine\n ports:\n - '6379:6379'\n volumes:\n - redis_data:/data\n restart: always\n\nvolumes:\n redis_data:\n"}, "6fcb0ac0c0c267ecd5d7e4fd17f84791722b1bed": {"t": 1786068167.2082, "n": 2488, "h": "37187abad73ae41a", "c": "services:\n server:\n image: boses/ask-ai:latest\n networks:\n - web_network\n environment:\n - TZ=Asia/Shanghai\n - DEBUG=false\n - ENABLE_AI_RATE_LIMIT=true\n - REDIS_URL=redis://redis:6379/0\n - DATABASE_URL=postgresql+asyncpg://blog:${POSTGRES_PASSWORD}@postgres:5432/blog\n # 下面这些变量会自动读取同级目录下的 .env 文件\n - LLM_API_KEY=${LLM_API_KEY}\n - LLM_API_BASE=${LLM_API_BASE:-https://api.deepseek.com}\n - LLM_API_MODEL=${LLM_API_MODEL:-deepseek-v4-flash}\n - LLM_MAX_CONCURRENCY=${LLM_MAX_CONCURRENCY:-200}\n - AI_DAILY_LIMIT_PER_USER=${AI_DAILY_LIMIT_PER_USER:-10}\n - COMMENT_HOURLY_LIMIT_PER_USER=${COMMENT_HOURLY_LIMIT_PER_USER:-10}\n - COMMENT_MODERATION_INTERVAL_SECONDS=${COMMENT_MODERATION_INTERVAL_SECONDS:-3600}\n - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY}\n - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY}\n - VAPID_SUBJECT=${VAPID_SUBJECT}\n - ALLOWED_ORIGINS=${ALLOWED_ORIGINS}\n - BLOG_POSTS_BASE_URL=${BLOG_POSTS_BASE_URL}\n - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}\n - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}\n - GITHUB_OAUTH_CALLBACK_URL=${GITHUB_OAUTH_CALLBACK_URL}\n - BLOG_AUTHOR_GITHUB_ID=${BLOG_AUTHOR_GITHUB_ID}\n - BLOG_FRONTEND_URL=${BLOG_FRONTEND_URL}\n - SESSION_COOKIE_SECURE=${SESSION_COOKIE_SECURE:-true}\n labels:\n caddy: ask-ai.xiaowo.live\n caddy.reverse_proxy: '{{upstreams 8000}}'\n # 用 Caddy 看到的真实对端 IP 覆写 X-Real-IP,限流据此识别客户端。\n # 服务无对外端口、仅内网可达,客户端无法伪造此头。\n caddy.reverse_proxy.header_up: 'X-Real-IP {remote_host}'\n depends_on:\n redis:\n condition: service_healthy\n postgres:\n condition: service_healthy\n restart: always # 服务器重启后自动拉起\n\n redis:\n image: redis:7.2-alpine\n environment:\n - TZ=Asia/Shanghai\n volumes:\n - redis_data:/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD', 'redis-cli', 'ping']\n interval: 10s\n timeout: 3s\n retries: 5\n\n postgres:\n image: postgres:17-alpine\n environment:\n - POSTGRES_DB=blog\n - POSTGRES_USER=blog\n - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n volumes:\n - postgres_data:/var/lib/postgresql/data\n networks:\n - web_network\n restart: always\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U blog -d blog']\n interval: 10s\n timeout: 5s\n retries: 5\n\nvolumes:\n redis_data:\n postgres_data:\n\nnetworks:\n web_network:\n external: true\n"}}}}