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

Настройки читаются из .env библиотекой python-decouple (AutoConfig с поиском в /workdir). Шаблон — env-dist; всё, чего нет в .env, берётся из значений по умолчанию в network/settings.py.

Важно

Секреты никогда не хардкодятся и не попадают в образ. В коде — только config("VAR_NAME", default=...). .env монтируется в контейнер во время выполнения.

Ниже — все переменные, которые читает network/settings.py, по разделам; в env-dist они же с умолчаниями. Полноту обоих списков проверяет network/base/test_settings_documented.py: переменная, которой нет в одном из них, роняет CI.

Базовые

Переменная

По умолчанию

Назначение

ENVIRONMENT

dev

При production включается задача parse_data_from_satnogs

DEBUG

False

Режим отладки и Django Debug Toolbar

SECRET_KEY

нет

Секретный ключ Django. Обязателен: без него портал не стартует

ALLOWED_HOSTS

localhost

Список через запятую; 127.0.0.1 и web добавляются всегда

CSRF_TRUSTED_ORIGINS

пусто

Список через запятую

DATABASE_URL

sqlite:///db.sqlite3

В Docker переопределяется на PostgreSQL

CONN_MAX_AGE

60

Сколько секунд держать соединение с БД между запросами; 0 — новое на каждый запрос

SESSION_ENGINE

cached_db

Хранилище сессий Django: чтение из кэша, запись насквозь в БД

LOCALE_PATHS

network/locale

Каталог переводов

LOGIN_URL, LOGIN_REDIRECT_URL

account_login (при OIDC_AUTH — oidc_authentication_init), users:redirect_user

Имена маршрутов входа и перехода после него

MEDIA_VOLUME_PATH

/opt/storage/network_volumes/media_volume

Каталог хоста для медиа web и celery; читает Compose. Должен существовать до up — локально ./media

REGISTRY_VOLUME_PATH

/opt/storage/network_volumes/registry

Каталог хоста для кэша сервиса registry; читает Compose

SONIKS_IMAGE

пусто

Тег образа, который деплой записал в .env; показывается на странице «Система»

DOCS_URL

GitLab Pages проекта

Куда ведёт /docs/network/

DOCS_HUB_URL

GitLab Pages soniks-docs

Куда ведёт остальной /docs/ — хаб документации

IGNORE_MIGRATION

False

Не используется: код, который его читал, снят при инициализации форка (e957dd00)

Безопасность

Переменная

По умолчанию

Назначение

SECURE_HSTS_SECONDS

31536000

Срок HSTS, с

SECURE_PROXY_SSL_HEADER

пусто

Заголовок прокси, подтверждающий HTTPS, в виде HTTP_X_FORWARDED_PROTO,https

SECURE_SSL_REDIRECT

включён, если задан SECURE_PROXY_SSL_HEADER и выключен DEBUG

Редирект на HTTPS. Без заголовка прокси за nginx он зациклится

NUM_PROXIES

пусто

Сколько прокси перед gunicorn дописывают X-Forwarded-For. Пусто — лимиты API различают анонимов по всему заголовку, который клиент может подменить. 1 — только если перед приложением ровно один nginx, пишущий заголовок; при лишнем балансировщике все анонимы окажутся в одном счётчике

SESSION_COOKIE_SECURE, CSRF_COOKIE_SECURE

not DEBUG

Cookie только по HTTPS. Выключать только на стенде, который действительно работает по HTTP, иначе туда никто не войдёт

Content Security Policy

Каждая переменная — список источников через запятую для одной директивы. Значение заменяет умолчание целиком, поэтому переопределение повторяет всё, что ещё нужно; пустое значение означает 'none'. Значения с кавычками в .env берутся в двойные кавычки: CSP_FRAME_ANCESTORS="'none'".

'unsafe-inline' и 'unsafe-eval' в умолчаниях нет: атрибут style="…" в разметке браузер отбрасывает, и так задумано (см. фронтенд). К style-src код сам добавляет nonce, но только на двух страницах со звуковым плеером (наблюдение и оценка), — через переменную его не задать и не убрать.

Переменная

Директива

По умолчанию

