مجله ایرانیکاسرورآموزش سرور، هاست، وردپرس و شبکه
آموزشی

تنظیم Environment Variable برای سرویس‌های systemd؛ آموزش EnvironmentFile

اگر برنامه شما هنگام اجرای دستی در SSH درست کار می‌کند اما همان برنامه وقتی با systemd اجرا می‌شود متغیرهایی مثل APP_ENV، NODE_ENV، PORT، DATABASE_URL یا مسیرهای سفارشی را پیدا نمی‌کند، احتمالاً Environment Variableها…

تنظیم Environment Variable برای سرویس‌های systemd؛ آموزش EnvironmentFile
خلاصه سریع این آموزش

اگر برنامه شما هنگام اجرای دستی در SSH درست کار می‌کند اما همان برنامه وقتی با systemd اجرا می‌شود متغیرهایی مثل APP_ENV، NODE_ENV، PORT، DATABASE_URL یا مسیرهای سفارشی را پیدا…

۷ دقیقه مطالعه ۰ دیدگاه ۱۲ مهر ۱۴۰۵ آخرین به‌روزرسانی

اگر برنامه شما هنگام اجرای دستی در SSH درست کار می‌کند اما همان برنامه وقتی با systemd اجرا می‌شود متغیرهایی مثل APP_ENV، NODE_ENV، PORT، DATABASE_URL یا مسیرهای سفارشی را پیدا نمی‌کند، احتمالاً Environment Variableها برای خود سرویس تعریف نشده‌اند.

پاسخ سریع: برای چند مقدار ساده از Environment= در بخش [Service] استفاده کنید. اگر تعداد متغیرها زیاد است، یک فایل جداگانه بسازید و با EnvironmentFile= به systemd معرفی کنید. بعد از هر تغییر، systemctl daemon-reload و سپس Restart سرویس را اجرا کنید.

فهرست مطالب

چرا systemd متغیرهای Shell را نمی‌بیند؟

وقتی در SSH دستور زیر را اجرا می‌کنید:

export APP_ENV=production

این متغیر در Environment همان Shell و Processهای فرزند آن وجود دارد.

اما یک system service معمولاً توسط System Manager اجرا می‌شود و Environment تعاملی SSH یا فایل‌هایی مثل ~/.bashrc و ~/.profile را به همان شکل Shell شما دریافت نمی‌کند.

⚠️ اضافه‌کردن یک متغیر به .bashrc و سپس انتظار داشتن از سرویس systemd برای خواندن آن، معمولاً راه‌حل صحیح نیست.

روش اول: استفاده از Environment= داخل Unit File

برای چند متغیر ساده می‌توانید آن‌ها را مستقیم در بخش [Service] قرار دهید.

مثال:

[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp

Environment=APP_ENV=production
Environment=NODE_ENV=production
Environment=PORT=3000

ExecStart=/opt/myapp/app
Restart=on-failure

[Install]
WantedBy=multi-user.target

بعد از ذخیره فایل:

sudo systemctl daemon-reload
sudo systemctl restart myapp.service

مقدار دارای Space را چطور تعریف کنیم؟

اگر مقدار Environment Variable شامل فاصله باشد، کل Assignment را داخل کوتیشن قرار دهید:

Environment="APP_NAME=Iranica Server Bot"
Environment="LOG_LEVEL=debug mode"

در Environment= نباید فرض کنید Syntax دقیقاً مانند Bash عمل می‌کند. systemd قواعد Parsing خودش را دارد.

روش دوم: استفاده از EnvironmentFile=

وقتی تعداد متغیرها زیاد می‌شود، گذاشتن همه آن‌ها داخل Unit File خوانایی را کم می‌کند. در این حالت استفاده از فایل Environment مناسب‌تر است.

مثلاً پوشه تنظیمات را بسازید:

sudo mkdir -p /etc/myapp

فایل Environment:

sudo nano /etc/myapp/myapp.env

نمونه محتوا:

APP_ENV=production
NODE_ENV=production
PORT=3000
DB_HOST=127.0.0.1
DB_PORT=5432

حالا در Unit File:

[Service]
User=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/myapp.env
ExecStart=/opt/myapp/app
Restart=on-failure

Permission فایل Environment را محدود کنید

اگر فایل Environment شامل اطلاعات حساس است، دسترسی آن را محدود کنید:

sudo chown root:root /etc/myapp/myapp.env
sudo chmod 600 /etc/myapp/myapp.env

⚠️ برای Secretهای حساس مثل Password، Private Key یا Tokenهای مهم، Environment Variable همیشه امن‌ترین Secret Store نیست. در محیط‌های حساس بهتر است قابلیت Credentials خود systemd یا یک Secrets Manager مناسب را بررسی کنید.

EnvironmentFile اختیاری با علامت منفی

اگر وجود فایل Environment اجباری نباشد، می‌توانید قبل از مسیر از – استفاده کنید:

EnvironmentFile=-/etc/myapp/myapp.env

در این حالت اگر فایل وجود نداشته باشد، systemd صرفاً به‌دلیل نبودن آن سرویس را Fail نمی‌کند.

Environment= و EnvironmentFile= با هم

می‌توانید هر دو روش را هم‌زمان استفاده کنید:

[Service]
Environment=APP_ENV=production
EnvironmentFile=/etc/myapp/myapp.env

اگر یک Variable چند بار تعریف شده باشد، ترتیب و منبع تعریف اهمیت دارد. مقادیر فایل Environment می‌توانند مقادیر قبلی تعریف‌شده با Environment= را Override کنند.

روش بهتر برای تغییر سرویس‌های Package شده: systemctl edit

اگر سرویس متعلق به Packageهایی مثل Nginx، Redis یا سرویس نصب‌شده توسط Package Manager است، Unit File اصلی را مستقیماً ویرایش نکنید.

از Drop-in استفاده کنید:

sudo systemctl edit myapp.service

سپس:

[Service]
Environment="APP_ENV=production"
EnvironmentFile=/etc/myapp/myapp.env

این روش باعث می‌شود تغییر شما با Update شدن Package راحت‌تر حفظ شود.

API، Bot یا سرویس دائمی روی VPS اجرا می‌کنید؟

برای سرویس‌هایی که با systemd اجرا می‌شوند، تفکیک صحیح Config، Environment و Secretها باعث می‌شود Deploy، Restart و عیب‌یابی سرور ساده‌تر شود. اگر سرویس شما به منابع بیشتری نیاز دارد، می‌توانید پلن‌های VPS ایرانیکاسرور را بررسی کنید.

تماس با پشتیبانی ایرانیکاسرور:
021-91302467

بعد از تغییر Environment چه دستورهایی اجرا کنیم؟

اگر Unit File یا Drop-in تغییر کرده است:

sudo systemctl daemon-reload
sudo systemctl restart myapp.service
sudo systemctl status myapp.service --no-pager

اگر فقط محتوای فایل EnvironmentFile= را عوض کرده‌اید، برای اینکه Process جدید مقادیر تازه را دریافت کند باید سرویس Restart شود.

چطور Environment تعریف‌شده Unit را ببینیم؟

برای متغیرهایی که مستقیم در Unit تعریف شده‌اند:

systemctl show myapp.service -p Environment

برای دیدن مسیر Environment Fileها:

systemctl show myapp.service -p EnvironmentFiles

همچنین برای دیدن Unit و Drop-inهای نهایی:

systemctl cat myapp.service

چطور Environment واقعی Process را ببینیم؟

اگر می‌خواهید مطمئن شوید خود Process مقدار را دریافت کرده است، PID اصلی سرویس را پیدا کنید:

systemctl show myapp.service -p MainPID

سپس برای یک سرویس غیرحساس می‌توانید Environment Process را بررسی کنید:

sudo tr '\0' '\n' < /proc/PID/environ

⚠️ این خروجی ممکن است Secret، Password یا Token داشته باشد. آن را در Ticket، Screenshot، Log عمومی یا انجمن‌ها منتشر نکنید.

تفاوت EnvironmentFile با فایل .env برنامه‌ها

فایل .env در بسیاری از Frameworkها مثل Laravel یا Node.js توسط خود Application یا Library مربوطه خوانده می‌شود.

اما EnvironmentFile= مستقیماً توسط systemd خوانده می‌شود و Variableها قبل از اجرای Process وارد Environment آن می‌شوند.

این دو مفهوم شبیه هستند اما دقیقاً یک چیز نیستند. Syntax فایل `.env` بعضی Frameworkها ممکن است قابلیت‌هایی داشته باشد که systemd EnvironmentFile همان رفتار را ندارد.

آیا می‌توان همان فایل .env پروژه را مستقیماً استفاده کرد؟

اگر Syntax فایل با فرمت قابل قبول systemd سازگار باشد، از نظر فنی ممکن است:

EnvironmentFile=/opt/myapp/.env

اما بهتر است ابتدا محتوا، Permission و Syntax آن را بررسی کنید. همچنین اگر Application خودش `.env` را می‌خواند، ممکن است واردکردن دوباره همان متغیرها در Environment لازم نباشد.

استفاده از Variable در ExecStart

systemd از Environment Variable در Argumentهای ExecStart پشتیبانی می‌کند.

مثال:

[Service]
Environment=PORT=3000
ExecStart=/opt/myapp/app --port ${PORT}

اما نباید فرض کنید ExecStart= یک خط Bash است.

برای مثال چنین Syntaxهایی به‌صورت Shell خودکار تفسیر نمی‌شوند:

ExecStart=/opt/myapp/app > /var/log/myapp.log
ExecStart=echo $HOME && /opt/myapp/app

Redirection، Pipe، && و بسیاری از قابلیت‌های Shell فقط در صورتی کار می‌کنند که صراحتاً Shell اجرا کنید؛ ولی برای سرویس‌های systemd بهتر است تا جای ممکن ExecStart مستقیم و ساده باشد.

مشکل PATH در systemd

یکی از مشکلات رایج این است که دستور در SSH پیدا می‌شود ولی در systemd نه.

مثلاً:

which node
which python3
which php

بهتر است در Unit File مسیر کامل Binary را قرار دهید:

ExecStart=/usr/bin/node /opt/myapp/server.js

نمونه کامل برای Node.js

[Unit]
Description=Node.js Application
After=network.target

[Service]
Type=simple
User=nodeapp
WorkingDirectory=/opt/nodeapp

Environment=NODE_ENV=production
EnvironmentFile=/etc/nodeapp/nodeapp.env

ExecStart=/usr/bin/node /opt/nodeapp/server.js

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

نمونه کامل برای Python

[Unit]
Description=Python Application
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp

Environment=PYTHONUNBUFFERED=1
EnvironmentFile=/etc/myapp/myapp.env

ExecStart=/opt/myapp/venv/bin/python /opt/myapp/app.py

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

اگر متغیر اعمال نمی‌شود چه کنیم؟

این ترتیب را بررسی کنید:

۱. مسیر EnvironmentFile درست باشد.

۲. Permission فایل درست باشد.

۳. Syntax فایل معتبر باشد.

۴. systemctl daemon-reload اجرا شده باشد.

۵. سرویس Restart شده باشد.

۶. Unit و Drop-in نهایی را با systemctl cat بررسی کنید.

۷. Log سرویس را بررسی کنید.

Log:

sudo journalctl -u myapp.service -b -n 100 --no-pager

پرسش‌های متداول

چرا export در SSH روی systemd Service اعمال نمی‌شود؟

چون system service معمولاً Environment همان Shell تعاملی شما را به ارث نمی‌برد. متغیر باید برای خود سرویس یا Service Manager تعریف شود.

Environment بهتر است یا EnvironmentFile؟

برای چند مقدار ساده Environment مناسب است. برای تعداد زیاد متغیر یا جداکردن Config از Unit File معمولاً EnvironmentFile خواناتر است.

بعد از تغییر EnvironmentFile باید daemon-reload اجرا کنیم؟

اگر فقط محتوای همان فایل Environment تغییر کرده باشد، معمولاً Reload تعریف Unit لازم نیست؛ اما برای دریافت مقدار جدید باید Process سرویس Restart شود. اگر Unit یا مسیر EnvironmentFile تغییر کرده باشد، daemon-reload نیز اجرا کنید.

آیا Password را در EnvironmentFile قرار دهیم؟

برای برنامه‌های ساده ممکن است استفاده شود، اما Environment Variable محل ایده‌آل برای Secretهای حساس نیست. Permission فایل را محدود کنید و برای محیط حساس قابلیت Credentials یا Secrets Manager را بررسی کنید.

آیا systemd فایل .bashrc را می‌خواند؟

System serviceها را نباید وابسته به .bashrc یا .profile کاربر طراحی کرد. Environment سرویس را به‌صورت صریح در systemd تعریف کنید.

چطور متغیرهای سرویس را ببینیم؟

برای تنظیمات Unit می‌توانید از systemctl show SERVICE -p Environment و برای Process واقعی از /proc/PID/environ استفاده کنید؛ ولی مراقب افشای Secretها باشید.

منابع

🔹 systemd.exec؛ Environment و EnvironmentFile

🔹 systemd.service؛ استفاده از Environment Variable در ExecStart

🔹 systemctl؛ مدیریت Environment سرویس‌ها

جمع‌بندی

برای تنظیم Environment Variable در systemd، روی export داخل SSH یا فایل‌های Shell حساب نکنید. برای چند مقدار ساده از Environment= و برای مجموعه بزرگ‌تر از EnvironmentFile= استفاده کنید. بعد از تغییر Unit، daemon-reload و Restart را انجام دهید و مقدار نهایی را با systemctl show یا Environment Process بررسی کنید. اطلاعات حساس را نیز با Permission مناسب و در محیط‌های جدی با روش‌های امن‌تر مدیریت کنید.

Environment سرویس هنوز اعمال نمی‌شود؟

اگر برنامه در SSH درست اجرا می‌شود اما در systemd Environment متفاوتی دارد، می‌توانید برای بررسی Unit File، EnvironmentFile، Permission و Logهای سرویس درخواست فنی ثبت کنید.

تماس با پشتیبانی ایرانیکاسرور:
021-91302467

اشتراک‌گذاری مقاله
گفت‌وگو درباره آموزش

دیدگاه‌ها (۰)

هنوز دیدگاهی ثبت نشده است.

دیدگاه یا سؤال خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *