# Ubuntu 24.04 — установка SAC (native, без Docker) Пошаговое руководство: **PostgreSQL + Python venv + systemd + nginx**. Рекомендуемый путь для production. --- ## 0. Исходные данные | Параметр | Пример | |----------|--------| | FQDN | `sac.kalinamall.ru` | | IP | `10.0.0.50` | | Каталог | `/opt/security-alert-center` | | Пользователь сервиса | `sac` | | API только на localhost | `127.0.0.1:8000` | | Снаружи | nginx → 443 → API | --- ## 1. Базовая настройка ОС ```bash sudo apt update sudo apt upgrade -y sudo timedatectl set-timezone Europe/Moscow ``` ### Firewall (ufw) ```bash 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. Пакеты ```bash sudo apt install -y \ git \ postgresql \ postgresql-contrib \ nginx \ python3.12 \ python3.12-venv \ python3-pip \ jq \ certbot \ python3-certbot-nginx ``` Проверка: ```bash python3.12 --version psql --version nginx -v ``` --- ## 3. Клонирование репозитория ```bash sudo mkdir -p /opt sudo git clone https://git.kalinamall.ru/PapaTramp/security-alert-center.git /opt/security-alert-center ``` --- ## 4. PostgreSQL Создать пользователя и БД (пароль сохраните для `.env`): ```bash 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 этого достаточно. Проверка: ```bash psql "postgresql://sac@127.0.0.1/sac" -c 'SELECT 1' ``` Каталог бэкапов: ```bash sudo mkdir -p /var/backups/sac sudo chown postgres:postgres /var/backups/sac ``` --- ## 5. Пользователь `sac` и Python venv ```bash 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/...`. ```bash 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` — перенесите: ```bash 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_SECRET` — `openssl rand -hex 32` - `SAC_PUBLIC_URL` — `https://sac.kalinamall.ru` - `SAC_BOOTSTRAP_API_KEY` — `python3.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` --- ## 7. Миграции БД Проверка, что `sac` читает конфиг (должно быть без `Permission denied`): ```bash 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 ``` Миграции: ```bash 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`. ```bash 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 ``` Логи: ```bash journalctl -u sac-api -f ``` --- ## 9. nginx и TLS Для KalinaMall: **корпоративный wildcard VeriSign** (или DigiCert), не Let's Encrypt. Хост `sac.kalinamall.ru` должен попадать под `*.kalinamall.ru`. **Подробно:** форматы, scp с Windows/Linux, `.pfx` → PEM, права — **[ssl-certificate.md](ssl-certificate.md)**. ### 9.1. Кратко: куда положить файлы nginx ожидает **два PEM-файла**: | Файл на сервере | Содержимое | |-----------------|------------| | `/etc/ssl/sac/fullchain.pem` | Wildcard-сертификат + промежуточные CA | | `/etc/ssl/sac/privkey.pem` | Закрытый ключ | ```bash # каталог: группа 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 ``` Скопировать с рабочего ПК (пример): ```bash # с вашего компьютера: scp fullchain.pem privkey.pem papatramp@:/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](ssl-certificate.md#3-каталог-и-права-на-сервере). Если PFX с другого Linux — `scp` на SAC: [ssl-certificate.md §4.3](ssl-certificate.md#43-забрать-файл-с-другого-linux-сервера-scp). Распаковка PFX на Ubuntu 24.04: **`openssl pkcs12 -legacy`** — [§4.4](ssl-certificate.md#44-распаковка-pfx--p12-на-сервере-ubuntu-2404). ### 9.2. Конфиг nginx (HTTPS) ```bash 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 ``` Проверка: ```bash curl -sS https://sac.kalinamall.ru/health | jq . ``` В `config/sac-api.env` должно быть: `SAC_PUBLIC_URL=https://sac.kalinamall.ru` ### 9.3. Агенты (ssh-monitor, RDP) и доверие к CA - Агенты ходят на `https://sac.kalinamall.ru/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 Если понадобится публичный бесплатный сертификат только на этот хост: ```bash sudo cp deploy/nginx/sac.conf.example /etc/nginx/sites-available/sac # ... nginx -t, reload, затем: sudo certbot --nginx -d sac.kalinamall.ru ``` --- ## 10. Сборка веб-UI (фаза 1C) ```bash 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.kalinamall.ru/` (логин `SAC_ADMIN_USERNAME`, по умолчанию `admin`). --- ## 11. Проверка Локально на сервере: ```bash curl -sS http://127.0.0.1:8000/health | jq . ``` Через nginx (после TLS): ```bash curl -sS https://sac.kalinamall.ru/health | jq . ``` Тест ingest (подставьте `SAC_BOOTSTRAP_API_KEY`): ```bash 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. Резервное копирование ```bash 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 ```bash cd /opt/security-alert-center sudo -u sac git pull sudo -u sac backend/.venv/bin/pip install -r backend/requirements.txt sudo -u sac bash -c 'set -a; source /opt/security-alert-center/config/sac-api.env; set +a; cd backend && .venv/bin/alembic upgrade head' sudo systemctl restart sac-api ``` --- ## 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 | --- ## См. также - [install-ubuntu-24.04.md](install-ubuntu-24.04.md) — указатель - [install-ubuntu-24.04-docker.md](install-ubuntu-24.04-docker.md) — альтернатива (не prod) - [deployment.md](deployment.md)