Files
ipwhitelist-app/docs/devops-deploy.md
T
naeel 38c7adf25d v0.5.14 — вход по токену, JWKS в mock-режиме, production deploy docs
- POST /login-token: принимает реальный JWT (не только clientId)
- auth.js: verifyAnyToken — mock + JWKS (Keycloak Nubes) одновременно
- auth.js: JWKS предзагружается всегда, даже в mock-режиме
- devops-deploy.md: полная production-инструкция для DevOps
- .env.example: production-ready шаблон
- README.md: актуальный (v0.5.13, архитектура, тесты, ссылки)
- .gitignore: очищен от дубликатов
2026-06-03 12:37:10 +03:00

8.2 KiB

Деплой 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. Подготовка сервера

# 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

# Создать пользователя и БД
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)

cp /opt/ipwhitelist/.env.example /opt/ipwhitelist/.env
chmod 600 /opt/ipwhitelist/.env
# ── База данных ──
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=<client_id>    # зарегистрированный OIDC-клиент
KC_CLIENT_SECRET=<secret>   # секрет клиента
KC_BASE_URL=https://keycloak.nubes.ru/realms/cloud
APP_URL=https://<домен>     # публичный URL приложения (без слеша)

# ── Сессия ──
SESSION_SECRET=<openssl rand -base64 32>
CSRF_SECRET=<openssl rand -base64 32>

# ── Лимит записей по умолчанию ──
DEFAULT_LIMIT=15

# ── Порт (для nginx upstream) ──
PORT=3001

# ── API_BASE — куда UI-слой ходит за API (обычно localhost) ──
API_BASE=http://localhost:3001

Генерация секретов:

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 Название компании
  1. Пользователи — создать в Keycloak с заполненными атрибутами client_id, company_id, company_name.

Формат multi-company: client_id = "WZ11125,WZ03816" — первое значение до запятой = активная компания. Приложение парсит автоматически.


5. nginx + HTTPS

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;
    }
}
# Получить сертификат
certbot --nginx -d <домен>

# Проверить авто-обновление
certbot renew --dry-run

6. PM2 — автозапуск

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. Порядок ввода в эксплуатацию

# 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. Обновление

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