Переменные среды CGI
При запуске CGI-скрипта веб-сервер передает ему целый ряд параметров в переменных среды. Часть переменных среды генерируется веб-сервером, а другая часть формируется из полей HTTP-запроса.
В "Спецификации CGI/1.1" описан стандартный набор переменных среды CGI, формируемых веб-сервером, а также способ передачи CGI-скрипту полей HTTP-запроса в переменных среды. Кроме того, ряд веб-серверов (включая Apache) помимо стандартных формируют свои переменные, в которых передают скрипту дополнительные ("нестандартные") параметры (E-Mail администратора сервера и т.п.).
Здесь рассмотрены как стандартные переменные среды CGI, так и переменные, формируемые сервером Apache.
Переменные среды CGI на конкретном хостинге.
Чтобы увидеть все доступные CGI-скрипту переменные среды на конкретном сервере, Вы можете запустить на нем CGI-скрипт, выводящий имена и значения всех своих переменных среды:
В зависимости от условий вызова (HTTP-метод, прямой или через SSI. ) набор переменных может быть различным, поэтому попробуйте вызывать этот скрипт различными путями и смотрите результаты работы.
Переменные среды CGI, формируемые веб-сервером.
QUERY_STRING — строка параметров вызова (все символы, записанные в URL после знака ‘?’).
REQUEST_METHOD — метод HTTP, с помощью которого вызван скрипт. Чаще всего это методы GET или POST, хотя в принципе могут быть и другие (PUT, DELETE и т.п.).
GATEWAY_INTERFACE — версия интерфейса CGI в виде CGI/x.y. Например, CGI/1.1
REMOTE_ADDR — содержит IP-адрес компьютера, с которого произошло обращение к веб-серверу (адрес клиента либо последнего прокси-сервера).
REMOTE_PORT — TCP-порт удаленного компьютера, с которого идет запрос.
REMOTE_HOST — доменное имя удаленного компьютера, с которого идет запрос (определяется веб-сервером через DNS по значению REMOTE_ADDR, если это разрешено его конфигурацией).
SERVER_NAME — доменное имя сервера.
SERVER_PORT — номер TCP-порта веб-сервера.
SERVER_ADDR — IP-адрес сервера.
SERVER_PROTOCOL — версия HTTP-протокола, используемая для данного HTTP-запроса. Например, HTTP/1.1.
SERVER_SOFTWARE — программное обеспечение сервера.
SCRIPT_NAME — HTTP-путь к скрипту.
SCRIPT_FILENAME — физический полный путь к скрипту в файловой системе сервера.
PATH_INFO — HTTP-путь к скрипту.
PATH_TRANSLATED — полный физический путь к скрипту.
Если используемый для запроса HTTP-метод предусматривает передачу содержимого в теле запроса, то передаются следующие переменные:
CONTENT_TYPE — тип содержимого (MIME).
CONTENT_LENGTH — длина содержимого
Если произошел аутентифицированный запрос (с указанием имени пользователя и пароля), то передаются переменные:
AUTH_TYPE — тип аутентификации (используемая аутентификационная схема). Чаще всего — ‘Basic’.
REMOTE_USER — имя пользователя, прошедшего аутентификацию.
Если скрипт рассчитан на обслуживание нескольких пользователей, по параметру REMOTE_USER он может их различать. Следует иметь в виду, что если CGI-скрипт уже запущен и ему передан параметр REMOTE_USER, то пользователь УЖЕ успешно прошел аутентификацию на уровне веб-сервера
Переменные CGI-среды Apache
Веб-сервер Apache, в зависимости от версии, может передавать дополнительные переменные, в часности, такие:
DOCUMENT_ROOT — физический путь к корневому WWW-каталогу сервера.
SERVER_ADMIN — E-Mail адрес администратора сервера.
Может использоваться, например, для отправки администратору письма через программу sendmail или в выводе сообщения об ошибке: если ошибка носит непредвиденный характер, скрипт может посоветовать пользователю сайта обратиться к администратору по "такому-то" E-Mail.
SERVER_SIGNATURE — подпись к страницам, сгенерированным сервером (листингам, сообщениям об ошибке). Например: Apache/1.3.3 Server at takoi-to.host.com Port 80
Может использоваться скриптом для "эмуляции" определенной ошибки. Например, если к скрипту обратиться с неправильными параметрами, то можно скрыть сам факт существования такого скрипта, выдав сообщение "Not Found".
Преобразование HTTP-полей запроса в переменные среды
Способ преобразования имен HTTP-полей запроса в имена переменных среды CGI-скрипта следующий:
1. все символы переводятся в верхний регистр;
2. символы ‘-‘ заменяются на ‘_’;
3. в начале имени переменной добавляется ‘HTTP_’.
Таким образом, значение поля HTTP-запроса Connection записывается в переменную среды HTTP_CONNECTION, а значение поля Accept-Language — в переменную HTTP_ACCEPT_LANGUAGE.
Надо сказать, что в большинстве случаев не все поля HTTP-запроса передаются CGI-скрипту.
HTTP_HOST — имя хоста, к которому идет обращение. Удобно, если скрипт обслуживает несколько виртуальных хостов.
HTTP_USER_AGENT — программное обеспечение клиента, сделавшего запрос. Например, Mozilla/4.7 [en] (Win95; I).
HTTP_ACCEPT — список поддерживаемых клиентом типов содержимого (через запятую, в порядке предпочтения).
HTTP_ACCEPT_LANGUAGE — список поддерживаемых браузером языков в виде двухбуквенных наименований (через запятую), например: ru,en. Удобно, если скрипт может выдавать ответы на нескольких языках (скажем, для русскоязычных и англоязычных посетителей сайта).
HTTP_ACCEPT_ENCODING — список поддерживаемых методов сжатия ответа.
Например: gzip,deflate.
HTTP_ACCEPT_CHARSET — список поддерживаемых кодировок текста (через запятую, в порядке предпочтения).
HTTP_CONNECTION — желаемый браузером режим работы соединения: Keep-Alive (после ответа на запрос сервер не разрывает соединения) и Close (сервер разрывает соединение после ответа на запрос).
HTTP_REFERER — значение поля Referer HTTP-запроса. В этом поле браузер передает URL ресурса, по ссылке с которого был запрошен данный ресурс.
Если пользователь переходит по ссылке со страницы A на страницу B, то в поле Referer HTTP-запроса страницы B будет URL страницы A.
*
Для картинок, внешних JavaScript и др. ресурсов, вставляемых в страницу, в поле Referer передается URL страницы, в которую они вставлены.
*
Для ресурсов-скриптов, вставленных через SSI, в переменной HTTP_REFERER передается то же, что и для страницы, куда они вставлены.
HTTP_X_FORWARDED_FOR — если пользователь работает через прокси-сервер, то последний формирует поле X-Forwarded-For, в котором указывает IP-адрес, с которого идет запрос к прокси. Если поле X-Forwarded-Forуже существует в запросе прокси-серверу, то он добавляет к уже существующему полю новое значение через запятую. Таким образом, если клиент работает "каскадно" через несколько прокси-серверов, то первый прокси-сервер создаст поле X-Forwarded-For с IP клиента, а каждый последующий прокси-сервер добавит к уже существующему полю X-Forwarded-For адрес предыдущего прокси через запятую.
Таким образом, можно отследить всю цепочку каскадно включенных прокси- серверов, если, конечно, ни один из них не является "анонимным".
При этом надо иметь в виду, что IP-адрес работающего через прокси клиента может и не принадлежать Интернету, если клиент работает из локальной сети. Обычно для локальных сетей используются адреса вида 172.16.x.y.
Переменные среды, передаваемые CGI-скрипту, вызванному через SSI.
CGI-скрипту, вызванному через SSI, сервером Apache передаются также дополнительные переменные среды:
QUERY_STRING_UNESCAPED — параметры вызова не самого скрипта, а содержащей его веб-страницы. Все escape-последовательности вида %xx уже заменены на символы. В переменной QUERY_STRING, как обычно, передаются параметры вызова самого скрипта в SSI-директиве. Таким образом, CGI-скрипт, вызванный через SSI, может обрабатывать параметры вызова содержащей его HTML-страницы, если они есть.
REQUEST_URI — HTTP-путь к веб-странице, содержащей SSI-директиву вызова скрипта.
DOCUMENT_NAME — имя файла документа (веб-страницы), в которую вставляется результат работы скрипта.
DOCUMENT_URI — HTTP-путь к веб-странице, вызвавшей этот скрипт.
LAST_MODIFIED — дата последнего изменения документа, в который вставлен результат работы этого скрипта.
DATE_LOCAL и DATE_GMT — соответственно местные дата-время и дата-время по Гринвичу.
Для CGI-скриптов, вызванных через SSI, переменная SERVER_PROTOCOL имеет значение ‘INCLUDED’.
Всё, что вы должны знать о переменных окружения в PHP Перевод
Переменные окружения, используемые в конфигурации, являются на сегодняшний день основным методом установки в приложении таких настроек, как учетные данные базы, API ключи, секретные ключи и всего, что является различным в зависимости от того, где развертывается приложение. Сейчас такие настройки попадают в код через окружение, вместо прямого прописывания в файлах конфигурации или, того хуже, хардкода прямо в коде.