CSP_DEFAULT_SRC

default-src

'self', Mapbox, archive.org, blob:

CSP_SCRIPT_SRC

script-src

'self'

CSP_IMG_SRC

img-src

'self', Gravatar, Mapbox, SatNOGS, Yandex Object Storage, data:, blob:

CSP_STYLE_SRC

style-src

'self' (+ nonce на страницах с плеером)

CSP_WORKER_SRC

worker-src

blob:

CSP_CHILD_SRC

child-src

blob:

CSP_FRAME_SRC

frame-src

blob:,https://dashboard.sonik.space — без хоста дашборда вкладка «Телеметрия» спутника пустая

CSP_FRAME_ANCESTORS

frame-ancestors

'none' — портал нельзя встроить во фрейм

Внешние сервисы

Переменная

Назначение

MAPBOX_TOKEN, MAPBOX_MAP_ID

Рендер карт станций и наблюдений

DB_API_ENDPOINT, DB_API_KEY, DB_API_TIMEOUT

SatNOGS DB — источник спутников и передатчиков

NETWORK_API_ENDPOINT

SatNOGS Network — источник данных для parse_data_from_satnogs

SATNOGS_DB_PROXY_URL

Исходящий HTTP(S)-прокси только для API db.satnogs.org и network.satnogs.org, если хосты заблокированы на уровне хостинга

EXTERNAL_IMPORT_USER_AGENT

Как портал представляется nanosats.eu, Wikidata и Wikimedia Commons при импорте паспортных данных. Wikimedia требует от автоматических клиентов осмысленного агента с контактом — адрес в нём должен быть рабочим

LL2_API_URL

Хост Launch Library 2, источника календаря запусков. По умолчанию боевой https://ll.thespacedevs.com/2.3.0; для локальной работы — https://lldev.thespacedevs.com/2.3.0 (без лимита, данные усечены). См. Запуски

LL2_HOURLY_BUDGET

Сколько запросов в час задача sync_launches_from_ll2 может потратить на LL2. По умолчанию 15 — анонимный лимит боевого хоста; поднимать только вместе с ключом, который поднимает лимит

COMMUNITY_TIMEOUT

Таймаут запроса к форуму сообщества, с (2.0)

WIKI_STATION_URL

Не используется: значок-ссылка на вики для владельца на странице станции снят редизайном раздела (763df9ad)

Орбитальные данные

Переменная

По умолчанию

Назначение

SPACE_TRACK_USERNAME, SPACE_TRACK_PASSWORD

пусто

Учётка Space-Track для загрузки каталога

TLE_PRIORITY_FRESHNESS_DAYS

7

Насколько дней приоритетный источник может отставать и всё ещё выигрывать

LATEST_TLES_MAX_AGE_DAYS

30

Предельный возраст TLE для публичной выдачи /api/latesttles/

SPACE_WEATHER_URL

файл CelesTrak

Индексы солнечной и геомагнитной активности для прогноза схода

DECAY_PERIGEE_ALTITUDE_KM

120

Высота перигея, ниже которой спутник считается сошедшим

DECAY_FORECAST_HORIZON_DAYS

365

Насколько далеко вперёд считается прогноз схода

DECAY_DAILY_FORECAST_DAYS

45

До какого срока прогноз опирается на суточные индексы; дальше дата показывается как оценка

DECAY_CONFIRM_LOOKBACK_DAYS

30

Глубина чтения фида подтверждённых сходов Space-Track

DECAY_TLE_SILENCE_DAYS

30

Сколько дней ни один источник не публикует TLE, прежде чем молчание считается сходом

Примечание

Дата схода считается по модели атмосферы NRLMSIS, которой управляют индексы F10.7 и Ap из SPACE_WEATHER_URL. Суточное разрешение у этих индексов есть примерно на полтора месяца вперёд, дальше известна только сглаженная кривая солнечного цикла — поэтому дата за границей DECAY_DAILY_FORECAST_DAYS показывается со знаком «≈».

Баллистический коэффициент не берётся из B* в TLE: это подгоночный параметр SGP4, вбирающий разницу между реальностью и его собственной грубой атмосферой, и в другой модели он занижает сопротивление в разы. Вместо этого коэффициент подгоняется под наблюдаемый спад самого спутника.

Если индексы недоступны и в кеше их нет, суточная задача расчёта орбитальных параметров не выполняется: прежние даты точнее, чем посчитанные без атмосферы.

Примечание

Прогноз даты схода и перевод спутника в статус «Сошёл с орбиты» — разные вещи. Статус меняет суточная задача confirm_satellite_reentries, и по прогнозу она этого не делает никогда: нужен либо подтверждённый сход из фида Space-Track, либо молчание всех источников TLE дольше DECAY_TLE_SILENCE_DAYS вместе с уже прошедшей прогнозной датой. Без учётки Space-Track работает только второе правило. Подробности — в Спутники и передатчики.

Примечание

На dev-стенде и в проде учётные данные Space-Track подставляются при деплое из CI/CD-переменных GitLab (SPACE_TRACK_*_DEV и SPACE_TRACK_*_PROD), а не берутся из env-dist на сервере. Стенд и прод используют разные аккаунты, чтобы не упереться в лимиты сессий Space-Track. Подробности — в Орбитальные данные (TLE) и CI/CD и деплой.

Планирование наблюдений

Переменная

По умолчанию

Назначение

OBSERVATION_DATE_MIN_START

4

Минимальный отступ начала наблюдения, мин — для станции без живого MQTT; станция на связи заявляет свой порог в секундах (см. Планирование наблюдений)

OBSERVATION_DATE_MAX_RANGE

—

Горизонт планирования

OBSERVATION_DURATION_MIN

120

Минимальная длительность, с

OBSERVATION_SPLIT_DURATION

720

Порог разбиения длинного окна, с

OBSERVATION_SPLIT_BREAK_DURATION

—

Пауза между частями разбитого окна

OBSERVATION_MAX_QUERY_COUNT

—

Ограничение выборки при планировании

NETWORK_SCHEDULER_USERNAME

admin

Аккаунт, от имени которого планирует сетевое расписание

OBSERVATIONS_PER_VIOLATOR_SATELLITE, OBSERVATIONS_PER_VIOLATOR_SATELLITE_PERIOD

2, 86400 с

Квота на спутники-нарушители частот: сколько наблюдений за период

OBSERVATION_WARN_MIN_OBS

30

Порог числа наблюдений, ниже которого форма планирования предупреждает

PASS_PREDICTIONS_CACHE_TTL

60 с

Сколько переиспользуется ответ с прогнозом пролётов. Коротко намеренно: флаг пересечения отражает текущее расписание

FUTURE_OBS_MAX_RANGE_DAYS, FUTURE_OBS_THROTTLE_RATE

7, 20/min

Предельное окно и лимит частоты /api/future_satellite_obs

Для наблюдений новых запусков — отдельный набор: LAUNCH_BREAK_DURATION, LAUNCH_SPLIT_DURATION (480), LAUNCH_MIN_ELEVATION (5), LAUNCH_GOOD_ELEVATION (25), LAUNCH_MIN_HORIZON (0), LAUNCH_MIN_PERIOD (48), LAUNCH_WAITING_FOR_SATELLITE.

Станции

Переменная

По умолчанию

Назначение

STATION_HEARTBEAT_TIME

60

Период сердцебиения станции, с

STATION_UPCOMING_END

24

Горизонт «ближайших» наблюдений, ч

MAX_ANTENNAS_PER_STATION

4

Лимит антенн

MAX_FREQUENCY_RANGES_PER_ANTENNA

5

Лимит диапазонов на антенну

MIN_FREQUENCY_FOR_RANGE, MAX_FREQUENCY_FOR_RANGE

300, 40000000000 Гц

Допустимые границы диапазона антенны

VHF_MIN_FREQUENCY, VHF_MAX_FREQUENCY

135000000, 148000000 Гц

Границы VHF для классификации

UHF_MIN_FREQUENCY, UHF_MAX_FREQUENCY

400000000, 470000000 Гц

Границы UHF

L_MIN_FREQUENCY, L_MAX_FREQUENCY

1050000000, 1750000000 Гц

Границы L-диапазона

S_MIN_FREQUENCY, S_MAX_FREQUENCY

2200000000, 2450000000 Гц

Границы S-диапазона

JOBS_ALLOW_ANONYMOUS

True

Отвечает ли GET /api/jobs/ без токена. Выключать, когда весь парк запрашивает расписание с токеном: JobView пишет предупреждение на каждый анонимный запрос

OBS_AUDIO_DURATION_TOLERANCE

120 с

На сколько аудио может расходиться с длительностью наблюдения, прежде чем оно оценивается как «failed»

DEMODDATA_TIME_TOLERANCE_MINUTES

5

Насколько метка времени кадра может выходить за окно наблюдения — допуск на дрейф часов станции

OBS_NO_RESULTS_CHECK_PERIOD

—

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

OBS_NO_RESULTS_MIN_COUNT

3

Сколько пустых наблюдений подряд считать проблемой

OBS_NO_RESULTS_IGNORE_TIME

—

Сколько ждать после конца наблюдения, прежде чем считать его провалившимся

EMAIL_FOR_STATIONS_ISSUES

пусто

Адрес для уведомлений о проблемных станциях

AUTO_TRANSMITTER_DRIFT

False

Применять ли ночной задаче поправки downlink_drift передатчиков, вычисленные по откалиброванным станциям; выключено — задача только пишет в лог, что изменила бы

Хранение артефактов

Аудио, водопады и данные могут лежать локально или в S3-совместимом хранилище — независимо друг от друга:

Переменная

Назначение

USE_S3_STORAGE_FOR_AUDIO

Аудио в S3

USE_S3_STORAGE_FOR_WATERFALL

Водопады в S3

USE_S3_STORAGE_FOR_DATA

Демодулированные данные в S3

AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_STORAGE_BUCKET_NAME, AWS_S3_ENDPOINT_URL, AWS_QUERYSTRING_AUTH

Доступ к бакету

BACKUP_S3_BUCKET

Отдельный приватный бакет для суточных дампов БД, те же ключи AWS_*; пусто — задача не регистрируется (см. Эксплуатация)

MEDIA_ROOT, STATIC_ROOT, MEDIA_URL, STATIC_URL

Локальные пути и URL

FILE_UPLOAD_TEMP_DIR

Каталог для загрузок, не поместившихся в память (/tmp)

Архивация аудио (упаковка в zip и выгрузка на archive.org) включается отдельно: ZIP_AUDIO_FILES, AUDIO_FILES_PER_ZIP (1000), ZIP_FILE_PREFIX, ARCHIVE_ZIP_FILES, ZIP_FILES_PER_ITEM (10), ARCHIVE_COLLECTION, ARCHIVE_MEDIA_TYPE (data), ITEM_IDENTIFIER_PREFIX, ITEM_TITLE_PREFIX, ARCHIVE_SKIP_TIME (48 ч), REMOVE_ARCHIVED_AUDIO_FILES, REMOVE_ARCHIVED_ZIP_FILE, S3_ACCESS_KEY, S3_SECRET_KEY, S3_RETRIES_ON_SLOW_DOWN, S3_RETRIES_SLEEP. Сроки блокировок в кэше, с: ZIP_AUDIO_LOCK_EXPIRATION (600, дописывание файла в архив), ZIP_TASK_LOCK_EXPIRATION (3600, задача упаковки), ARCHIVE_TASK_LOCK_EXPIRATION (86400, задача выгрузки), ARCHIVE_ZIP_LOCK_EXPIRATION (21600, выгрузка одного архива). ARCHIVE_AUDIO_LOCK_EXPIRATION не используется: задача, которая его читала, снята в 22119248.

Примечание

Задачи zip_audio_files и archive_audio_zip_files регистрируются в расписании только если соответствующий флаг включён и USE_S3_STORAGE_FOR_AUDIO выключен — при хранении аудио в S3 паковать нечего.

Данные наблюдений и проверка

Переменная

По умолчанию

Назначение

EXPORTED_FRAMESET_TIME_TO_LIVE

86400 с

Сколько хранится выгрузка кадров, прежде чем её удалит периодическая задача

PROCESS_AUDIO_LOCK_EXPIRATION

900 с

Срок блокировки задачи обработки аудио

VET_ITEMS_PER_CHUNK

20

Сколько наблюдений подгружает за раз страница массовой проверки

CHUNKS_BUFFER_HEADSTART, FWD_BUFFER_CHUNKS, BWD_BUFFER_CHUNKS

1, 2, 2

Сколько порций страница проверки подгружает сразу при открытии и сколько держит загруженными впереди и позади текущей

NOT_SYNCED_MODES

список аналоговых режимов

Не используется: синхронизация демодулированных данных в SatNOGS DB, которая его читала, снята в a77b17ff

Статика

Переменная

По умолчанию

Назначение

COMPRESS_ENABLED

False

Сборка скриптов и стилей страниц в общие файлы django-compressor. JS не минифицируется: минификатор ломал tom-select и mapbox-gl (комментарий COMPRESS_FILTERS в settings.py)

COMPRESS_OFFLINE

False

Собирать заранее: bin/djangoctl.sh выполняет compress --force при старте контейнера, страницы читают его манифест. На сервере включается только вместе с COMPRESS_ENABLED: без него бандлы собираются по первому запросу, имена лежат в кэше, а collectstatic --clear при следующем старте стирает сами файлы

COMPRESS_CACHE_BACKEND

default

Кэш, в котором компрессор хранит имена собранных файлов

SASS_BINARY

dart-sass из node_modules или sass из PATH

Путь к dart-sass для SCSS. Задаётся там, где нет ни того ни другого — например в тестовой джобе CI

Registry образов станций

Читаются Compose, а не settings.py: сервис registry в docker-compose.yml — pull-through cache Docker Hub для станций. Устройство и сниппет nginx — в CI/CD и деплой.

Переменная

Назначение

COMPOSE_PROFILES

registry поднимает сервис. Только на сервере, где nginx ведёт /v2/ на него

REGISTRY_PORT

Порт на loopback, куда nginx проксирует /v2/; умолчание 5000. На проде 5000 занят sonik_globus — задать свободный и тот же порт в сниппете nginx

REGISTRY_PROXY_USERNAME, REGISTRY_PROXY_PASSWORD

Read-only токен Docker Hub. Пусто — анонимно: работает, но промахи кэша упираются в лимит Docker Hub по IP

MQTT-брокер

Живой канал со станциями (сервисы mosquitto и mqtt-bridge под профилем mqtt). Устройство и сниппет nginx — в CI/CD и деплой.

Переменная

Назначение

COMPOSE_PROFILES

mqtt (вместе с registry: registry,mqtt) поднимает брокер и мост. Только на сервере, где nginx ведёт /mqtt на брокер

MQTT_BROKER_HOST, MQTT_BROKER_PORT

Адрес брокера для публикации и моста; в compose — mosquitto, 1883. Пусто — публикации нет, станции забирают конфигурацию REST’ом

MQTT_PORTAL_USERNAME, MQTT_PORTAL_PASSWORD

Служебный логин портала на брокере. Проверяется самим порталом в /api/v2/mqtt/auth/

Авторизация через Keycloak

OIDC_AUTH (False) включает вход через OIDC-провайдера. Дополнительно: OIDC_RP_CLIENT_ID, OIDC_RP_CLIENT_SECRET, OIDC_OP_AUTHORIZATION_ENDPOINT, OIDC_OP_TOKEN_ENDPOINT, OIDC_OP_USER_ENDPOINT, OIDC_OP_JWKS_ENDPOINT, OIDC_OP_LOGOUT_ENDPOINT, OIDC_KEYCLOAK_URL, OIDC_REALM, OIDC_ADMIN_SERVICE_ID, OIDC_ADMIN_SERVICE_SECRET.

Лимиты попыток входа

