diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 35033e1..412b685 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,380 +1,128 @@ -# TODO管理系統 - 生產環境部署指南 +# TODO 管理系統 - 生產環境部署指南(最新架構) -## 📋 概述 +## 概述 -本文件提供TODO管理系統的完整生產環境部署指南,使用單一容器架構,簡化部署和維護。 +本文件說明最新部署架構:以 Nginx 為對外入口(Port 12011),反向代理至後端 Gunicorn(容器內 12011),前端由 Flask 靜態目錄提供。此架構提升穩定度與擴充性,支援約 200 位同時使用者。 -## 🏗️ 系統架構 +## 架構總覽 + +- 對外入口:Nginx(容器 `nginx`),監聽並對外開放 `12011` +- 應用服務:Flask + Gunicorn(容器 `todolist-app`),僅容器網路內提供 `12011` +- 前端:Next.js 靜態輸出,隨應用容器打包(Flask 靜態目錄 `frontend/out`) +- CORS:允許 `http://localhost:12011`、`http://127.0.0.1:12011` + +## 專案結構(摘要) ``` -┌─────────────────────────────────────┐ ┌─────────────────┐ -│ 單一容器應用 │ │ MySQL DB │ -│ ┌─────────────┐ ┌─────────────────┐ │ │ theaken.com │ -│ │Next.js 靜態 │ │ Flask API │ │◄───┤ Port: 33306 │ -│ │ 文件 │ │ Port: 12011 │ │ │ │ -│ └─────────────┘ └─────────────────┘ │ └─────────────────┘ -│ 統一 Port: 12011 │ -└─────────────────────────────────────┘ - │ - ▼ - ┌─────────────────┐ - │ LDAP/AD │ - │ panjit.com.tw │ - │ Port: 389 │ - └─────────────────┘ +TODOLIST/ +├─ backend/ # 後端程式(Flask) +│ ├─ app.py # Flask 應用(含 SPA 靜態路由) +│ └─ requirements.txt # Python 依賴 +├─ frontend/ # 前端(Next.js 靜態輸出) +├─ nginx/ +│ └─ nginx.conf # Nginx 反向代理設定(listen 12011) +├─ Dockerfile # 應用容器建置檔(含 Gunicorn 啟動) +├─ docker-compose.yml # Compose:nginx + todolist-app +└─ .env.production # 生產環境變數 ``` -## 🚀 快速部署 +## 主要環境變數(.env.production) -### Windows 環境 +- Database:`MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE` +- LDAP/AD:`LDAP_SERVER, LDAP_PORT, LDAP_USE_SSL, LDAP_SEARCH_BASE, LDAP_BIND_USER_DN, LDAP_BIND_USER_PASSWORD, LDAP_USER_LOGIN_ATTR` +- SMTP:`SMTP_SERVER, SMTP_PORT, SMTP_USE_TLS, SMTP_USE_SSL, SMTP_AUTH_REQUIRED, SMTP_SENDER_EMAIL, SMTP_SENDER_PASSWORD` +- Flask/JWT:`SECRET_KEY, JWT_SECRET_KEY` +- CORS:`CORS_ORIGINS=http://localhost:12011,http://127.0.0.1:12011` -```batch -# 1. 克隆專案(如果尚未克隆) -git clone -cd TODOLIST +## Docker 服務(最新) -# 2. 執行部署腳本 -deploy.bat +- `todolist-app`(應用容器) + - 對外不開放 Port;內部提供 `12011` + - 健康檢查:`GET /api/health/` + - 重啟策略:`unless-stopped` -# 或使用管理腳本 -manage.bat -``` +- `nginx`(反向代理) + - 對外 Port:`12011:12011` + - 代理規則:`/api/*` 與其餘路由 → `todolist-app:12011` + - 設定檔:`nginx/nginx.conf` -### Linux/Mac 環境 +## Gunicorn 生產設定(現行) + +Dockerfile 已內建以下啟動參數: ```bash -# 1. 克隆專案(如果尚未克隆) +--bind 0.0.0.0:12011 +--worker-class gthread +--workers 4 +--threads 8 +--timeout 120 +--keep-alive 10 +--max-requests 2000 +--max-requests-jitter 200 +--forwarded-allow-ips * +``` + +並發估算:4 workers × 8 threads ≈ 32 併發(可依 CPU 核心數調整)。 + +## 部署步驟 + +Windows: +```batch git clone cd TODOLIST +deploy.bat +``` -# 2. 設置執行權限並執行部署腳本 +Linux/Mac: +```bash +git clone +cd TODOLIST chmod +x deploy.sh ./deploy.sh ``` -## 📁 部署文件結構 - -``` -TODOLIST/ -├── backend/ # 後端代碼 -│ ├── app.py # Flask應用(含靜態文件服務) -│ ├── requirements.txt # Python依賴 -│ └── ... -├── frontend/ # 前端代碼 -│ ├── next.config.js # Next.js配置(靜態導出) -│ ├── package.json # Node.js依賴 -│ └── ... -├── Dockerfile # 單一容器構建文件 -├── docker-compose.yml # Docker Compose配置 -├── .env.production # 生產環境變量配置 -├── deploy.bat # Windows部署腳本 -├── deploy.sh # Linux/Mac部署腳本 -├── manage.bat # Windows管理腳本 -└── DEPLOYMENT.md # 部署說明文件 -``` - -## 🔧 環境配置 - -### 生產環境變量 (`.env.production`) - -本系統使用以下生產環境配置: - -#### 🗄️ 資料庫配置 -- **MySQL主機**: `mysql.theaken.com:33306` -- **資料庫**: `db_A060` -- **用戶**: `A060` - -#### 🔐 LDAP認證配置 -- **LDAP服務器**: `panjit.com.tw:389` -- **搜索基礎**: `OU=PANJIT,DC=panjit,DC=com,DC=tw` -- **認證方式**: Active Directory集成 - -#### 📧 郵件服務配置 -- **SMTP服務器**: `mail.panjit.com.tw:25` -- **發送者**: `todo-system@panjit.com.tw` - -#### 🌐 服務端口 -- **統一端口**: `12011` (前端 + 後端API) - -## 🐳 Docker配置 - -### 單一容器架構 - -**todolist-app**: 整合式應用容器 -- 端口映射: `12011:12011` -- 健康檢查: `/api/health` -- 自動重啟: `unless-stopped` -- 包含: Flask API + Next.js 靜態文件 - -### 構建過程 - -1. **階段1**: 構建 Next.js 靜態文件 -2. **階段2**: 設置 Flask 環境 + Gunicorn 生產服務器 -3. **階段3**: 複製靜態文件到 Flask 容器 -4. **最終**: 單一容器同時提供前後端服務 (Gunicorn驅動) - -### 生產服務器配置 - -**Gunicorn 配置參數**: +或直接使用 Compose: ```bash ---bind 0.0.0.0:12011 # 綁定地址和端口 ---workers 4 # 4個工作進程 ---threads 2 # 每進程2個線程 ---timeout 120 # 請求超時120秒 ---keep-alive 2 # 保持連線時間 ---max-requests 1000 # 進程處理請求上限後自動重啟 ---max-requests-jitter 100 # 隨機化重啟時機 +docker-compose up --build -d ``` -**總並發能力**: 4 workers × 2 threads = **8個同時請求** - -## 🔍 手動部署步驟 - -如果需要手動部署,請按以下步驟執行: - -### 1. 停止現有服務 +## 驗證與測試 ```bash -# 停止並移除現有容器 -docker-compose down +curl http://localhost:12011 # 前端首頁 +curl http://localhost:12011/api/health # 健康檢查 ``` -### 2. 建置Docker鏡像 +## 維運常用指令 ```bash -# 建置單一容器鏡像 -docker-compose build --no-cache -``` - -### 3. 啟動服務 - -```bash -# 使用Docker Compose啟動 -docker-compose up -d -``` - -### 4. 驗證部署 - -```bash -# 檢查容器狀態 docker-compose ps - -# 檢查服務健康 -curl http://localhost:12011/api/health -curl http://localhost:12011 -``` - -## 🧪 測試與驗證 - -### 服務訪問測試 - -```bash -# 前端頁面測試 -curl http://localhost:12011 - -# API健康檢查 -curl http://localhost:12011/api/health - -# API功能測試 -curl -X POST http://localhost:12011/api/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"test","password":"test"}' -``` - -## 🛠️ 維護指令 - -### 使用管理腳本 (Windows) - -```batch -# 執行管理腳本 -manage.bat - -# 選項包括: -# 1. 部署應用程式 -# 2. 停止服務 -# 3. 檢視服務狀態 -# 4. 檢視日誌 -# 5. 重啟服務 -# 6. 清理舊映像檔 -``` - -### 日誌查看 - -```bash -# 查看服務日誌 docker-compose logs -f - -# 查看最近日誌 -docker-compose logs --tail=50 -``` - -### 服務管理 - -```bash -# 重啟服務 docker-compose restart - -# 停止服務 -docker-compose down - -# 更新並重啟 docker-compose down docker-compose up -d --build -``` - -### 資源監控 - -```bash -# 查看容器狀態 -docker-compose ps - -# 查看資源使用 docker stats - -# 查看容器詳情 +docker inspect todolist-nginx docker inspect todolist-single-prod ``` -## 🚨 故障排除 +## 疑難排解(重點) -### 常見問題 +- 端口占用:`netstat -ano | findstr :12011` +- SPA 404:由 Flask 回傳 `index.html` 已處理;若異常請重建鏡像 +- 後端 URL 與重導:已加 `ProxyFix` 並信任代理標頭 +- 大量連線:由 Nginx 保持連線與緩衝,Gunicorn gthread 提升併發 -#### 1. 容器無法啟動 -```bash -# 檢查日誌 -docker-compose logs +## 安全建議 -# 檢查端口占用 -netstat -ano | findstr :12011 -``` +- 更換強度足夠的 `SECRET_KEY` 與 `JWT_SECRET_KEY` +- 若需 TLS/443,可在 `nginx/nginx.conf` 新增對應 server 與憑證設定 +- 適度設定 `client_max_body_size`、基本安全標頭與 Rate Limit(視需求) -#### 2. 靜態文件無法載入 -```bash -# 檢查文件是否正確複製 -docker exec -it todolist-single-prod ls -la /app/frontend/out +## 版本資訊(摘要) -# 重新構建並啟動 -docker-compose down -docker-compose up -d --build -``` +- 架構:Nginx 反向代理 + Gunicorn 應用容器(對外 Port 12011) +- 應用服務器:Gunicorn 21.2.0 +- 併發能力:預設約 32(可依硬體調整) +- 訪問端點:`http://localhost:12011` -#### 3. 資料庫連接失敗 -- 確認網路連通性到 `mysql.theaken.com:33306` -- 驗證資料庫憑證 -- 檢查防火牆設置 - -#### 4. LDAP認證失敗 -- 確認網路連通性到 `panjit.com.tw:389` -- 驗證LDAP服務帳號憑證 -- 檢查搜索基礎設置 - -#### 5. Dashboard/SPA頁面404錯誤 🆕 -**問題**: 前端SPA路由(如 `/todos/`, `/dashboard/`)返回404 JSON錯誤 -**原因**: Flask 404錯誤處理器攔截了所有404響應並返回JSON格式 -**解決方案**: -```bash -# 重新構建應用(此問題已在最新版本修復) -docker-compose down -docker-compose up -d --build -``` - -**技術詳情**: -- 修復了 `app.py` 中404錯誤處理器,只對API路徑返回JSON錯誤 -- 非API路徑(SPA路由)現在正確返回 `index.html` -- 修復了SPA路由處理邏輯,確保靜態文件與路由正確分離 - -#### 6. Flask開發服務器警告 (已升級為生產服務器) 🆕 -**問題**: 使用Flask開發服務器在生產環境,顯示警告且無法支撐多人使用 -**影響**: 200人規模使用時會出現嚴重延遲和請求超時 -**解決方案**: -```bash -# 系統已升級為Gunicorn生產服務器 -docker-compose down -docker-compose up -d --build -``` - -**升級詳情**: -- ✅ **Gunicorn生產服務器**: 4 workers × 2 threads = 8個同時請求處理能力 -- ✅ **支持200+用戶**: 完全滿足企業級使用需求 -- ✅ **自動重啟機制**: 防止記憶體洩漏,提高穩定性 -- ✅ **無開發服務器警告**: 生產就緒配置 -- ✅ **120秒超時設置**: 適合複雜查詢操作 -- ✅ **自動負載平衡**: 多進程處理請求分配 - -**性能對比**: -| 項目 | Flask開發服務器 | Gunicorn生產服務器 | -|------|----------------|-------------------| -| 並發處理 | 1個請求 | **8個同時請求** | -| 適用規模 | 5-10人 | **200+人** | -| 穩定性 | 低 | **高** | -| 生產就緒 | ❌ | **✅** | - -### 健康檢查端點 - -- **應用健康檢查**: `GET http://localhost:12011/api/health` -- **前端頁面檢查**: `GET http://localhost:12011` - -## 🔒 安全考量 - -### 生產環境安全設置 - -1. **更改默認密鑰**: - - 修改 `SECRET_KEY` 和 `JWT_SECRET_KEY` - - 使用強密碼策略 - -2. **網路安全**: - - 考慮使用反向代理(Nginx) - - 配置HTTPS證書 - - 限制外部訪問 - -3. **監控與日誌**: - - 設置日誌輪轉 - - 監控系統資源 - - 設置告警機制 - -## 📞 支援聯繫 - -- **系統管理員**: `ymirliu@panjit.com.tw` -- **技術支援**: 參考專案文檔或聯繫開發團隊 - -## 📝 版本資訊 - -- **系統版本**: 2.1.0 🆕 -- **架構**: 單一容器部署 -- **應用服務器**: Gunicorn 21.2.0 (生產級WSGI服務器) -- **並發能力**: 4 workers × 2 threads = 8個同時請求 -- **支持規模**: 200+用戶 -- **Docker映像**: `todolist-single:latest` -- **訪問地址**: `http://localhost:12011` - -### 🚀 v2.1.0 更新內容 -- ✅ 升級為Gunicorn生產服務器,支持大規模用戶使用 -- ✅ 修復SPA路由404錯誤問題 -- ✅ 優化Badge圓形顯示問題 -- ✅ 修復所有hardcoded API URL問題 -- ✅ 完善錯誤處理和健康檢查機制 - -## 🔄 從舊版本升級 - -如果從分離式部署升級: - -1. 停止舊的分離式服務 -```bash -docker stop todo-backend-prod todo-frontend-prod -docker rm todo-backend-prod todo-frontend-prod -``` - -2. 部署新的單一容器 -```bash -./deploy.sh # 或 deploy.bat -``` - -3. 驗證服務正常 -```bash -curl http://localhost:12011/api/health -curl http://localhost:12011 -``` - ---- - -**注意**: 本文件包含敏感配置資訊,請妥善保管,僅限授權人員查看。 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index da20c13..54405d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,4 +53,4 @@ HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=40s \ CMD curl -f http://localhost:12011/api/health/ || exit 1 # Run with Gunicorn for production (supports 200+ users) -CMD ["gunicorn", "--bind", "0.0.0.0:12011", "--workers", "4", "--threads", "2", "--timeout", "120", "--keep-alive", "2", "--max-requests", "1000", "--max-requests-jitter", "100", "app:app"] \ No newline at end of file +CMD ["gunicorn", "--bind", "0.0.0.0:12011", "--worker-class", "gthread", "--workers", "4", "--threads", "8", "--timeout", "120", "--keep-alive", "10", "--max-requests", "2000", "--max-requests-jitter", "200", "--forwarded-allow-ips", "*", "--access-logfile", "-", "app:app"] diff --git a/README.md b/README.md index 08661b6..5c46cfe 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ deploy.bat # Linux/macOS ./deploy.sh -# 或使用 Docker Compose +# 或使用 Docker Compose(包含 Nginx 反向代理,對外開放 12011) docker-compose up -d # 使用管理腳本 (Windows) @@ -221,8 +221,8 @@ manage.bat 2. **應用程式部署** - 設定反向代理 (Nginx/IIS) - - 應用服務: Port 12011 → 對外 Port 80/443 - - 配置 SSL 證書 + - 應用服務: Port 12011 → 對外 Port 12011(由 Nginx 監聽) + - 配置 SSL 證書(若需 443 可另行設定) - 設定生產環境變數 3. **背景服務設定** @@ -353,4 +353,3 @@ A: 確認 Next.js 構建正確完成,檢查 /app/frontend/out 目錄是否存 **Q: Excel 匯入失敗** A: 檢查文件格式和欄位映射,參考匯入模板 - diff --git a/backend/app.py b/backend/app.py index 2af3252..8f44d9a 100644 --- a/backend/app.py +++ b/backend/app.py @@ -2,6 +2,7 @@ import os import logging from datetime import datetime from flask import Flask, jsonify, send_from_directory, send_file, request +from werkzeug.middleware.proxy_fix import ProxyFix from flask_cors import CORS from flask_jwt_extended import JWTManager from jwt.exceptions import InvalidTokenError @@ -95,6 +96,9 @@ def create_app(config_name=None): else: return jsonify({'error': 'Not Found'}), 404 + # Trust proxy headers (for nginx) + app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1) + # Register error handlers register_error_handlers(app) @@ -182,4 +186,4 @@ app = create_app() if __name__ == '__main__': debug_mode = os.environ.get('FLASK_ENV') == 'development' - app.run(host='0.0.0.0', port=12011, debug=debug_mode) \ No newline at end of file + app.run(host='0.0.0.0', port=12011, debug=debug_mode) diff --git a/docker-compose.yml b/docker-compose.yml index aa32fe3..5f9d9c6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,8 +4,7 @@ services: context: . dockerfile: Dockerfile container_name: todolist-single-prod - ports: - - "12011:12011" + # No external port; only Nginx exposes ports environment: # MySQL Database Configuration - DATABASE_URL=mysql+pymysql://A060:WLeSCi0yhtc7@mysql.theaken.com:33306/db_A060 @@ -16,7 +15,7 @@ services: - MYSQL_DATABASE=db_A060 - MYSQL_CHARSET=utf8mb4 - # CORS Configuration (allow both localhost and 127.0.0.1) + # CORS Configuration (access via 12011) - CORS_ORIGINS=http://localhost:12011,http://127.0.0.1:12011 # LDAP Configuration (Production) @@ -47,7 +46,8 @@ services: - LOG_LEVEL=INFO # Frontend API URL (now pointing to same container) - - NEXT_PUBLIC_API_URL=http://localhost:12011 + # Frontend uses relative API path in build; this is unused in runtime + #- NEXT_PUBLIC_API_URL=http://localhost:12011 restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:12011/api/health/"] @@ -58,10 +58,23 @@ services: networks: - todolist-network + nginx: + image: nginx:1.25-alpine + container_name: todolist-nginx + depends_on: + - todolist-app + ports: + - "12011:12011" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + restart: unless-stopped + networks: + - todolist-network + networks: todolist-network: driver: bridge volumes: app-logs: - driver: local \ No newline at end of file + driver: local diff --git a/docs/DEPLOYMENT_NGINX_UPDATE.md b/docs/DEPLOYMENT_NGINX_UPDATE.md new file mode 100644 index 0000000..df9d032 --- /dev/null +++ b/docs/DEPLOYMENT_NGINX_UPDATE.md @@ -0,0 +1,40 @@ +# Nginx 反向代理與對外 Port 12011(部署更新) + +本專案現已於 Docker Compose 中加入 `nginx` 服務作為對外入口,並統一只開放 `12011`。此更新提升連線穩定度與可擴充性,適用約 200 名同時使用者。 + +## 架構與 Port +- `nginx`:對外 `12011:12011`,反向代理到 `todolist-app:12011`。 +- `todolist-app`:Flask API + 前端靜態檔;僅在容器網路內對 Nginx 提供服務。 +- 存取網址:`http://localhost:12011` +- CORS 預設允許:`http://localhost:12011`, `http://127.0.0.1:12011` + +## Gunicorn 參數(現行) +```bash +--bind 0.0.0.0:12011 +--worker-class gthread +--workers 4 +--threads 8 +--timeout 120 +--keep-alive 10 +--max-requests 2000 +--max-requests-jitter 200 +--forwarded-allow-ips * +``` +並發估算:4 workers × 8 threads ≈ 32(可依 CPU 調整)。 + +## Nginx 設定檔 +- 路徑:`nginx/nginx.conf` +- 監聽:`listen 12011;` +- 反代:`/api/*` 與其餘路由至 `todolist-app:12011` +- 已啟用 gzip、keepalive 與代理緩衝;可依需要擴充(例如 TLS/HTTP2、靜態快取) + +## 啟動 +```bash +docker-compose up --build -d +# 確認 +curl http://localhost:12011/api/health/ +``` + +## 備註 +- 若需 TLS/443,請在 `nginx/nginx.conf` 中加入對應的 server 區塊與憑證設定。 +- `todolist-app` 不再對外曝露 Port,請僅對外開放 12011。 diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index c77db77..23d3575 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -13,7 +13,6 @@ import { IconButton, Tooltip, Divider, - Badge, Chip, } from '@mui/material'; import { @@ -378,24 +377,26 @@ const Sidebar: React.FC = ({ collapsed, onToggleCollapse, onClose }} /> {item.badge && ( - + > + {item.badge} + )} )} @@ -634,4 +635,4 @@ const Sidebar: React.FC = ({ collapsed, onToggleCollapse, onClose ); }; -export default Sidebar; \ No newline at end of file +export default Sidebar; diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..a917bf8 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,77 @@ +user nginx; +worker_processes auto; + +events { + worker_connections 1024; + multi_accept on; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 4096; + + gzip on; + gzip_comp_level 5; + gzip_min_length 1024; + gzip_proxied any; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + upstream app_backend { + server todolist-app:12011 max_fails=3 fail_timeout=10s; + keepalive 64; + } + + server { + listen 12011; + server_name _; + + # Adjust as needed for uploads + client_max_body_size 20m; + + # Proxy API requests to Flask/Gunicorn + location /api/ { + proxy_pass http://app_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_read_timeout 120s; + proxy_send_timeout 120s; + proxy_connect_timeout 5s; + proxy_buffering on; + proxy_buffers 32 32k; + proxy_busy_buffers_size 64k; + } + + # All other routes (frontend SPA and static) via backend + # Optionally, later mount static and serve directly + location / { + proxy_pass http://app_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 120s; + proxy_send_timeout 120s; + proxy_connect_timeout 5s; + proxy_buffering on; + proxy_buffers 32 32k; + proxy_busy_buffers_size 64k; + } + } +}