Давайте подробнее взглянем на то:
- как это работает?
- действительно ли это хорошая идея?
- как с ними работать в PHP?
- и в заключение на некоторые рекомендации и распространенные ошибки, которых следует избегать – на те ловушки, на которые мы наткнулись в реальном мире!
Мы не будем рассматривать как настроить переменные окружения в вашем веб-сервере / Docker-е / crontab-ах. т. к. это зависит от системы, программного обеспечения, а мы хотим сосредоточиться на самих переменных окружения.
Если ваш хостинг использует Docker Swarm или AWS, все будет немного по-другому, например, т. к. они решили подсовывать файлы на файловую систему вашего контейнера, чтобы внедрить ваши секретные ключи, а не использовать переменные окружения. Это очень специфично для этих платформ и не является распространённым вариантом для всех.
Env vars 101
При запуске программы, она наследует все переменные окружения от своих родителей. Так что если вы установите переменную YOLO в значение covfefe в bash, а затем выполните команду, вы сможете прочитать YOLO в любом дочернем процессе.
Поскольку эта переменная определена только локально, мы не можем прочитать её из другого терминала (другого родителя). Идея в том, чтобы убедиться, что ваше приложение всегда наследует нужные переменные.
Вы можете посмотреть все переменные окружения в командной строке, выполнив следующую команду, но вы не увидите переменной YOLO , т. к. она была передана только в команду php "на лету", а не установлена в текущем процессе:
Вы можете установить переменную окружения с помощью export <имя>=<значение> :
Имена переменных чувствительны к регистру и соглашение заключается в использовании имён только на английском, в верхнем регистре, с _ в качестве разделителя (т. н. "змеиный" стиль в верхнем регистре). Вы уже наверняка знаете некоторые переменные – такие как PATH , DISPLAY , HTTP_PROXY …
Лучшие практики на сегодня
Возможно, вы уже знаете о двенадцати факторной методологии для создания надежных и масштабируемых приложений (если нет, то я предлагаю вам сделать перерыв и проверить его). Глава о конфигурации объясняет, почему сохранение конфигов в окружении это правильный путь:
- Конфигурация существенно отличается в зависимости от того, где развёрнуто приложение (production, staging, testing…), код – нет.
- Переменные окружения легко изменять на разных машинах без изменения кода.
- Они являются стандартом и не зависят от используемого язык или ОС. Одни и же конфигурации могут использоваться и PHP, и Python процессами.
Манифест также довольно хорошо описывает что должно быть в коде и что должно быть в окружении – не кладите все настройки приложения в него, только то, что отличается у одного развернутого стенда от другого.
Я читал(а) в Интернете, что переменные окружения опасны
Некоторые статьи расскажут вам, что переменные окружения вредны для ваших секретных ключей. Главная причина заключается в том, что любой процесс наследует от своего родителя переменные, все из них. Так что если у вас очень секретная настройка в окружающей среде, дочерние процессы будут иметь доступ к нему:
Дочерние процессы могут рассматривать переменную окружения, как что-то публичное, что можно записать в логи, включить в отчеты об ошибках, вывести пользователю в случае ошибки. Они могут допустить утечку ваших секретных ключей.
Альтернатива – старые текстовые файлы, со строгими Unix-правами. Но что действительно должно быть сделано, очистка окружения при запуске дочернего процесса, которому вы не доверяете, как это делает nginx. По умолчанию nginx удаляет все переменные окружения, унаследованные от своего родительского процесса, за исключением переменной TZ. Проблема решена!
Это можно сделать с помощью команды env -i , которая говорит, что следующие команды должны быть запущены в пустой среде.
Всегда запускайте процессы, которым вы не доверяете, в ограниченной среде.
Даже если вы доверяете вашему коду, вы всё равно должны быть очень осторожны и передавать ваши переменные как можно меньшему количеству процессов – кто и как их будет использовать вы никогда не знаете (внутри драма в NPM-проекте).
Подготовка приложения
При работе с переменными окружения в PHP-проекте, вы хотите убедиться, что ваш код всегда будет получать переменную из надежного источника, будь то $_ENV , $_SERVER , getenv . Но эти три метода не возвращают одинаковые результаты!
Это потому что настройка variables_order в PHP на моей машине установлена в "GPCS" . И так как в ней нет буквы "E" , я не могу полагаться на суперглобальный массив $_ENV . Это может привести к тому, что код работающий на одном PHP не будет работать на другом.
Другой камень преткновения – это то, что разработчики не хотят управлять переменными окружения локально. Каждый раз, когда мы редактируем VirtualHost, мы не хотим перезагружать php-fpm или некую службу, или очищать кеш. Разработчики хотят иметь простой и безболезненный способ настройки переменных окружения. как .env файл!
Файл .env — это просто сборник переменных окружения с их значениями:
Библиотеки "Dot Env" в помощь
vlucas/phpdotenv, самая популярная библиотека на данный момент:
Эта библиотека будет читать .env файл и заполнит все суперглобальные переменные:
Есть несколько хороших плюшек, таких как возможность помечать некоторые переменные, как обязательные. (используется фреймворком Laravel)
josegonzalez/dotenv, ориентирована на безопасность:
Эта библиотека не заполнит суперглобальные переменные по умолчанию:
Она поддерживает обязательные переменные, фильтрацию, и может выбрасывать исключения, когда переменная перезаписывается.
symfony/dotenv, новый малыш на этом поприще:
Доступен начиная с Symfony 3.3. Этот компонент заботится о .env -файле, как остальные, и тоже заполняет суперглобальные массивы:
На packagist есть ещё куча других и я даже боюсь спрашивать, почему каждый пишет тот же парсер снова и снова.
Но все они используют ту же логику:
- найти .env файл;
- разобрать его, проверить на вложенные значения, вытащить все переменные;
- заполнить все суперглобальные массивы переменными, кроме тех, что уже установленны.
Я рекомендую комитить файл .env со значениями, заданными для разработчиков: каждый должен иметь возможность вытащить ваш проект и запустить его так, как ему нравится (сервер из командной строки, Apache, nginx. ) без мучений с конфигурацией.
Эта рекомендация хорошо работает, когда каждый локально имеет ту же инфраструктуру: тот же пароль к БД, тот же сервер и порт. Т. к. мы используем Docker Compose на всех наших проектах, у нас никогда нет никаких различий в настройках одного разработчика от настроек другого. Если у вас нет такой плюшки, просто позвольте разработчикам перезаписывать настройки по умолчанию, импортировав два файла:
В этом случае, вы просто должны создать и заполнить файл .env.dev тем, что отличается для вас (и добавить его .gitignore ).
Затем на продакшене, вы не должны загружать эти значения по умолчанию:
Если вы так не сделаете, и ваш хостинг-провайдер забудет передать переменную, то запустите код в продакшене с настройками от дева, а это не приведёт ни к чему хорошему.
Подводные камни, на которые вы должны обратить внимание ⚠
Конфликты имен
Нейминг – это сложно, и переменные окружения не являются исключением из этого правила.
Поэтому при именовании переменных окружения, вы должны быть осторожными и допускать как можно меньше конфликтов имен. Ситуация усложняется тем, что нет официального списка зарезервированных имен. Хорошая практика – использовать префиксы пользовательских переменных.
В мире Unix это уже делают, используя LC_ , GTK_ , NODE_ …
Отсутствие переменных во время выполнения
У вас есть два варианта в случае, если переменная отсутствует: либо бросить исключение, или использовать значение по умолчанию. Решать вам, но второй вариант молчаливый. Что может принести вред во многих случаях.
Как только вы захотите использовать переменные окружения, вы должны установить их везде:
- на веб-сервере;
- в длительных скриптах и сервисах;
- в crontab-ах…
- и в сценарии развертывания!
Про последний легко забыть, но так как сценарии могут разогревать кеш приложения (как Symfony-вские). да, отсутствие переменной может привести к поломке деплоя. Будьте осторожны с этим и добавите проверку при запуске приложения.
Префикс HTTP_
Есть только один префикс, который вы никогда не должны использовать: HTTP_ . Потому что его использует сам PHP (и другие cgi-подобные контексты) для хранения заголовков http-запроса.
Вы помните httpoxy уязвимость? Она возникала при поиске http-клиентом переменной в окружении таким образом, что её можно было установить через простой http-заголовок.
Некоторые DotEnv-библиотеки также предотвращают переопределение таких переменных, например, Symfony-компонент.
Потокобезопасность функции getenv()
У меня плохие новости: в некоторых конфигурациях, использование функции getenv() приведет к неожиданным результатам. Эта функция не потокобезопасна!
Вы не должны использовать её для получения ваших значений, поэтому я предлагаю вам вместо этого обращаться к $_SERVER – к тому же есть небольшая разница в производительности между обращением к массиву и вызовом функции в пользу массивов.
Переменные окружения – всегда строки
Одной из главных проблем является то, что сейчас в PHP есть указание типов, а наши настройки не всегда правильно набраны.
В Symfony теперь можно преобразовывать variables, а даже больше – чтение файла, декодирование json. …
Переменные окружения везде или нет
На данный момент существует много споров между использованием переменных окружения, файлов, или их смеси: переменная окружения ссылается на файл конфигурации. Дело в том, что несмотря на то, что это считается лучшей практикой, переменные окружения не представляют больших преимуществ.
Но если правильно использовать, в приложении на Symfony, например, переменные окружения могут быть изменены "на лету" — без очистки какого-либо кеша, без обращения к файловой системе, без развертывания кода: просто перезапустив процесс, например.
Использование переменных окружения в Node.js
Материал, посвящённый переменным окружения в Node.js, перевод которого мы сегодня публикуем, написал Берк Холланд, веб-разработчик, в сферу интересов которого входят JavaScript, Node.js и VS Code. Кроме того, стоит отметить, что у него сложились непростые отношения с Java. Вот его история.
Переменные окружения — одна из фундаментальных конструкций среды Node.js, но почему-то я никогда не стремился научиться правильно ими пользоваться. Возможно, случилось так из-за их названия — «Environment Variables». Это название вызывало у меня нечто вроде посттравматического синдрома, неприятные воспоминания о том, как я пытался добавить путь к домашней директории Java в Windows. Я тогда толком не мог понять, надо ли добавлять этот путь в переменную PATH, в переменную JAVA_HOME, или и туда и туда. Было неясно и то, нужно ли, чтобы в конце этого пути стояла точка с запятой. Собственно говоря, тогда у меня возникал и вопрос о том, почему я использую Java. Как бы там ни было, я наконец нашёл в себе силы и приступил к знакомству с переменными окружения Node.

