diff --git a/backend/app/config.py b/backend/app/config.py index 3d926b9..e0ccc78 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -1,3 +1,4 @@ +import os from functools import lru_cache from pathlib import Path @@ -5,15 +6,33 @@ from pydantic_settings import BaseSettings, SettingsConfigDict ROOT = Path(__file__).resolve().parents[2] SCHEMA_PATH = ROOT / "schemas" / "event-schema-v1.json" +DEFAULT_CONFIG_FILE = Path("/opt/security-alert-center/config/sac-api.env") -class Settings(BaseSettings): - model_config = SettingsConfigDict( - env_file=".env", +def _resolve_config_files() -> tuple[str, ...]: + """Файлы конфигурации для pydantic (корректный разбор кавычек и URL).""" + candidates: list[Path] = [] + explicit = os.environ.get("SAC_CONFIG_FILE", "").strip() + if explicit: + candidates.append(Path(explicit)) + else: + candidates.append(DEFAULT_CONFIG_FILE) + candidates.append(Path(".env")) + return tuple(str(p) for p in candidates if p.is_file()) + + +def _settings_config() -> SettingsConfigDict: + files = _resolve_config_files() + return SettingsConfigDict( + env_file=files if files else None, env_file_encoding="utf-8", extra="ignore", ) + +class Settings(BaseSettings): + model_config = _settings_config() + database_url: str = "postgresql+psycopg2://sac:sac@localhost:5432/sac" sac_public_url: str = "http://localhost:8000" jwt_secret: str = "change-me-in-production" @@ -24,7 +43,7 @@ class Settings(BaseSettings): sac_admin_username: str = "admin" sac_admin_password: str = "" - event_schema_path: str = str(SCHEMA_PATH) # override: EVENT_SCHEMA_PATH + event_schema_path: str = str(SCHEMA_PATH) cors_origins: str = "*" diff --git a/deploy/env.native.example b/deploy/env.native.example index 5794891..cc94991 100644 --- a/deploy/env.native.example +++ b/deploy/env.native.example @@ -1,6 +1,7 @@ # Native: /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 +# sudo chown sac:sac ... && sudo chmod 600 ... +# Пароль в URL — в двойных кавычках. Символ # в пароле допустим только внутри кавычек. +# systemd НЕ парсит этот файл — читает приложение (SAC_CONFIG_FILE). DATABASE_URL=postgresql+psycopg2://sac:CHANGE_ME_POSTGRES_PASSWORD@127.0.0.1:5432/sac diff --git a/deploy/systemd/sac-api.service b/deploy/systemd/sac-api.service index 2e5e860..ae08c9f 100644 --- a/deploy/systemd/sac-api.service +++ b/deploy/systemd/sac-api.service @@ -10,7 +10,8 @@ Type=simple User=sac Group=sac WorkingDirectory=/opt/security-alert-center/backend -EnvironmentFile=/opt/security-alert-center/config/sac-api.env +# Конфиг читает само приложение (pydantic), не systemd — иначе ломаются пароли с #, $ и т.д. +Environment=SAC_CONFIG_FILE=/opt/security-alert-center/config/sac-api.env Environment=PYTHONPATH=/opt/security-alert-center/backend ExecStart=/opt/security-alert-center/backend/.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000 Restart=on-failure diff --git a/docs/install-ubuntu-24.04-native.md b/docs/install-ubuntu-24.04-native.md index 01539c9..bf24d76 100644 --- a/docs/install-ubuntu-24.04-native.md +++ b/docs/install-ubuntu-24.04-native.md @@ -171,7 +171,10 @@ sudo -u sac bash -c 'set -a; source /opt/security-alert-center/config/sac-api.en ## 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 @@ -290,7 +293,8 @@ sudo systemctl restart sac-api | Симптом | Действие | |---------|----------| | `sac-api.env: Permission denied` | Конфиг в `/opt/security-alert-center/config/`, `chown sac:sac`, `chmod 600`. Не используйте `/etc/...` с каталогом `root:root` | -| `password authentication failed for user sac` | Пароль в `DATABASE_URL` ≠ пароль в PostgreSQL; или `.env` не прочитан (тогда берётся дефолт `sac:sac`). Исправить пароль: `sudo -u postgres psql -c "ALTER USER sac PASSWORD '...';"` и обновить `DATABASE_URL` | +| `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` |