diff --git a/.env.example b/.env.example index 7a089c0..08b8fc4 100644 --- a/.env.example +++ b/.env.example @@ -15,11 +15,12 @@ FRONTEND_PORT=80 # ============================ # DATABASE (PostgreSQL) # ============================ +# На VPS используй: openssl rand -base64 32 DB_HOST=postgres DB_PORT=5432 DB_NAME=pg_admin DB_USER=postgres -DB_PASSWORD=CHANGE_ME_SECURE_PASSWORD +DB_PASSWORD=CHANGE_ME_TO_STRONG_PASSWORD_GENERATED_WITH_OPENSSL DB_HOST_DEV=localhost # Connection pool diff --git a/VPS-DEPLOYMENT.md b/VPS-DEPLOYMENT.md new file mode 100644 index 0000000..2e148fd --- /dev/null +++ b/VPS-DEPLOYMENT.md @@ -0,0 +1,269 @@ +# 🚀 Развертывание на VPS + +Инструкция по запуску pg-admin на VPS (Ubuntu 24.04, другие версии похожи). + +## Быстрый старт (3 шага) + +### 1️⃣ Подключись к VPS и клонируй репозиторий + +```bash +ssh root@YOUR_VPS_IP +cd ~ +git clone git@your-repo-url:your-org/pg-admin.git +cd pg-admin +``` + +### 2️⃣ Генерируй безопасные пароли + +```bash +bash scripts/generate-secrets.sh +``` + +Скопируй выходные значения. + +### 3️⃣ Создай и настрой .env + +```bash +cp .env.example .env +nano .env +``` + +**Замени в .env:** +- `CHANGE_ME_TO_STRONG_PASSWORD` → Пароль из `generate-secrets.sh` +- `CHANGE_ME_TO_STRONG_RANDOM_SECRET` → JWT_SECRET из `generate-secrets.sh` +- `your-domain.com` → Твой реальный доменName (или IP на тест) +- `FRONTEND_API_URL` → `http://ТВЙ_ДОМЕН/api` +- `CORS_ORIGIN` → `http://ТВЙ_ДОМЕН` (пока HTTP) + +Сохрани (Ctrl+X, Y, Enter в nano). + +### 4️⃣ Запусти инициализацию + +```bash +bash scripts/setup-vps.sh +``` + +Скрипт установит Docker, настроит контейнеры и запустит приложение. + +### 5️⃣ Проверь статус + +```bash +docker compose ps +docker compose logs -f +``` + +Приложение готово на `http://YOUR_VPS_IP:80` 🎉 + +--- + +## 📋 Требования + +- **OS:** Ubuntu 20.04+ (или другой Linux с Docker) +- **RAM:** Минимум 2GB (рекомендуется 4GB) +- **CPU:** 2 ядра (рекомендуется 4+) +- **Диск:** 20GB свободного места (SSD лучше) +- **Порты:** 80/TCP открыты в файрволе + +--- + +## 🔒 Безопасность на VPS + +### ✅ Сделано в docker-compose.yml: +- ❌ БД не открыта наружу (только для контейнеров) +- ❌ Redis не открыт наружу (только для контейнеров) +- ❌ API не открыт напрямую (только через Nginx) +- ✅ Nginx проксирует запросы безопасно +- ✅ Ограничение ресурсов на контейнеры +- ✅ Health checks для отказоустойчивости + +### ⚠️ Нужно сделать вручную: + +#### 1. Настрой файрвол (UFW) +```bash +# Разреши только необходимые порты +sudo ufw enable +sudo ufw allow 22/tcp # SSH (для удаленного доступа) +sudo ufw allow 80/tcp # HTTP +sudo ufw allow 443/tcp # HTTPS (когда добавишь SSL) +sudo ufw status +``` + +#### 2. Добавь SSH ключи (вместо пароля) +```bash +# На локальной машине генерируй ключ если нет +ssh-keygen -t ed25519 -C "your-email@example.com" + +# Скопируй публичный ключ на VPS +ssh-copy-id -i ~/.ssh/id_ed25519.pub root@YOUR_VPS_IP + +# Отключи вход по пароеи в sshd_config +sudo nano /etc/ssh/sshd_config +# Найди и измени на: +# PasswordAuthentication no +# PubkeyAuthentication yes + +sudo systemctl reload ssh +``` + +#### 3. Установи Let's Encrypt SSL/HTTPS +Позже, когда будешь готов: +```bash +sudo apt-get install certbot python3-certbot-nginx +sudo certbot certonly --standalone -d your-domain.com -d www.your-domain.com +``` + +Затем обнови nginx.conf и docker-compose.yml для HTTPS. + +#### 4. Настрой резервное копирование БД +```bash +# Создай backup скрипт +mkdir -p backups +cat > backups/backup-db.sh << 'EOF' +#!/bin/bash +BACKUP_DIR="./backups" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +docker exec pg-admin-db pg_dump -U postgres pg_admin | gzip > $BACKUP_DIR/backup_$TIMESTAMP.sql.gz +echo "✅ Backup завершен: backup_$TIMESTAMP.sql.gz" +EOF + +chmod +x backups/backup-db.sh + +# Настрой cron для ежедневного backup (21:00 UTC) +crontab -e +# Добавь строку: +# 0 21 * * * cd /root/pg-admin && bash backups/backup-db.sh +``` + +#### 5. Мониторинг логов +```bash +# Просмотри логи всех контейнеров +docker compose logs -f + +# Или конкретного контейнера +docker compose logs -f pg-admin-api + +# Проверь дисковое пространство +df -h + +# Проверь использование памяти +docker stats +``` + +--- + +## 🛠️ Частые команды + +```bash +# Посмотри статус контейнеров +docker compose ps + +# Перезагрузи приложение +docker compose restart + +# Обнови код и перестрой +git pull origin main +docker compose up -d --build + +# Посмотри логи +docker compose logs -f + +# Останови все +docker compose down + +# Полная переустановка (опасно - удалит данные!) +docker compose down -v +docker compose up -d --build +``` + +--- + +## 🔄 Pipeline для development → production + +1. ✅ Делай коммиты в git +2. ✅ Пуш на main/master +3. ✅ На VPS: `git pull origin main` +4. ✅ На VPS: `docker compose up -d --build` +5. ✅ Проверь: `docker compose logs -f` + +--- + +## 📊 Проверка здоровья приложения + +```bash +# Проверь доступность +curl -I http://YOUR_VPS_IP:80/ + +# Посмотри статус контейнеров +docker compose ps + +# Проверь память и CPU +docker stats + +# Посмотри логи ошибок +docker compose logs | grep -i error +``` + +--- + +## 🚨 Troubleshooting + +### Контейнер крашится при старте +```bash +# Посмотри логи +docker compose logs pg-admin-api + +# Перестрой с чистого листа +docker compose down -v +docker compose up -d --build +``` + +### БД не подключается +```bash +# Проверь что БД запущена +docker compose ps + +# Проверь логи БД +docker compose logs pg-admin-db + +# Проверь переменные окружения +docker compose exec pg-admin-api env | grep DB +``` + +### Порт уже занят +```bash +# Найди процесс на порту 80 +sudo lsof -i :80 + +# Убей процесс (замени PID) +sudo kill -9 PID + +# Или смени порт в .env: +NGINX_PORT=8080 +docker compose up -d +``` + +### No space left on device +```bash +# Очисти Docker образы +docker image prune -a + +# Очисти volumes (ОСТОРОЖНО!) +docker volume prune + +# Посмотри место на диске +df -h +``` + +--- + +## 📞 Поддержка + +Если что-то не работает: +1. Проверь логи: `docker compose logs -f` +2. Проверь конфигурацию .env +3. Посмотри порты: `sudo netstat -tlnp | grep LISTEN` +4. Перезагрузи: `docker compose restart` + +--- + +**Создано для pg-admin | VPS Deployment Guide v1.0** diff --git a/docker-compose.yml b/docker-compose.yml index 5980fa3..eee8563 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,9 +6,8 @@ services: POSTGRES_USER: ${DB_USER:-postgres} POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres} POSTGRES_DB: ${DB_NAME:-pg_admin} - POSTGRES_INITDB_ARGS: "--encoding=UTF8" - ports: - - "${DB_PORT:-5432}:5432" + POSTGRES_INITDB_ARGS: "--encoding=UTF8 -c shared_buffers=256MB -c max_connections=100" + # БД НЕ открыта наружу - только для контейнеров volumes: - postgres_data:/var/lib/postgresql/data - ./docker/init-db.sql:/docker-entrypoint-initdb.d/init.sql @@ -19,6 +18,15 @@ services: retries: 5 networks: - pg-admin-network + restart: unless-stopped + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M backend: build: @@ -37,8 +45,7 @@ services: JWT_EXPIRE: ${JWT_EXPIRE:-7d} MAX_CONNECTIONS: ${MAX_CONNECTIONS:-20} LOG_LEVEL: ${LOG_LEVEL:-info} - ports: - - "${API_PORT:-3000}:${API_PORT:-3000}" + # API НЕ открыт наружу - только для nginx depends_on: postgres: condition: service_healthy @@ -48,6 +55,14 @@ services: networks: - pg-admin-network restart: unless-stopped + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M frontend: build: @@ -57,8 +72,7 @@ services: environment: REACT_APP_API_URL: ${FRONTEND_API_URL:-http://localhost:3000/api} REACT_APP_ENV: ${NODE_ENV:-production} - ports: - - "${FRONTEND_PORT:-80}:3000" + # Frontend НЕ открыт наружу - только для nginx depends_on: - backend volumes: @@ -66,14 +80,20 @@ services: networks: - pg-admin-network restart: unless-stopped + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M redis: image: redis:7-alpine container_name: pg-admin-cache - ports: - - "${REDIS_PORT:-6379}:6379" - environment: - REDIS_PASSWORD: ${REDIS_PASSWORD:-change_me} + # Redis НЕ открыт наружу - только для контейнеров + command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data healthcheck: @@ -84,12 +104,20 @@ services: networks: - pg-admin-network restart: unless-stopped + deploy: + resources: + limits: + cpus: '0.5' + memory: 256M + reservations: + cpus: '0.25' + memory: 128M nginx: image: nginx:alpine container_name: pg-admin-proxy ports: - - "${NGINX_PORT:-8080}:80" + - "${NGINX_PORT:-80}:80" volumes: - ./docker/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: @@ -98,6 +126,14 @@ services: networks: - pg-admin-network restart: unless-stopped + deploy: + resources: + limits: + cpus: '0.5' + memory: 256M + reservations: + cpus: '0.25' + memory: 128M volumes: postgres_data: diff --git a/docker/Dockerfile.frontend b/docker/Dockerfile.frontend index 5c768cc..4b96762 100644 --- a/docker/Dockerfile.frontend +++ b/docker/Dockerfile.frontend @@ -6,22 +6,22 @@ WORKDIR /app # Copy package files COPY package*.json ./ -# Install dependencies with production flag -RUN npm ci --only=production && npm ci +# Install dependencies +RUN npm install # Copy source code COPY . . # Build production bundle with optimizations -RUN NODE_ENV=production npm run build 2>/dev/null || true +RUN NODE_ENV=production npm run build -# Production stage - optimize serving +# Production stage - minimal footprint FROM node:18-alpine WORKDIR /app -# Install serve with gzip compression support -RUN npm install -g serve +# Install serve for static file serving +RUN npm install -g serve@14 # Copy built app from builder COPY --from=builder /app/build ./build @@ -32,5 +32,5 @@ EXPOSE 3000 HEALTHCHECK --interval=10s --timeout=5s --retries=5 \ CMD wget --quiet --tries=1 --spider http://localhost:3000/ || exit 1 -# Start server with compression and caching headers +# Start server with gzip compression CMD ["serve", "-s", "build", "-l", "3000", "--gzip"] diff --git a/scripts/generate-secrets.sh b/scripts/generate-secrets.sh new file mode 100644 index 0000000..9f00b80 --- /dev/null +++ b/scripts/generate-secrets.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Генерирование безопасных паролей и секретов для production VPS + +set -e + +echo "🔐 Генерирование захищенных паролей для production..." +echo "" + +# Генерируем паароль для БД +DB_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25) +echo "📊 DB_PASSWORD: $DB_PASSWORD" + +# Генерируем JWT секрет +JWT_SECRET=$(openssl rand -base64 64 | tr -d "\n") +echo "🔑 JWT_SECRET: $JWT_SECRET" + +# Генерируем Redis пароль +REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25) +echo "💾 REDIS_PASSWORD: $REDIS_PASSWORD" + +echo "" +echo "========================================" +echo "📝 Скопируй эти значения в .env на VPS:" +echo "========================================" +echo "" +echo "DB_PASSWORD=$DB_PASSWORD" +echo "JWT_SECRET=$JWT_SECRET" +echo "REDIS_PASSWORD=$REDIS_PASSWORD" +echo "" +echo "⚠️ НЕ коммитьи эти значения в git!" +echo "⚠️ Храни .env в безопасном месте, не в репозитории!" diff --git a/scripts/setup-vps.sh b/scripts/setup-vps.sh new file mode 100644 index 0000000..a5d1a18 --- /dev/null +++ b/scripts/setup-vps.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Инициализация Django приложения на VPS (Ubuntu 24.04) +# Запуск: bash scripts/setup-vps.sh + +set -e + +echo "🚀 Инициализация pg-admin на VPS..." +echo "" + +# Проверяем что мы на VPS (Ubuntu) +if ! grep -qi ubuntu /etc/os-release; then + echo "⚠️ Это скрипт для Ubuntu. Попробуй вручную для другой OS." +fi + +# 1. Обновляем систему +echo "📦 Обновление системы..." +sudo apt-get update +sudo apt-get upgrade -y + +# 2. Устанавливаем Docker если его нет +if ! command -v docker &> /dev/null; then + echo "🐳 Установка Docker..." + sudo apt-get install -y docker.io docker-compose-plugin + sudo usermod -aG docker $USER + echo "⚠️ Нужен перелогин для работы docker без sudo. Выполни: newgrp docker" +else + echo "✅ Docker уже установлен" +fi + +# 3. Создаем .env если его нет +if [ ! -f .env ]; then + echo "📝 Создание .env из .env.example..." + cp .env.example .env + echo "" + echo "⚠️ ВАЖНО! Отредактируй .env:" + echo " - Замени CHANGE_ME_TO_STRONG_PASSWORD на реальный пароль" + echo " - Замени CHANGE_ME_TO_STRONG_RANDOM_SECRET на реальный секрет" + echo " - Замени your-domain.com на твой домен" + echo " - Используй скрипт: bash scripts/generate-secrets.sh" + echo "" + echo "📝 Открой .env в редакторе и отредактируй значения:" + echo " nano .env" + exit 1 +else + echo "✅ .env файл уже существует" +fi + +# 4. Останавливаем старые контейнеры +echo "🛑 Остановка старых контейнеров..." +docker compose down -v --remove-orphans || true + +# 5. Создаем необходимые папки +echo "📁 Создание папок..." +mkdir -p backend/logs +mkdir -p logs + +# 6. Собираем и запускаем контейнеры +echo "🔨 Сборка и запуск контейнеров..." +docker compose up -d --build + +# 7. Проверяем статус +echo "" +echo "✅ Инициализация завершена!" +echo "" +echo "📊 Статус контейнеров:" +docker compose ps + +echo "" +echo "🌐 Приложение доступно по адресу:" +echo " http://YOUR_VPS_IP:80" +echo "" +echo "📝 Логи:" +echo " docker compose logs -f" +echo "" +echo "💡 Рекомендации:" +echo " 1. Настрой файрвол (UFW): sudo ufw allow 80,443/tcp" +echo " 2. Добавь SSL (Let's Encrypt) когда будешь готов" +echo " 3. Настрой резервное копирование БД" +echo " 4. Настрой мониторинг"