Files
security-alert-center/docs/install-ubuntu-24.04-native.md
T
PTah 6b288bfa49 chore(github): generic example.com in docs, remove mirror scripts
Replace sac.kalinamall.ru with sac.example.com in public docs/deploy.
Remove Push-Mirror and Rewrite-GitHostUrls scripts from repo.
Simplify workspace-three-repos.md for GitHub-only workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 11:57:02 +10:00

16 KiB
Raw Blame History

Ubuntu 24.04 — установка SAC (native, без Docker)

Пошаговое руководство: PostgreSQL + Python venv + systemd + nginx.
Рекомендуемый путь для production.


0. Исходные данные

Параметр Пример
FQDN sac.example.com
IP 10.0.0.50
Каталог /opt/security-alert-center
Пользователь сервиса sac
API только на localhost 127.0.0.1:8000
Снаружи nginx → 443 → API

1. Базовая настройка ОС

sudo apt update
sudo apt upgrade -y
sudo timedatectl set-timezone Europe/Moscow

Firewall (ufw)

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

2. Пакеты

sudo apt install -y \
  git \
  postgresql \
  postgresql-contrib \
  nginx \
  python3.12 \
  python3.12-venv \
  python3-pip \
  jq \
  certbot \
  python3-certbot-nginx

Проверка:

python3.12 --version
psql --version
nginx -v

3. Клонирование репозитория

sudo mkdir -p /opt
sudo git clone https://github.com/PTah/security-alert-center.git /opt/security-alert-center

4. PostgreSQL

Создать пользователя и БД (пароль сохраните для .env):

sudo -u postgres psql <<'SQL'
CREATE USER sac WITH PASSWORD 'ЗАМЕНИТЕ_НА_ДЛИННЫЙ_ПАРОЛЬ';
CREATE DATABASE sac OWNER sac;
GRANT ALL PRIVILEGES ON DATABASE sac TO sac;
SQL

PostgreSQL по умолчанию слушает 127.0.0.1 — для SAC этого достаточно.
Проверка:

psql "postgresql://sac@127.0.0.1/sac" -c 'SELECT 1'

Каталог бэкапов:

sudo mkdir -p /var/backups/sac
sudo chown postgres:postgres /var/backups/sac

5. Пользователь sac и Python venv

sudo useradd --system --home /opt/security-alert-center --shell /usr/sbin/nologin sac || true
sudo chown -R sac:sac /opt/security-alert-center

cd /opt/security-alert-center/backend
sudo -u sac python3.12 -m venv .venv
sudo -u sac .venv/bin/pip install --upgrade pip
sudo -u sac .venv/bin/pip install -r requirements.txt

6. Конфигурация

Файл лежит в каталоге приложения (владелец sac) — так проще, чем права на /etc/....

sudo mkdir -p /opt/security-alert-center/config
sudo cp /opt/security-alert-center/deploy/env.native.example \
  /opt/security-alert-center/config/sac-api.env
sudo nano /opt/security-alert-center/config/sac-api.env
sudo chown sac:sac /opt/security-alert-center/config/sac-api.env
sudo chmod 600 /opt/security-alert-center/config/sac-api.env

Если уже создавали /etc/security-alert-center/sac-api.env — перенесите:

sudo mkdir -p /opt/security-alert-center/config
sudo cp /etc/security-alert-center/sac-api.env /opt/security-alert-center/config/sac-api.env
sudo chown sac:sac /opt/security-alert-center/config/sac-api.env
sudo chmod 600 /opt/security-alert-center/config/sac-api.env

