- 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: очищен от дубликатов
8.2 KiB
8.2 KiB
Деплой ipwhitelist — PRODUCTION
Репозиторий:
https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git(публичный)
Стек: Node.js 20+ / Express 4 / EJS / PostgreSQL 16+
Требования: доступ к Keycloak Nubes (realmcloud), зарегистрированный 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):
-
Создать клиента:
- Client ID:
<домен>(напримерwhite.nubes.ru) - Client authentication: ON
- Standard flow: ON
- Valid redirect URIs:
https://<домен>/callback - Web origins:
https://<домен>(или+)
- Client ID:
-
Забрать
Client secret→ в .env какKC_CLIENT_SECRET -
Mapper'ы (создать на клиенте, тип
User Attribute → Token Claim):
| Claim name | User attribute | Назначение |
|---|---|---|
ClientID |
client_id |
ID компании (может быть через запятую) |
company_id |
company_id |
ID компании в БД |
company_name |
company_name |
Название компании |
- Пользователи — создать в 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