# Деплой ipwhitelist — PRODUCTION > Репозиторий: `https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git` (публичный) > Стек: Node.js 20+ / Express 4 / EJS / PostgreSQL 16+ > Требования: доступ к Keycloak Nubes (realm `cloud`), зарегистрированный OIDC-клиент --- ## 1. Подготовка сервера ```bash # Node.js 20+ curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt install -y nodejs git nginx certbot python3-certbot-nginx postgresql # Код git clone https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git /opt/ipwhitelist cd /opt/ipwhitelist npm install --production ``` --- ## 2. PostgreSQL ```bash # Создать пользователя и БД sudo -u postgres psql -c "CREATE USER ipwhitelist WITH PASSWORD '${PASSWORD}';" sudo -u postgres psql -c "CREATE DATABASE ipwhitelist OWNER ipwhitelist;" # Применить схему PGPASSWORD="${PASSWORD}" psql -h localhost -U ipwhitelist -d ipwhitelist -f /opt/ipwhitelist/sql/schema.sql # Настройка: слушать только localhost (безопасность) grep -c "^listen_addresses = 'localhost'" /etc/postgresql/16/main/postgresql.conf \ || echo "listen_addresses = 'localhost'" >> /etc/postgresql/16/main/postgresql.conf systemctl restart postgresql ``` --- ## 3. .env (PRODUCTION) ```bash cp /opt/ipwhitelist/.env.example /opt/ipwhitelist/.env chmod 600 /opt/ipwhitelist/.env ``` ```ini # ── База данных ── DB_HOST=localhost DB_PORT=5432 DB_NAME=ipwhitelist DB_USER=ipwhitelist DB_PASS=<сгенерировать: openssl rand -base64 24> DB_SSLMODE=disable # localhost — шифрование не нужно # ── Аутентификация ── DEV_MODE=false # ОБЯЗАТЕЛЬНО false в production ADMIN_CLIENT_ID=WZ01112 # clientId пользователя-администратора # ── Keycloak / OIDC (данные от DevOps) ── KC_CLIENT_ID= # зарегистрированный OIDC-клиент KC_CLIENT_SECRET= # секрет клиента KC_BASE_URL=https://keycloak.nubes.ru/realms/cloud APP_URL=https://<домен> # публичный URL приложения (без слеша) # ── Сессия ── SESSION_SECRET= CSRF_SECRET= # ── Лимит записей по умолчанию ── DEFAULT_LIMIT=15 # ── Порт (для nginx upstream) ── PORT=3001 # ── API_BASE — куда UI-слой ходит за API (обычно localhost) ── API_BASE=http://localhost:3001 ``` **Генерация секретов:** ```bash openssl rand -base64 32 # для SESSION_SECRET openssl rand -base64 32 # для CSRF_SECRET openssl rand -base64 24 # для DB_PASS ``` --- ## 4. Keycloak — регистрация OIDC-клиента **Что сделать в админке Keycloak (realm `cloud`):** 1. Создать клиента: - Client ID: `<домен>` (например `white.nubes.ru`) - Client authentication: ON - Standard flow: ON - Valid redirect URIs: `https://<домен>/callback` - Web origins: `https://<домен>` (или `+`) 2. Забрать `Client secret` → в .env как `KC_CLIENT_SECRET` 3. **Mapper'ы** (создать на клиенте, тип `User Attribute → Token Claim`): | Claim name | User attribute | Назначение | |---|---|---| | `ClientID` | `client_id` | ID компании (может быть через запятую) | | `company_id` | `company_id` | ID компании в БД | | `company_name` | `company_name` | Название компании | 4. **Пользователи** — создать в Keycloak с заполненными атрибутами `client_id`, `company_id`, `company_name`. **Формат multi-company:** `client_id = "WZ11125,WZ03816"` — первое значение до запятой = активная компания. Приложение парсит автоматически. --- ## 5. nginx + HTTPS ```nginx server { listen 80; server_name <домен>; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name <домен>; ssl_certificate /etc/letsencrypt/live/<домен>/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/<домен>/privkey.pem; # Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; location / { proxy_pass http://127.0.0.1:3001; 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 X-Forwarded-Host $host; } } ``` ```bash # Получить сертификат certbot --nginx -d <домен> # Проверить авто-обновление certbot renew --dry-run ``` --- ## 6. PM2 — автозапуск ```bash npm i -g pm2 # Запуск pm2 start /opt/ipwhitelist/server.js --name ipwhitelist --update-env # Автостарт при перезагрузке pm2 startup systemd pm2 save # Проверка pm2 status pm2 logs ipwhitelist --lines 5 # Должно быть: [auth] OIDC — Keycloak # Если [auth] MOCK — значит KC_CLIENT_ID не задан ``` --- ## 7. Порядок ввода в эксплуатацию ```bash # 1. Убедиться что DEV_MODE=false и заданы KC_* grep -E "DEV_MODE|KC_CLIENT_ID|KC_CLIENT_SECRET" /opt/ipwhitelist/.env # 2. Перезапустить pm2 restart ipwhitelist --update-env # 3. Проверить логи — должен быть OIDC-режим pm2 logs ipwhitelist --lines 3 --nostream # 4. Проверить health curl -s https://<домен>/healthz # → OK # 5. Проверить SSO: открыть https://<домен>/login в браузере # → редирект на Keycloak # → после входа → редирект обратно на главную ``` --- ## 8. Проверка | URL | Ожидаемый результат | |---|---| | `https://<домен>/healthz` | `OK` | | `https://<домен>/` | Редирект на Keycloak login (если нет сессии) | | `https://<домен>/login` | Редирект на Keycloak (если `DEV_MODE=false`) | | `https://<домен>/export` | CIDR-список (text/plain) | | `https://<домен>/api/v1/entries` | 401 (нужен Bearer) | | `https://<домен>/callback?code=...` | Обмен code → сессия → редирект на `/` | --- ## 9. Обновление ```bash cd /opt/ipwhitelist git pull npm install --production pm2 restart ipwhitelist --update-env ``` --- ## 10. Переменные окружения (справочно) | Переменная | Обязательна | По умолчанию | Описание | |---|---|---|---| | `DB_HOST` | да | — | Хост PostgreSQL | | `DB_PORT` | нет | 5432 | Порт PostgreSQL | | `DB_NAME` | да | — | Имя БД | | `DB_USER` | да | — | Пользователь БД | | `DB_PASS` | да | — | Пароль БД | | `DB_SSLMODE` | нет | disable | `require` для внешнего подключения | | `DEV_MODE` | нет | true | `false` в production (ОБЯЗАТЕЛЬНО) | | `ADMIN_CLIENT_ID` | нет | WZ01112 | clientId администратора | | `KC_CLIENT_ID` | да* | — | OIDC client ID (обязателен для SSO) | | `KC_CLIENT_SECRET` | да* | — | OIDC client secret | | `KC_BASE_URL` | нет | `https://keycloak.nubes.ru/realms/cloud` | Keycloak realm URL | | `APP_URL` | да* | — | Публичный URL приложения (для OIDC redirect) | | `SESSION_SECRET` | да | — | Подпись сессионных cookie | | `CSRF_SECRET` | нет | — | CSRF-токены | | `PORT` | нет | 3000 | Порт Express | | `DEFAULT_LIMIT` | нет | 15 | Лимит записей по умолчанию | | `API_BASE` | нет | `http://localhost:PORT` | URL для UI→API запросов | \* — обязательны при `DEV_MODE=false`