Обязательно задать:

  • DATABASE_URLс паролем PostgreSQL из шага 4 (если в пароле есть #, @, % — возьмите значение в кавычки: DATABASE_URL="postgresql+psycopg2://...")
  • JWT_SECRETopenssl rand -hex 32
  • SAC_PUBLIC_URLhttps://sac.example.com
  • SAC_BOOTSTRAP_API_KEYpython3.12 -c "import secrets; print('sac_'+secrets.token_urlsafe(32))"
  • SAC_ADMIN_PASSWORD — пароль входа в веб-UI (отдельно от API key агентов)
  • EVENT_SCHEMA_PATH=/opt/security-alert-center/schemas/event-schema-v1.json
  • (опц.) Telegram из SAC: TELEGRAM_ENABLED=true, TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_MIN_SEVERITY=high

7. Миграции БД

Проверка, что sac читает конфиг (должно быть без Permission denied):

ls -la /opt/security-alert-center/config/sac-api.env
# должно быть: -rw------- sac sac
sudo -u sac test -r /opt/security-alert-center/config/sac-api.env && echo OK

Миграции:

cd /opt/security-alert-center/backend
sudo -u sac bash -c 'set -a; source /opt/security-alert-center/config/sac-api.env; set +a; .venv/bin/alembic upgrade head'

8. systemd

Приложение загружает config/sac-api.env само (не через EnvironmentFile systemd) — так же, как при alembic с source.

cd /opt/security-alert-center && sudo git pull
sudo cp /opt/security-alert-center/deploy/systemd/sac-api.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable sac-api
sudo systemctl start sac-api
sudo systemctl status sac-api --no-pager

Логи:

journalctl -u sac-api -f

9. nginx и TLS

Для KalinaMall: корпоративный wildcard VeriSign (или DigiCert), не Let's Encrypt.
Хост sac.example.com должен попадать под *.example.com.

Подробно: форматы, scp с Windows/Linux, .pfx → PEM, права — ssl-certificate.md.

9.1. Кратко: куда положить файлы

nginx ожидает два PEM-файла:

Файл на сервере Содержимое
/etc/ssl/sac/fullchain.pem Wildcard-сертификат + промежуточные CA
/etc/ssl/sac/privkey.pem Закрытый ключ
# каталог: группа ssl-cert, чтобы www-data мог зайти в каталог (chmod 750)
sudo mkdir -p /etc/ssl/sac
sudo chown root:ssl-cert /etc/ssl/sac
sudo chmod 750 /etc/ssl/sac

# nginx читает ключ через группу ssl-cert (на чистой Ubuntu в группе часто только postgres)
sudo groupadd -f ssl-cert
sudo usermod -aG ssl-cert www-data

Скопировать с рабочего ПК (пример):

# с вашего компьютера:
scp fullchain.pem privkey.pem deploy@<IP_SAC>:/tmp/

# на сервере:
sudo mv /tmp/fullchain.pem /tmp/privkey.pem /etc/ssl/sac/
sudo chmod 644 /etc/ssl/sac/fullchain.pem
sudo chmod 640 /etc/ssl/sac/privkey.pem
sudo chown root:root /etc/ssl/sac/fullchain.pem
sudo chown root:ssl-cert /etc/ssl/sac/privkey.pem
# каталог снова root:ssl-cert (если меняли владельца при mv)
sudo chown root:ssl-cert /etc/ssl/sac
sudo chmod 750 /etc/ssl/sac

# worker nginx должен подхватить группу www-data
sudo systemctl restart nginx

sudo -u www-data test -x /etc/ssl/sac && echo dir OK || echo dir FAIL
sudo -u www-data test -r /etc/ssl/sac/fullchain.pem && echo fullchain OK || echo fullchain FAIL
sudo -u www-data test -r /etc/ssl/sac/privkey.pem && echo key OK || echo key FAIL

Если test -r privkey.pem молчит: каталог был root:root при 750у www-data нет права x на /etc/ssl/sac/; либо www-data не в ssl-cert. См. ssl-certificate.md §3.

Если PFX с другого Linux — scp на SAC: ssl-certificate.md §4.3.
Распаковка PFX на Ubuntu 24.04: openssl pkcs12 -legacy§4.4.

9.2. Конфиг nginx (HTTPS)

cd /opt/security-alert-center
sudo git pull
sudo cp deploy/nginx/sac.conf.tls.example /etc/nginx/sites-available/sac
sudo nano /etc/nginx/sites-available/sac
# Проверьте пути ssl_certificate и ssl_certificate_key → /etc/ssl/sac/...

sudo ln -sf /etc/nginx/sites-available/sac /etc/nginx/sites-enabled/sac
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

Шаблон sac.conf.tls.example содержит default_server с return 444 (:80) и ssl_reject_handshake (:443) для любого Host, кроме sac.example.com. Это защищает от ситуации, когда на IP SAC (например <SAC_SERVER_IP>) по ошибке DNS попадает ext.example.com и открывается форма входа SAC.

Проверка после reload:

curl -sS -o /dev/null -w '%{http_code}\n' --resolve sac.example.com:443:127.0.0.1 https://sac.example.com/health
# ожидается 200

curl -sS -o /dev/null -w '%{http_code}\n' --resolve ext.example.com:443:127.0.0.1 https://ext.example.com/ 2>/dev/null || echo "connection closed (444/reject OK)"

Проверка:

curl -sS https://sac.example.com/health | jq .

В config/sac-api.env должно быть: SAC_PUBLIC_URL=https://sac.example.com

9.3. Агенты (ssh-monitor, RDP) и доверие к CA

  • Агенты ходят на https://sac.example.com/api/v1/events.
  • Если используется внутренний корневой CA, а не публичный VeriSign/DigiCert в системном store — на Linux/Windows может понадобиться установка корневого сертификата в доверенные (или корпоративный прокси с подменой TLS).
  • Для публичного коммерческого wildcard от известного УЦ обычно дополнительных действий на агентах не нужно.

9.4. Альтернатива: только HTTP (отладка)

Шаблон deploy/nginx/sac.conf.example — порт 80 без TLS. Не для production.

9.5. Альтернатива: Let's Encrypt

Если понадобится публичный бесплатный сертификат только на этот хост:

sudo cp deploy/nginx/sac.conf.example /etc/nginx/sites-available/sac
# ... nginx -t, reload, затем:
sudo certbot --nginx -d sac.example.com

10. Сборка веб-UI (фаза 1C)

sudo apt install -y nodejs npm
cd /opt/security-alert-center
sudo -u sac git pull
cd frontend
sudo -u sac npm ci
sudo -u sac npm run build
ls -la dist/index.html
sudo systemctl restart sac-api

В config/sac-api.env задайте SAC_ADMIN_PASSWORD, затем откройте https://sac.example.com/ (логин SAC_ADMIN_USERNAME, по умолчанию admin).

После обновления с multi-user (миграция 009_sac_users): выполните alembic upgrade head в каталоге backend/. При первом старте API создаст пользователя admin из SAC_ADMIN_*, если таблица sac_users пуста.

Добавить сотрудника с ролью monitor (просмотр без «Настройки»):

cd /opt/security-alert-center/backend
sudo -u sac python scripts/sac_manage_user.py create ivanov 'StrongPass123' --role monitor

Роли: admin — полный доступ; monitor — события, хосты, проблемы, отчёты (без /settings и /users).


11. Проверка

Локально на сервере:

curl -sS http://127.0.0.1:8000/health | jq .

Через nginx (после TLS):

curl -sS https://sac.example.com/health | jq .

Тест ingest (подставьте SAC_BOOTSTRAP_API_KEY):

API_KEY="ваш_ключ_из_sac-api.env"
curl -sS -X POST http://127.0.0.1:8000/api/v1/events \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "schema_version": "1.0",
    "event_id": "00000000-0000-4000-8000-000000000002",
    "occurred_at": "2026-05-26T12:00:00+03:00",
    "source": {"product": "ssh-monitor", "product_version": "test"},
    "host": {"hostname": "test-host", "os_family": "linux"},
    "category": "agent",
    "type": "agent.test",
    "severity": "info",
    "title": "Test",
    "summary": "Native install check"
  }'

Ожидается HTTP 202 и "status": "accepted".


12. Резервное копирование

sudo tee /etc/cron.d/sac-backup <<'EOF'
0 3 * * * postgres pg_dump -Fc -U sac sac > /var/backups/sac/sac_$(date +\%Y\%m\%d).dump
EOF

Для pg_dump без пароля в cron настройте ~postgres/.pgpass (см. документацию PostgreSQL).


13. Обновление SAC (деплой)

Рекомендуется: скрипт /opt/sac-deploy.sh

После первой установки один раз:

sudo cp /opt/security-alert-center/deploy/sac-deploy.sh /opt/sac-deploy.sh
sudo chmod 755 /opt/sac-deploy.sh

Каждое обновление с git:

sudo /opt/sac-deploy.sh

Скрипт: chown sac:sacgit pull (от sac) → pipalembicnpm run buildsystemctl restart sac-api → проверка /health.

Вручную (если без скрипта)

sudo chown -R sac:sac /opt/security-alert-center
sudo -u sac git -C /opt/security-alert-center pull
cd /opt/security-alert-center/frontend && sudo -u sac npm ci && sudo -u sac npm run build
sudo -u sac /opt/security-alert-center/backend/.venv/bin/pip install -r /opt/security-alert-center/backend/requirements.txt
sudo -u sac bash -c 'set -a; source /opt/security-alert-center/config/sac-api.env; set +a; cd /opt/security-alert-center/backend && .venv/bin/alembic upgrade head'
sudo systemctl restart sac-api