Если вы пишете для платформы Node.js, и, так же, как и я, неважно — по каким причинам, до сих пор не особенно хорошо знакомы с переменными окружения — предлагаю это исправить.
Переменные окружения в Node.js
В Node переменные окружения могут быть глобальными (как в Windows), но часто они используются в применении к конкретному процессу, в выполнении которого заинтересован разработчик. Например, если у вас имеется веб-приложение, это значит, что в нём могут применяться следующие переменные окружения:
- HTTP-порт, который будет прослушивать это приложение.
- Строка подключения к базе данных.
- Путь к JAVA_HOME, ох, подождите, это мимо. Прошу учесть, что выздоровление требует времени.
Если раньше вы программировали для .NET, возможно, вы знакомы с чем-то вроде файла web.config . Переменные окружения Node играют практически такую же роль, как настройки из web.config — они представляют собой механизм передачи в приложение информации, которую разработчик не хочет жёстко задавать в коде.
Кстати, на тему «hard code» — задания в коде неких значений вместо получений их из внешних источников, хочу поделиться моим собственным твитом.

Цитирую сам себя на пике помешательства
Как же использовать переменные окружения в Node.js-приложениях? Мне пришлось изрядно потрудиться для того, чтобы найти хороший материал по переменным окружения в Node, с непременным условием наличия в этом материале достаточного количества шуток о Java. Такого материала я не нашёл, поэтому решил написать его сам.
Вот несколько способов использования переменных окружения в приложениях для Node.js.
Указание переменных окружения в терминале
Вы можете указывать переменные окружения в терминале, в котором планируется запускать Node. Например, если у вас имеется приложение, использующее Express, и вы хотите передать ему сведения о порте, сделать это можно так:
Кстати, интересная вещь. Оказывается, самое большое значение, которое может принимать номер порта, это 65535. Как я это узнал? Конечно, нашёл на StackOverflow. Как вообще кто-либо что-либо узнаёт? Но в Node самый большой номер порта — это 65534. Почему? Понятия не имею. Я не могу знать абсолютно всё.
Итак, для использования переменной окружения в коде нужно воспользоваться объектом process.env . Выглядит это так:
Однако использование описанного здесь подхода может плохо кончиться. Если у вас есть, например, строка подключения к базе данных, вы, вероятно, не будете особенно рады перспективам её ввода в терминал. На самом деле, ввод длинных значений в терминале похож на болезненную зависимость, а нам это совершенно ни к чему. Посмотрите сами:
Такой подход не масштабируется, а все хотят масштабирования. По мнению каждого архитектора, рядом с которым мне доводилось сидеть на разных мероприятиях, «масштабирование» — это даже важнее, чем сам факт работоспособности приложения.
Поэтому рассмотрим другой подход, который заключается в применении файлов .env .
Использование файлов .env
Файлы .env предназначены для хранения переменных окружения. Для использования этой технологии достаточно создать в проекте файл с именем .env и внести в него переменные окружения, начиная каждую с новой строки:
Читать эти значения можно разными способами. Пожалуй, проще всего — с помощью пакета dotenv из npm :
После установки пакета его нужно подключить к проекту, а затем им можно пользоваться для работы с переменными окружения. Этот пакет найдёт файл .env и загрузит переменные, описанные в нём, в Node. Вот как это выглядит:
Кстати, хочу поделиться важным советом. Не заливайте файлы .env на GitHub. В них находятся сведения, не предназначенные для чужих глаз. Не повторяйте моих ошибок.
Итак, пока всё хорошо, но то, о чём мы тут говорили, не очень-то удобно. Подключать dotenv придётся в каждом файле, где надо использовать переменные окружения, и dotenv придётся использовать в продакшне, когда, в сущности, вам это не нужно. Я не отношусь к фанатам развёртывания бесполезного кода в продакшне, хотя, мне кажется, до сих пор я только этим и занимался.
Что же делать? К счастью, вы пользуетесь VS Code (я абсолютно в этом уверен), а это значит, что у вас есть ещё несколько вариантов.
Работа с файлами .env в VS Code
Для начала вы можете установить расширение DotENV для VS Code, которое даст приятную подсветку синтаксиса файлов .env .

Вот как выглядит файл .env без подсветки синтаксиса и с подсветкой
Кроме того, отладчик VS Code, если вы им пользуетесь, предлагает некоторые более удобные возможности по загрузке значений из файлов .env .
Конфигурация запуска VS Code
Отладчик Node.js для VS Code (он устанавливается по умолчанию) поддерживает загрузку файлов .env посредством конфигураций запуска. Подробности о конфигурациях запуска можно почитать здесь.
Создание базовой конфигурации запуска для Node
После того, как вы создадите базовую конфигурацию запуска для Node (щёлкните по значку с шестерёнкой и выберите Node), можно выполнить одно из следующих действий, или сделать и то и другое.
Первый вариант заключается во включении переменных в конфигурационный файл.

Переменные в конфигурационном файле
Это — вполне приемлемый вариант, но меня немного беспокоит то, что каждое значение должно быть строкой. Всё-таки некоторые значения — это числа, а не строки, а в JavaScript есть лишь, скажем так, три основных типа данных, и мне не хотелось бы лишаться одного из них.
Передать переменные окружения в VS Code можно и более простым способом. Мы уже выяснили, что файлы .env — это наши друзья, поэтому вместо того, чтобы вписывать в конфигурационный файл значения переменных, просто укажем там путь к файлу .env .

Путь к файлу .env в конфигурационном файле
До тех пор, пока мы запускаем процесс Node.js из VS Code, файл с переменными окружения будет передаваться этому процессу. При этом нам не придётся втискивать числа в кавычки, делая из них строки, и не придётся разворачивать ненужный код в продакшне. Ну, по крайней мере, вам этого делать не придётся.
Запуск node-скриптов через NPM
Возможно, вы дошли до этого места и подумали о том, что никогда не запускаете Node-проекты командами вида node … , всегда пользуясь npm-скриптами вроде npm start . Конфигурациями запуска VS Code можно пользоваться и в этом случае. Однако, вместо применения стандартного запуска Node, можно настроить задачу Launch Via NPM.
Задача Launch Via NPM
После этого можно настроить значение параметра envFile , указав путь к файлу .env , и параметра runtimeArgs для запуска нужного скрипта. Обычно в качестве скрипта выступает start или debug .

Настройка запуска проекта с помощью npm
Обратите внимание на то, что в package.json нужно добавить, к npm-скрипту, флаг —inspect для того, чтобы VS Code мог подключить к процессу отладчик. В противном случае, хотя задача и запустится, отладчик не сможет сделать ничего полезного.
Флаг —inspect в package.json
Переменные окружения в продакшне
Итак, мы разобрались с тем, как пользоваться переменными окружения в ходе разработки. Вы, вероятнее всего, не будете применять файлы .env в продакшне, да и конфигурация запуска VS Code на сервере особой пользы не принесёт.
В продакшне определение переменных окружения будет зависеть от особенностей используемой платформы. Например, в случае с Azure есть три способа объявления таких переменных и управления ими.
Первый способ заключается в использовании Azure CLI.
Это работает, но выглядит не очень. Ещё один способ — использование веб-портала Azure. Я не часто пользуюсь веб-порталом, но когда это случается, я обращаюсь к нему именно для установки переменных окружения.
Здесь то, что мы называем «переменными окружения», называется «Application Settings».

