# Переменные и секреты

> Как задать настройки приложения, чем секрет отличается от обычной переменной и когда изменения вступают в силу.

Раздел: Приложение
Источник: https://nodbox.ru/docs/apps/env/

---
Переменные и секреты - настройки, которые приложение читает из окружения при запуске: адрес базы, ключ внешнего сервиса, режим работы. Секрет отличается от обычной переменной тем, что платформа хранит его значение зашифрованным и не возвращает никогда: ни в панели, ни по API. Правка набора ничего не деплоит, она доезжает до приложения со следующей версией.

## Чем секрет отличается от переменной

Приложение читает оба набора одинаково, как переменные окружения: `process.env.NAME` в Node.js, `os.environ["NAME"]` в Python. Разница в том, что платформа делает со значением.

| | Переменная | Секрет |
| --- | --- | --- |
| Поле в API | `env` | `secrets` |
| Что отдаёт API | имя и значение | только имя |
| Что показывает панель | значения под точками, кнопка «Показать значения» | «Значение скрыто - показать его платформа не может» |
| Хранение | значение лежит в настройках приложения | значение хранится зашифрованным |
| Как правится в API | набор заменяется целиком | присланное накладывается поверх прежнего |

Что из этого следует на практике:

- Значение секрета видит только само приложение. Платформа показать его не может, поэтому правка секрета - это новое значение, а не редактирование прежнего.
- Обычные переменные видит любой, у кого есть право читать приложение: токен с правом «читать» получает их значения в ответе на `GET /api/v1/applications/{id}`. Пароли, токены и ключи клади в секреты.
- Платформа не вырезает значения секретов из логов приложения. Если приложение само напечатает секрет, он попадёт в [логи](/docs/observability/logs/) как есть. Не печатай переменные окружения целиком.
- Сборке переменные и секреты приложения не видны: у неё свои, они описаны в разделе [Настройки сборки и свой Dockerfile](/docs/deploy/build-settings/).

## Как задать в панели

На странице приложения открой вкладку «Окружение». На ней две карточки: «Переменные окружения» и «Секреты». Те же карточки есть при создании приложения: первая версия снимет их сразу.

Чтобы добавить переменную:

1. Нажми «Добавить переменную».
2. Впиши имя, например `LOG_LEVEL`, и значение.
3. Нажми «Добавить», а потом «Сохранить окружение».

Секрет добавляется так же кнопкой «Добавить секрет». Изменения копятся в черновике, пока не нажата кнопка «Сохранить окружение»: переменные и секреты уходят на платформу одним сохранением. После него панель пишет «Окружение сохранено» и напоминает, что набор применится со следующей версией.

Несколько правил поля:

- Значение многострочное. `Enter` переносит строку, `Ctrl` + `Enter` или `⌘` + `Enter` добавляет переменную. Переводы строк и пробелы по краям сохраняются как есть, поэтому закрытый ключ или сертификат можно вставить целиком. Под значением панель показывает, сколько в нём строк и знаков и стоит ли в конце перевод строки.
- Имя переменной не правится. Чтобы переименовать, удали переменную и добавь заново.
- Над списком панель считает занятые имена: например, «3 переменные и 1 секрет из 100».

Как менять и удалять секрет:

- Рядом с именем нажми «Задать новое» и введи значение. Пока поле пустое, прежнее значение остаётся на месте. Кнопка «Отмена» убирает поле.
- Значок корзины помечает секрет к удалению: в строке появляется «Удалится при сохранении», а «Вернуть» отменяет пометку.
- Новый секрет с пустым значением панель не принимает: имя без значения приложению ничего не даст.

Чтобы превратить переменную в секрет, удали её из переменных и добавь секретом под тем же именем. Одно имя не бывает и переменной, и секретом, поэтому сохранить нужно оба изменения разом: так делает одна кнопка «Сохранить окружение».

## Как задать по API

Переменные и секреты лежат в полях `env` и `secrets` приложения. Их можно прислать при создании, `POST /api/v1/applications`, и поменять запросом `PATCH /api/v1/applications/{id}`:

```json
{
  "env": {
    "NODE_ENV": "production",
    "LOG_LEVEL": "info"
  },
  "secrets": {
    "STRIPE_KEY": "значение секрета",
    "OLD_TOKEN": null
  }
}
```

Поля правятся по-разному, и это важно не перепутать:

- `env` заменяется целиком. Присланный объект и есть новый набор: переменные, которых в нём нет, исчезнут. `{}` убирает все переменные, а если поле не прислать, набор не тронут. Чтобы добавить одну переменную, пришли весь набор вместе с ней.
- `secrets` накладывается поверх прежнего набора. Присланное имя получает новое значение, `null` под именем стирает секрет, неназванные остаются как были. Пустая строка - это значение, а не удаление. При создании приложения `null` в секретах не принимается: стирать нечего.

В ответе `GET /api/v1/applications/{id}` значения `env` лежат картой, а `secrets` - списком одних имён:

```json
{
  "env": { "LOG_LEVEL": "info", "NODE_ENV": "production" },
  "secrets": ["STRIPE_KEY"]
}
```

Список вместо карты сделан намеренно: карту с `null` вместо значений можно было бы отправить обратно в `PATCH` и стереть все секреты разом.

Чтобы превратить переменную в секрет по API, пришли в одном запросе `env` без неё и `secrets` с ней. Запрос с `secrets`, имя в которых ещё занято переменной, отвечает `422`.

Для `POST` хватает права токена «деплоить». `PATCH` требует два права сразу: «деплоить» и «менять мощность», потому что та же ручка правит размер приложения. Подробнее - в разделе [Токены и права](/docs/automation/tokens/).

## Когда изменения вступают в силу

Правка переменных и секретов работающее приложение не трогает. Каждая версия снимает набор в момент заказа и запускается с этим снимком, поэтому переменные, как и размер, живут вместе с версией.

Что из этого следует:

- Поменял переменную или секрет - закажи новую версию. В панели это «Задеплоить снова» на странице приложения, по API - `POST /api/v1/applications/{id}/revisions`, а у приложения из репозитория версию заводит и push в ветку с включённым [автодеплоем](/docs/deploy/auto-deploy/). Версия возьмёт значения, которые записаны в приложении в момент заказа.
- Версия, которая уже заказана и собирается, правку, сделанную после заказа, не заметит. Закажи ещё одну.
- Откат возвращает значения той версии, на которую ты откатился, а не сегодняшние. Если ты сменил пароль в базе, а потом откатился на версию со старым паролем, приложение стартует со старым. Значения секретов тоже входят в снимок версии.
- Запуск остановленного приложения берёт сегодняшние значения, а не те, с которыми приложение работало до остановки.
- Какие значения были у какой версии, платформа не показывает: в истории версий переменных нет. Сегодняшний набор виден на вкладке «Окружение».

Про откат подробнее - в разделе [Версии и откат](/docs/deploy/versions/).

## Имена и значения

| Что | Предел |
| --- | --- |
| Сколько имён | 100 на переменные и секреты вместе |
| Длина имени | до 128 знаков |
| Из чего имя | латинские буквы, цифры и подчёркивание, первый знак - буква или подчёркивание |
| Длина значения | до 4 096 знаков |
| Один набор на имя | имя есть либо среди переменных, либо среди секретов |

Остальное про значения:

- Значение - любой текст в UTF-8: переводы строк, пробелы по краям и пустая строка допустимы и сохраняются как есть. Нулевой байт и текст в другой кодировке платформа не принимает.
- Длина считается в знаках, а не в байтах.
- По API значением может быть строка, число или `true` и `false`. Платформа записывает число или булево строкой, потому что окружение процесса знает только строки: `4` станет `"4"`, а `true` станет `"true"`. Массив, объект и `null` в `env` отвечают `422`.

Нарушение любого предела отвечает `422` с текстом, который называет имя виноватой переменной. Панель проверяет имя и длину до отправки.

## Имена, которые занимает платформа

Платформа сама ставит в окружение приложения `PORT` и все имена, которые начинаются с `K_`. Такие имена задать нельзя. Запрос с ними отвечает `422`: «Имя PORT занято платформой: она подставляет эту переменную сама, и твоё значение потерялось бы». Панель говорит то же прямо в окне добавления.

`PORT` содержит порт приложения из его настроек. Другой порт задаётся настройкой приложения, а не переменной: [Порт, протокол и проверка готовности](/docs/apps/runtime/). Имена на `K_` служебные, и пользоваться ими не нужно.

Это правило действует для рантайма. У сборки свои занятые имена: `PORT` и `K_` там свободны, зато заняты `PATH`, `HOME` и ещё несколько. Список - в разделе [Настройки сборки и свой Dockerfile](/docs/deploy/build-settings/).

## Подключение к базе

Платформа не подставляет строку подключения в приложение сама. У приложения может быть несколько баз, и три строки не могут называться одинаково `DATABASE_URL`, поэтому имя выбираешь ты.

Скопируй строку подключения базы, положи её в секрет под своим именем, например `DATABASE_URL`, и задеплой приложение. Строку, режимы TLS и путь к сертификату базы разбирает страница [Подключение к базе](/docs/databases/connect/).

## Переменные сборки

Переменные и секреты на этой странице видит работающее приложение. Сборка видит другие: `build_env` и `build_secrets`. Одно и то же имя, например `NODE_ENV`, можно задать в обоих наборах с разными значениями: это две настройки двух разных этапов. Если значение нужно и сборке, и приложению, задай его в обоих местах. Как это устроено, разобрано в разделе [Настройки сборки и свой Dockerfile](/docs/deploy/build-settings/).

## Что дальше

- [Версии и откат](/docs/deploy/versions/) - как версия хранит переменные и что возвращает откат
- [Настройки сборки и свой Dockerfile](/docs/deploy/build-settings/) - переменные и секреты сборки
- [Подключение к базе](/docs/databases/connect/) - строка подключения секретом приложения
- [Порт, протокол и проверка готовности](/docs/apps/runtime/) - откуда берётся `PORT`
- [Автодеплой по push](/docs/deploy/auto-deploy/) - как правка набора доезжает без ручного заказа
- [Токены и права](/docs/automation/tokens/) - какие права нужны для правки приложения
- [Логи приложения](/docs/observability/logs/) - куда попадает всё, что приложение печатает само
