systemd servisi yazmak: uygulamayı Linux'ta arka planda kalıcı çalıştırmak
Bir Node.js, Python veya Go uygulamasını sunucuda nohup ya da screen içinde çalıştırmak ilk başta işe yarar. Ama sunucu yeniden başladığında uygulama açılmaz, çökerse kimse fark etmez. Doğru yol bir systemd servisi yazmaktır.
Basit bir servis dosyası
/etc/systemd/system/uygulamam.service:
[Unit]
Description=Uygulamam API
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=uygulama
Group=uygulama
WorkingDirectory=/opt/uygulamam
EnvironmentFile=/opt/uygulamam/.env
ExecStart=/usr/bin/node /opt/uygulamam/server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Açıklamalar:
- User/Group: Uygulamayı root olarak çalıştırma. Ayrı bir kullanıcı aç:
sudo useradd --system --home /opt/uygulamam --shell /usr/sbin/nologin uygulama - EnvironmentFile: Gizli bilgileri servis dosyasına yazmak yerine ayrı bir dosyada tut. Dosyanın izinleri kısıtlı olsun (
chmod 600). - ExecStart: Programın tam yolu.
which nodeveyawhich python3ile öğren. systemd, kabuğundaki PATH'i kullanmaz. - Restart=on-failure: Uygulama hatayla çökerse 5 saniye sonra yeniden başlatır.
Python için örnek ExecStart (sanal ortam kullanıyorsan ortamın içindeki yorumlayıcıyı ver):
ExecStart=/opt/uygulamam/venv/bin/python -m gunicorn app:app --bind 127.0.0.1:8000
Etkinleştir ve başlat
sudo systemctl daemon-reload # yeni veya değişen servis dosyasını oku
sudo systemctl enable --now uygulamam # açılışta başlat + şimdi başlat
systemctl status uygulamam
Servis dosyasında her değişiklikten sonra daemon-reload gerekir.
Günlükler
Uygulamanın standart çıktısına yazdığı her şey journald'a gider:
journalctl -u uygulamam -f
journalctl -u uygulamam --since "10 min ago"
Ayrı bir log dosyası yönetmen gerekmez.
Sık karşılaşılan hatalar
| Belirti | Sebep |
|---|---|
status=203/EXEC |
ExecStart'taki yol yanlış veya dosya çalıştırılabilir değil |
status=217/USER |
User satırındaki kullanıcı yok |
| Uygulama elle çalışıyor, serviste çalışmıyor | Ortam değişkenleri eksik, WorkingDirectory yanlış ya da kullanıcının dosyalara izni yok |
start request repeated too quickly |
Uygulama hemen çöküp tekrar başlatılıyor; journalctl -u ile ilk hatayı bul |
Takıldığında servis kullanıcısıyla elle çalıştırmayı dene:
sudo -u uygulama bash -c 'cd /opt/uygulamam && /usr/bin/node server.js'
Güvenliği artıran ek ayarlar
[Service] bölümüne eklenebilir. Uygulamanın neye ihtiyaç duyduğuna göre test ederek ekle:
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/uygulamam/storage
ProtectSystem=strict dosya sisteminin büyük kısmını salt okunur yapar; uygulamanın yazması gereken klasörleri ReadWritePaths ile açarsın. systemd-analyze security uygulamam komutu servisin ne kadar kısıtlı olduğunu puanlar ve önerilerde bulunur.
Zamanlanmış görevler için timer
Cron yerine systemd timer da kullanılabilir. Avantajı: görevin günlükleri journalctl ile okunur, son çalışma zamanı ve sonucu systemctl list-timers ile görülür. Basit işler için cron hâlâ gayet yeterli.
Ters vekil ile birlikte
Uygulama genellikle sadece 127.0.0.1 üzerinde dinlemeli ve dışarıya Nginx gibi bir ters vekil üzerinden açılmalı. Böylece SSL, sıkıştırma ve statik dosyaları Nginx üstlenir. Kurulum için forumdaki Nginx ters vekil rehberine bakabilirsin.