Настройка переменных окружения в Azure
Ещё один вариант, учитывая то, что вы пользуетесь VS Code, заключается в установке расширения App Service и в настройке вышеописанных Application Settings прямо из редактора.
Настройка переменных окружения из VS Code
Мне нравится делать в VS Code абсолютно всё, и если бы там можно было бы писать электронные письма, я бы так и поступал. Кстати, похоже, моя мечта сбылась.
Итоги
Теперь вы знаете то же, что знаю я (не так много, позволю заметить), и я чувствую, что выполнил свою цель по шуткам на тему Java. Если вдруг их тут недостаточно — вот ещё одна, автор которой неизвестен: «Java — это очень мощный инструмент по превращению XML в стек-трейсы».
Надеемся, этот материал дал возможность восполнить пробелы в знаниях о переменных окружения в Node тем, кто раньше ими не пользовался, а тем, кто уже о них знал, позволил узнать что-нибудь новое о файлах .env, о применении переменных окружения на боевых серверах, и о том, как облегчить себе жизнь, занимаясь разработкой Node-проектов в VS Code. Если тема переменных окружения Node вам интересна — вот одна из наших предыдущих публикаций на эту тему, посвящённая особенностям работы с process.env.
Уважаемые читатели! Как вы решаете проблемы использования переменных окружения Node в ходе разработки и в продакшне?
Переменные окружения в приложении Node.js
Переменные окружения или переменные среды (environment variables) — это некие глобальные значения, расположенные на уровне операционной системы, доступные программам, например настройки системы.
Самой известной переменной, можно считать PATH. Операционная система использует значение этой переменной для того, чтобы найти нужные исполняемые файлы в командной строке или окне терминала. Например, когда мы выполняем в терминале команду node, npm или другую, именно переменная PATH подсказывает где искать исполняемые файлы. Об этом, подробнее рассказывается в этом посте, на платформах linux и macos. Наверняка вы сталкивались с этой коварной переменной в начале своей карьеры .
Замечу, что значения в переменных окружения хранятся в виде строк. Поэтому старайтесь не использовать цифровые и булевы типы данных, иначе при записи они преобразуются к строкам. Помните об этом.
Проблема
В процессе разработки приложения, будь то клиентское или серверное, может понадобится использовать приватные данные, например секретный токен для запросов на сторонний сервер. Вот так:
Но мы не можем сохранить такой код в git, иначе мы просто расскажем всему миру наш секретный ключ.
Время переменных окружения
Мы можем хранить секретные данные, настройки сборки и другие данные в переменных окружения. Программа на nodejs имеет к ним доступ.
В nodejs есть глобальный объект process (доступный из любого места программы, как window в браузере), хранящий информацию о текущем процессе. У этого объекта есть свойство env — оно и дает доступ к переменным окружения. Попробуйте запустить node в терминале и выполнить console.log(process.env):
Мы увидим как в терминал выведется объект со всеми значениями переменных окружения.
Теперь если представить, что наш секретный ключ уже находится в переменных окружения, то предыдущий пример можно переписать так:
Мы получаем наш секретный ключ из окружения. Отличный пример .
Еще, вы наверняка использовали или встречали конструкцию node.env.NODE_ENV === ‘production’ для определения режима сборки своего приложения.
Но как же установить эти переменные окружения?
Установка переменных окружения
Главной сложностью, является различие в способах установки переменных окружения в разных операционных системах и разных терминальных оболочках. В основном мы имеем две платформы: Windows и Linux (MacOS). Давайте посмотрим как это сделать в обоих.
Linux, MacOS
Отобразить весь список переменных можно командой printenv.
Показать конкретную переменную можно так:
Для добавления переменной можно использовать комманду export.
Однако нужно помнить, такой способ задает переменную только на текущий сеанс операционной системы.
Так же, можно определить переменные во время запуска программы, в одной строке. Такая переменная будет жить только во время работы программы.
Для сохранения постоянной переменной используйте следующее решение. Поскольку Mac и большинство Linux дистрибутивов используют оболочку bash, переменные окружения могут быть добавлены в каталог .bash_profile для текущего пользователя. Путь к этому файлу можно найти с помощью команды:
В этот файл нужно добавить определение переменной, просто на новой строке.
При старте системы переменная будет инициализирована. Не забудьте закрыть и снова открыть терминал, прежде чем использовать новую переменную среды. Повторное открытие терминала загружает обновленный файл .bash_profile.
Windows
Что бы посмотреть список переменных в коммандной строке (Command Prompt) используйте комманду set.
Вывести значение по имени переменной можно так:
Добавление новой переменной скрыто за несколькими графическими окнами. Для добавления переменной нажмите Win+R, в открывшемся окне введите sysdm.cpl и нажмите Enter.
В открывшемся окне перейдите на вкладку «Дополнительно» и затем нажмите кнопку «Переменные среды» в правом нижнем углу окна.
Открывшееся окно имеет два разных раздела. Один из них — это список переменных среды, характерных только для вашего пользователя. Это означает, что они недоступны для других пользователей. В другом разделе содержатся общесистемные переменные, общие для всех пользователей.
Создайте пользовательскую переменную, нажав кнопку «Создать» ниже раздела, предназначенного для пользователя. Укажите имя переменной и значение.
Так же можно использовать утилиту setx. Она появилась еще со времен Windows Vista и Windows Server 2008:
Такой способ сохраняет переменную в памяти ОС и не удаляет ее после перезагрузки. Что бы начать использовать новую переменную, так же нужно перезагрузить терминал.
Установить временную переменную и запустить процесс node так же возможно:
Избавляемся от различий
Как вы уже заметили. Запуск node приложения с временными переменными отличается в разных платформах. Что бы решить эту проблему я использую пакет cross-env. Эта небольшая библиотечка позволяет определять временные переменные окружения в одном виде. Определите скрипт в package.json:
Так должно без проблем работать на windows, mac и linux. Конечно хранить никакие ключи тут не нужно.
Все переменные в одном месте
Если вы разрабатываете несколько проектов Node.js на одном компьютере, возможно столкнуться с тем, что у вас есть перекрывающиеся имена переменных окружения. Например для разных приложений могут понадобиться разные ключи MYAPIKEY. Хороший способ исправить это, использовать файл .env, для конфигурации конкретного проекта. Эти файлы позволяют указать различные переменные окружения и их значения.
Просто создайте файл .env в корневом каталоге проекта и добавьте в него все необходимые переменные. В нашем случае:
Не забудьте добавить этот файл в свой .gitignore, ведь мы не хотим раздавать всем наши ключи. В некоторых репозиториях возможно встретить файлы с именами .env.example — это всего лишь шаблон/схема для ваших значений, просто скопируйте все в .env и подставьте свои значения. Важно понимать, что такие названия это всего лишь общая договоренность и ничего больше. Некоторые редакторы даже подставляют иконки для таких файлов:
Далее, необходимо прочитать переменные и добавить их в переменные окружения. Самый распространенный способ — использовать модуль npm, под названием dotenv. Просто установите модуль через npm:
Затем добавьте следующую строку в самое начало вашего файла (первой точки входа в приложение):
Пакет dotenv автоматически загрузит файл .env из корневого каталога проекта, и инициализирует значения. Подробнее читайте в документации к пакету. Важной особенностью этого модуля является то что он не перезаписывает уже существующие переменные окружения (хотя и есть способ это сделать) и пропускает их. Есть и другие решения, например env2 и node-env-file.
Так же важно понимать, что использовать такой подход можно только при разработке и никак не в продакшене. Дело в том что файл .env доступен для чтения и если злоумышленник получит доступ к серверу, он может найти этот файл просто по имени. Само сохранение секретных значений в открытый файл противоречит безопасности.
Замечание
При использовании node.env есть проблемы с производительностью. Например нам необходимо часто делать запрос на сторонний сервис и токен мы берем напрямую из node.env.TOKEN. То есть проблема заметна при большой нагрузке. Есть способы решения этой проблемы, но это уже другая история.
Заключение
Мы разобрались что такое переменные окружения/среды (environment variables), узнали как создавать временные и постоянные переменные на разных платформах и посмотрели как можно автоматизировать установку значений.
Конечно, эта тема очень большая, и я пробежался по основным возможностям. Но думаю этого достаточно что бы начать с ними работать .
Я надеюсь, вам понравился пост. Если да, похлопайте , чтобы помочь другим найти эту информацию. И не стесняйтесь оставлять комментарии — буду рад любым замечаниям!