diff --git a/NGINX_SETUP.md b/NGINX_SETUP.md new file mode 100644 index 0000000..de59f0b --- /dev/null +++ b/NGINX_SETUP.md @@ -0,0 +1,168 @@ +# Настройка с Nginx + Frontend + +## Архитектура + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ Browser │───▶│ Nginx │───▶│ MC Panel │ +│ │ │ │ │ (API only) │ +└─────────────┘ └─────────────┘ └─────────────┘ + │ + ▼ + ┌─────────────┐ + │ Frontend │ + │ (Static) │ + └─────────────┘ +``` + +- **Nginx**: Раздает статические файлы frontend + проксирует API запросы +- **MC Panel**: Только API backend (порт 8000, внутренний) +- **Frontend**: Собирается в Docker и копируется в nginx + +## Файлы + +### 1. ✅ Dockerfile +Уже настроен для многоэтапной сборки: +- Stage 1: Собирает frontend (`npm run build`) +- Stage 2: Python backend + статические файлы + +### 2. ✅ nginx/default.conf +Полная nginx конфигурация: +- Раздача статических файлов из `/usr/share/nginx/html` +- Проксирование `/api/*` на backend +- WebSocket поддержка для `/ws/*` +- Gzip сжатие +- Кэширование статики + +### 3. ✅ docker-compose-nginx.yml +- `mc-panel`: Backend API (внутренний порт 8000) +- `nginx`: Статика + reverse proxy (порт 80) +- `frontend-init`: Init контейнер для копирования статики + +## Запуск + +### Подготовка + +```bash +# 1. Создать папку data +mkdir -p data +cat > data/users.json << 'EOF' +{"admin":{"username":"admin","password":"$2b$12$PAaomoUWn3Ip5ov.S/uYPeTIRiDMq7DbA57ahyYQnw3QHT2zuYMlG","role":"owner","servers":[],"permissions":{"manage_users":true,"manage_roles":true,"manage_servers":true,"manage_tickets":true,"manage_files":true,"delete_users":true,"view_all_resources":true},"resource_access":{"servers":[],"tickets":[],"files":[]}}} +EOF +echo '{}' > data/tickets.json +echo '{}' > data/daemons.json + +# 2. Скопировать файлы: +# - docker-compose-nginx.yml +# - nginx/default.conf (обновленный) +# - backend/daemons.py (обновленный) +``` + +### Запуск + +```bash +# Остановить старые контейнеры +docker compose down + +# Запустить с nginx +docker compose -f docker-compose-nginx.yml up --build -d +``` + +### Проверка + +```bash +# Статус контейнеров +docker compose -f docker-compose-nginx.yml ps + +# Логи +docker compose -f docker-compose-nginx.yml logs nginx +docker compose -f docker-compose-nginx.yml logs mc-panel + +# Проверка API +curl http://localhost/api/auth/oidc/providers + +# Проверка frontend +curl http://localhost/ +``` + +## Что происходит + +1. **Сборка**: + - Frontend собирается в `/app/frontend/dist` + - Backend копируется в `/app/backend` + +2. **Инициализация**: + - `frontend-init` копирует статику в volume `frontend-static` + - Завершается после копирования + +3. **Nginx**: + - Монтирует volume `frontend-static` в `/usr/share/nginx/html` + - Раздает статические файлы + - Проксирует `/api/*` на `mc-panel:8000` + +4. **Backend**: + - Запускается на внутреннем порту 8000 + - Доступен только через nginx + +## Преимущества + +✅ **Производительность**: Nginx раздает статику быстрее +✅ **Кэширование**: Статические файлы кэшируются +✅ **Сжатие**: Gzip для всех файлов +✅ **Безопасность**: Backend недоступен извне +✅ **Масштабируемость**: Можно добавить SSL, балансировку + +## Отладка + +### Nginx не запускается + +```bash +# Проверить конфигурацию +docker compose -f docker-compose-nginx.yml exec nginx nginx -t + +# Проверить файлы +docker compose -f docker-compose-nginx.yml exec nginx ls -la /usr/share/nginx/html +``` + +### Frontend не загружается + +```bash +# Проверить статические файлы +docker compose -f docker-compose-nginx.yml exec nginx ls -la /usr/share/nginx/html + +# Проверить логи init контейнера +docker compose -f docker-compose-nginx.yml logs frontend-init +``` + +### API не работает + +```bash +# Проверить backend +docker compose -f docker-compose-nginx.yml exec mc-panel curl http://localhost:8000/api/auth/oidc/providers + +# Проверить проксирование +curl -v http://localhost/api/auth/oidc/providers +``` + +## Альтернативные варианты + +### Вариант 1: Простой (без nginx) +Используйте `docker-compose-linux.yml` - backend раздает всё сам + +### Вариант 2: Nginx + внешняя сборка +Соберите frontend локально и монтируйте папку `dist` + +### Вариант 3: Отдельные контейнеры +Frontend и backend в разных контейнерах + +## Результат + +После успешного запуска: +- **Frontend**: `http://IP_СЕРВЕРА/` +- **API**: `http://IP_СЕРВЕРА/api/` +- **WebSocket**: `ws://IP_СЕРВЕРА/ws/` +- **Логин**: `admin` / `Admin` + +--- + +**Nginx + Frontend в статике = максимальная производительность!** 🚀 \ No newline at end of file diff --git a/docker-compose.txt.backup b/docker-compose.txt.backup new file mode 100644 index 0000000..d0bb726 --- /dev/null +++ b/docker-compose.txt.backup @@ -0,0 +1,47 @@ +version: '3.8' + +services: + # MC Panel приложение + mc-panel: + build: + context: . + dockerfile: Dockerfile + container_name: mc-panel + restart: unless-stopped + ports: + - "80:8000" # Прямой доступ через порт 80 + environment: + # ZITADEL OpenID Connect + - ZITADEL_ISSUER=${ZITADEL_ISSUER} + - ZITADEL_CLIENT_ID=${ZITADEL_CLIENT_ID} + - ZITADEL_CLIENT_SECRET=${ZITADEL_CLIENT_SECRET} + + # URLs + - BASE_URL=${BASE_URL:-http://localhost} + - FRONTEND_URL=${FRONTEND_URL:-http://localhost} + + # Security + - SECRET_KEY=${SECRET_KEY:-change-this-in-production} + + # Python + - PYTHONUNBUFFERED=1 + volumes: + # Персистентное хранилище для серверов + - ./data/servers:/app/backend/servers + # Персистентное хранилище для пользователей и тикетов + - ./data/users.json:/app/backend/users.json + - ./data/tickets.json:/app/backend/tickets.json + # Папка для данных демонов + - ./data:/app/data + networks: + - mc-panel-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/api/auth/oidc/providers"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +networks: + mc-panel-network: + driver: bridge \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d0bb726..06c47e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,37 +1,29 @@ version: '3.8' services: - # MC Panel приложение mc-panel: build: context: . dockerfile: Dockerfile container_name: mc-panel restart: unless-stopped - ports: - - "80:8000" # Прямой доступ через порт 80 + expose: + - "8000" environment: - # ZITADEL OpenID Connect - ZITADEL_ISSUER=${ZITADEL_ISSUER} - ZITADEL_CLIENT_ID=${ZITADEL_CLIENT_ID} - ZITADEL_CLIENT_SECRET=${ZITADEL_CLIENT_SECRET} - # URLs - BASE_URL=${BASE_URL:-http://localhost} - FRONTEND_URL=${FRONTEND_URL:-http://localhost} - # Security - SECRET_KEY=${SECRET_KEY:-change-this-in-production} - # Python - PYTHONUNBUFFERED=1 volumes: - # Персистентное хранилище для серверов - ./data/servers:/app/backend/servers - # Персистентное хранилище для пользователей и тикетов - ./data/users.json:/app/backend/users.json - ./data/tickets.json:/app/backend/tickets.json - # Папка для данных демонов - ./data:/app/data networks: - mc-panel-network @@ -42,6 +34,39 @@ services: retries: 3 start_period: 40s + nginx: + image: nginx:alpine + container_name: mc-panel-nginx + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx/default.conf:/etc/nginx/nginx.conf:ro + - frontend-static:/usr/share/nginx/html:ro + - ./nginx/ssl:/etc/nginx/ssl:ro + depends_on: + - frontend-init + - mc-panel + networks: + - mc-panel-network + + frontend-init: + build: + context: . + dockerfile: Dockerfile + container_name: mc-panel-frontend-init + volumes: + - frontend-static:/tmp/frontend + command: sh -c "cp -r /app/frontend/dist/* /tmp/frontend/ 2>/dev/null || echo 'No files to copy'; echo 'Frontend initialization complete'" + restart: "no" + networks: + - mc-panel-network + networks: mc-panel-network: - driver: bridge \ No newline at end of file + driver: bridge + +volumes: + frontend-static: + driver: local \ No newline at end of file diff --git a/nginx/default.conf b/nginx/default.conf index 3508a03..9315639 100644 --- a/nginx/default.conf +++ b/nginx/default.conf @@ -6,26 +6,50 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; + # Логирование + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; - access_log /var/log/nginx/access.log main; + # Основные настройки sendfile on; + tcp_nopush on; + tcp_nodelay on; keepalive_timeout 65; client_max_body_size 100M; - upstream mc_panel { + # Gzip сжатие + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript + application/json application/javascript application/xml+rss + application/atom+xml image/svg+xml; + + # Upstream для backend API + upstream mc_panel_api { server mc-panel:8000; } server { listen 80; server_name _; + root /usr/share/nginx/html; + index index.html; - # API endpoints + # Статические файлы frontend + location / { + try_files $uri $uri/ /index.html; + + # Кэширование статических файлов + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + } + + # API запросы к backend location /api/ { - proxy_pass http://mc_panel; + proxy_pass http://mc_panel_api; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -43,7 +67,7 @@ http { # WebSocket для консоли location /ws/ { - proxy_pass http://mc_panel; + proxy_pass http://mc_panel_api; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; @@ -58,21 +82,16 @@ http { proxy_read_timeout 7d; } - # Статические файлы фронтенда - location / { - proxy_pass http://mc_panel; - 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; - } - # Health check location /health { access_log off; return 200 "healthy\n"; add_header Content-Type text/plain; } + + # Безопасность + location ~ /\. { + deny all; + } } } \ No newline at end of file