Локальный вход и регистрация идут через django-allauth, и его лимиты действуют по умолчанию, без отдельных переменных: пять неверных паролей на одно имя пользователя за пять минут блокируют имя (даже с верным паролем), плюс десять неудачных попыток в минуту с одного IP; регистрация — 20 в минуту с IP, сброс пароля — 20 в минуту с IP и 5 в минуту на адрес. Блокировка по имени показывается ошибкой формы входа, лимиты по IP — страницей 429. Счётчики живут в кэше (CACHE_BACKEND): с Redis они общие для всех воркеров, с locmem — на процесс. Переопределяются словарём ACCOUNT_RATE_LIMITS в settings.py (ключи login_failed, login, signup, reset_password; False отключает всё). Вход через OIDC этим лимитам не подчиняется. Проверка — network/users/test_login_rate_limit.py.

Celery, кэш, лимиты API

Переменная

По умолчанию

CELERY_BROKER_URL

redis://redis:6379/0

CELERY_RESULT_BACKEND

redis://redis:6379/0

REDIS_VISIBILITY_TIMEOUT

3600 с — через сколько брокер переотправит неподтверждённую задачу; должен быть больше любого time_limit, иначе долгая задача выполнится дважды (проверяет test_settings_wiring)

CELERY_RESULT_EXPIRES

3600 с — он же потолок длительности стадии автопланирования

CELERY_TASK_SOFT_TIME_LIMIT, CELERY_TASK_TIME_LIMIT

600 / 900 с — мягкий лимит бросает SoftTimeLimitExceeded внутри задачи, жёсткий убивает процесс; у бэкапа и обходов каталога свои лимиты в network/celery.py

CELERY_TASK_ACKS_LATE, CELERY_TASK_REJECT_ON_WORKER_LOST

True — задача подтверждается после выполнения и возвращается в очередь, если воркер погиб

CELERY_WORKER_PREFETCH_MULTIPLIER

1 — воркер не резервирует задачи впрок

CELERY_WORKER_CONCURRENCY

4 — число процессов воркера; не от числа ядер, потому что от него посчитан mem_limit сервиса celery (см. Эксплуатация)

CACHE_BACKEND, CACHE_LOCATION, CACHE_TTL

300 с

DOCKER_API_URL

http://docker-proxy:2375 — Docker Engine API для страницы «Система» (см. Эксплуатация); пустое значение прячет секции контейнеров и логов

LATEST_TLES_THROTTLE_RATE

60/min

OBSERVATIONS_LIST_ANON_THROTTLE_RATE, OBSERVATIONS_LIST_AUTH_THROTTLE_RATE

60/hour, 240/hour — чтение списка наблюдений анонимно и с токеном

STATIONS_LIST_ANON_THROTTLE_RATE

256/hour — анонимное чтение списка станций

ANALYTICS_THROTTLE_RATE

120/min

ANALYTICS_HEAVY_THROTTLE_RATE

30/min

DEMODDATA_CREATE_THROTTLE_RATE

3600/hour — отправка кадров SIDS в /api/demoddata/, на пользователя или на IP анонима

STATION_STATUS_THROTTLE_RATE

1200/hour — отчёт станции POST /api/v2/stations/<id>/status/ на владельца; чтение не ограничено

ITEMS_PER_PAGE

25

InfluxDB

Необязательная интеграция для телеметрии: USE_INFLUX, INFLUX_URL, INFLUX_TOKEN, INFLUX_BUCKED, INFLUX_ORG.

Почта

EMAIL_HOST, EMAIL_PORT, EMAIL_USE_TLS, EMAIL_USE_SSL, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, DEFAULT_FROM_EMAIL, SERVER_EMAIL, EMAIL_ADMIN, EMAIL_TIMEOUT.

По этой же почте уходят необработанные ошибки: обработчик mail_admins на логгере django.request шлёт трассировку каждого 500 на EMAIL_ADMIN. Фильтр require_debug_false гасит отправку при DEBUG=True, поэтому локальный запуск никому не пишет. Ограничения частоты нет: цикл отказов даст письмо на каждый запрос.

Важно

Так что EMAIL_HOST и EMAIL_ADMIN на сервере — не декоративные. Пока они не настроены, об ошибках портала не узнаёт никто: обработчик отработает, письмо не уйдёт, а AdminEmailHandler проглотит сбой SMTP молча, чтобы не ронять запрос.