Git: только от пользователя sac

Не выполняйте sudo git pull в /opt/security-alert-center.git станет root и появится:

error: cannot open '.git/FETCH_HEAD': Permission denied

Исправление: sudo chown -R sac:sac /opt/security-alert-center.


14. Чеклист

  • Ubuntu 24.04, timezone
  • ufw: 22, 80, 443
  • PostgreSQL: БД sac, пользователь sac
  • venv, зависимости установлены
  • /opt/security-alert-center/config/sac-api.env, владелец sac:sac, chmod 600
  • alembic upgrade head без ошибок
  • sac-api active (systemd)
  • nginx + TLS
  • /health ok, ingest 202
  • frontend/dist собран, UI открывается, вход admin OK
  • cron backup

15. Устранение неполадок

Симптом Действие
sac-api.env: Permission denied Конфиг в /opt/security-alert-center/config/, chown sac:sac, chmod 600. Не используйте /etc/... с каталогом root:root
password authentication failed в sac-api, но alembic OK Старый unit с EnvironmentFile=git pull, обновить sac-api.service, daemon-reload, restart. Либо пароль в DATABASE_URL ≠ PostgreSQL
password authentication failed везде Пароль в DATABASE_URL в кавычках; ALTER USER sac WITH PASSWORD; тот же пароль в URL
database: error / SQLAlchemy connect systemctl status postgresql; проверить DATABASE_URL после успешного source
401 ingest ключ в Authorization: Bearer; проверить SAC_BOOTSTRAP_API_KEY
502 от nginx API не слушает: ss -lntp | grep 8000, systemctl restart sac-api
Schema errors 422 путь EVENT_SCHEMA_PATH, наличие файла schema
FETCH_HEAD: Permission denied sudo chown -R sac:sac /opt/security-alert-center; далее sudo -u sac git pull
UI 404 / пустая главная cd frontend && sudo -u sac npm run build; restart sac-api
503 на /auth/login задать SAC_ADMIN_PASSWORD в config/sac-api.env
test -r privkey.pem без вывода каталог /etc/ssl/sacroot:ssl-cert, www-data в группе ssl-certssl-certificate.md §3
PFX RC2-40-CBC unsupported openssl pkcs12 -legacyssl-certificate.md §4.4

См. также