Process.env.PATH undefined в приложении Пассажир node (режим производства)

Недавно я развернул приложение node с Phusion Passenger для nginx и обнаружил довольно причудливую ошибку в этом процессе:

В моем коде возникла ошибка при попытке создать дочерний_процесс. Я немного отлаживал и в конце концов пришел к выводу, что проблема возникла из переменной среды $PATH, являющейся undefined в node, и я мог бы решить проблему с директивой passenger_env_var, подобной этой (показывая выписку моего nginx конфигурации):

server {
    listen 80;
    server_name blargh.com;
    root /home/user/blargh.com/build;

    passenger_enabled on;
    # For some reason $PATH isn't loaded into node, and we can't spawn child processes without it
    passenger_env_var PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games;
}

Я до сих пор не понял, что вызвало эту проблему, но настройка passenger_load_shell_envvars on; не помогла, и пользователь www-data имел $PATH envvar, определенный в оболочке. Более того, другие переменные среды (например, $SHELL), по-видимому, были загружены node, добавив к тайне почему исключение $PATH.

Кто-нибудь знает, что может вызвать эту проблему?

Ответ 1

TL;DRУкажите глобальные envvars, которые вы ожидаете определить при загрузке системы (например, PATH) в /etc/default/nginx. Используйте что-то вроде dotenv правильно и напишите конфигурацию, специфичную для вашего приложения, в текстовом файле, который не был отмечен. Переменные окружения довольно злые вообще.

Я чувствовал, что этот заслуживает довольно продолжительного ответа, поскольку переменные окружения вызвали повторяющиеся проблемы для меня в течение последних нескольких месяцев.

Сохранение конфигурации в качестве переменных окружения является одним из правил, которые 12-факторное приложение позволяет писать масштабируемые веб-приложения. Они хороши, потому что они позволяют гибко отделять конфигурацию от вашего кода. Тем не менее, проблема с ними заключается в том, что мы обычно сталкиваемся с ними, когда мы export MYVAR=myvalue или устанавливаем их в наших ~/.pam_environment или ~/.bashrc, , их область - это наш текущий сеанс терминала.

Это вызывает проблемы, когда мы начинаем использовать такие решения, как Phusion Passenger, чтобы запускать наши приложения при загрузке системы - их сценарии запуска не заботятся о средах оболочки пользователя. Они также не заботятся о глобальном /etc/environment, по-видимому, что и вызвало мои проблемы с PATH undefined.

Phusion Passenger фактически имеет некоторую документацию по чтобы глобальные переменные среды сохранялись:

Если вы установили Nginx через пакеты Debian или Ubuntu, вы можете определить переменные среды в /etc/default/nginx. Это оболочка script, поэтому вы должны использовать синтаксис экспорта FOO=bar.

Итак, установив PATH envvar в /etc/default/nginx, я мог бы решить эту проблему. Но у меня все еще были проблемы с другими переменными среды - мне пришлось установить их в моей конфигурации nginx, чтобы они перешли в мое приложение node. Мне было ясно, что это не правильный способ сделать это.

В этот момент я уже использовал dotenv, но я неправильно понял его цель. Я проверил файл .env и подумал об этом как о способе предоставления значений по умолчанию для envvars, которые будут переопределены средой по мере необходимости. Это не то, как сами авторы предполагали использовать этот модуль:

Мы настоятельно рекомендуем не передавать ваш .env файл в систему контроля версий. Он должен включать только такие значения среды, как пароли базы данных или ключи API.

Мне стало ясно, что люди часто не определяют envvars для своих приложений в реальной среде. Я нашел статью Питера Лиона, которая предлагает хранить конфигурацию в текстовом файле, а не в envvars, и что когда она щелкнула для меня.

Моим окончательным решением было разогнать мой файл .env и написать конкретное для каждой среды. Я оставил .env.template в своем репо в качестве ссылки на то, какую конфигурацию мое приложение ожидало определить во время выполнения.