Pernah bikin script Python buat scraping data terus kamu jalankan manual pakai python scrape.py lewat SSH? Tiap kali VPS reboot, scriptnya mati. Kamu harus login lagi, jalankan nohup atau screen, dan kalau lupa, data hari itu gak ke-scrape. Nah, situasi kayak gini yang bikin saya akhirnya belajar systemd.
Systemd itu init system default di hampir semua distro Linux modern (Ubuntu, Debian, CentOS, Arch). Tugas utamanya: jaga service biar tetap jalan, auto-restart kalau crash, dan jalan otomatis saat boot. Tapi banyak developer yang masih mengandalkan pm2, supervisor, atau bahkan tmux buat urusan ini padahal systemd sudah built-in, gak perlu install apa-apa.
Apa Itu Systemd dan Kenapa Developer Wajib Tahu?
Systemd adalah service manager untuk Linux. Dia ngatur proses yang jalan di background (daemon), logging, networking, dan mount filesystem. Dari sudut pandang developer, bagian yang paling penting adalah service unit file konfigurasi yang bilang "jalankan program X dengan parameter Y, dan restart kalau dia mati".
Beberapa keunggulan systemd dibanding tools alternatif:
- Tanpa instalasi tambahan sudah ada di setiap Ubuntu 16.04+ dan Debian 8+
- Auto-restart kalau app kamu crash, systemd nyalain lagi dalam hitungan detik
- Boot otomatis service mulai sendiri pas VPS reboot, tanpa intervensi manual
- Logging terpusat semua output log masuk ke
journalctl, gak perlu setup logrotate manual - Dependency management service A bisa tunggu service B ready dulu sebelum start (misal: app tunggu database dulu)
Struktur File Service Unit
File service systemd punya ekstensi .service dan biasanya disimpan di /etc/systemd/system/. Formatnya mirip INI file key-value sederhana. Ini contoh paling basic buat jalanin Node.js app:
[Unit]
Description=My Express API Server
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/myapp
ExecStart=/usr/bin/node /home/ubuntu/myapp/index.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production
Environment=PORT=3000
[Install]
WantedBy=multi-user.target
Mari kita bedah tiap bagian:
[Unit] metadata dan dependency. Description cuma buat display di systemctl status. After=network.target berarti "start service ini setelah network ready". Penting banget buat app yang butuh koneksi internet atau database.
[Service] konfigurasi eksekusi. Type=simple artinya proses di ExecStart adalah proses utama yang dipantau systemd. User=ubuntu menjalankan service sebagai user tertentu (jangan pernah pakai root kalau gak perlu). Restart=always berarti auto-restart dalam kondisi apapun, termasuk saat exit code 0. RestartSec=3 beri jeda 3 detik sebelum restart, supaya gak loop tanpa henti kalau app crash langsung pas start.
[Install] bagian ini mengatur kapan service start saat boot. WantedBy=multi-user.target artinya service mulai saat sistem masuk runlevel multi-user (mode normal, bukan single-user/rescue).
Praktik: Bikin Service untuk Python Flask API
Mari bikin service beneran. Misal kamu punu Flask app di /home/ubuntu/flaskapp/app.py yang jalan di port 5000. Pertama, pastikan app-nya bisa jalan standalone:
# Test dulu tanpa systemd
cd /home/ubuntu/flaskapp
source venv/bin/activate
python app.py
# Kalau jalan di port 5000, tekan Ctrl+C lalu lanjut bikin service
Sekarang bikin file service:
sudo nano /etc/systemd/system/flaskapp.service
Isi dengan konfigurasi ini:
[Unit]
Description=Flask API Server
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/flaskapp
ExecStart=/home/ubuntu/flaskapp/venv/bin/python /home/ubuntu/flaskapp/app.py
Restart=always
RestartSec=5
Environment=FLASK_ENV=production
Environment=FLASK_APP=app.py
[Install]
WantedBy=multi-user.target
Perhatikan ExecStart pakai path absolut ke Python di dalam virtualenv. Ini penting systemd gak load .bashrc atau .profile, jadi PATH environment gak sama kayak saat kamu SSH. Selalu pakai path lengkap.
Manage Service: Start, Stop, Status, Logs
Setelah file service dibuat, jalankan perintah-perintah ini:
# Reload systemd biar baca file service baru
sudo systemctl daemon-reload
# Enable service (auto-start saat boot)
sudo systemctl enable flaskapp
# Start service sekarang
sudo systemctl start flaskapp
# Cek status
sudo systemctl status flaskapp
Output systemctl status kira-kira kayak gini:
flaskapp.service - Flask API Server
Loaded: loaded (/etc/systemd/system/flaskapp.service; enabled)
Active: active (running) since Wed 2026-09-16 01:00:03 UTC
Main PID: 12345 (python)
Tasks: 2 (limit: 4915)
Memory: 45.2M
CGroup: /system.slice/flaskapp.service
12345 /home/ubuntu/flaskapp/venv/bin/python app.py
Kalau Active: active (running) berarti service kamu sudah jalan. Kalau Active: failed, cek log-nya:
# Lihat log terakhir
sudo journalctl -u flaskapp -n 50 --no-pager
# Follow log realtime
sudo journalctl -u flaskapp -f
# Lihat log sejak jam tertentu
sudo journalctl -u flaskapp --since "2026-09-16 01:00:00"
journalctl ini salah satu fitur systemd yang paling underrated. Gak perlu setup file log, gak perlu tail -f /var/log/app.log. Semua output stdout dan stderr dari app kamu langsung masuk ke jurnal sistem, bisa difilter per-service, per-waktu, bahkan per-priority.
Tipe Service yang Perlu Kamu Tahu
Parameter Type= di section [Service] menentukan cara systemd memantau proses. Lima tipe yang paling sering dipakai:
- simple (default) ExecStart adalah proses utama. Systemd langsung anggap service "active" begitu ExecStart jalan. Cocok untuk app yang gak daemonize diri sendiri (Flask, Express, FastAPI).
- forking ExecStart akan fork child process lalu exit. Systemd menganggap child process adalah proses utama. Cocok untuk app tradisional yang daemonize (PostgreSQL, Nginx, Apache).
- exec sama kayak simple, tapi systemd nunggu sampai ExecStart selesai di-load sebelum anggap active. Lebih strict.
- oneshot service yang jalan sekali lalu selesai (misal: script setup, backup script). Gak ada proses yang tetap jalan.
- notify app ngirim notifikasi ke systemd saat sudah ready. Cocok untuk app yang support sd_notify (banyak modern daemon).
Untuk 90% kasus developer, Type=simple sudah cukup. Tapi kalau kamu jalanin app yang pakai daemonize atau --daemon flag, pakai Type=forking.
Environment Variables dan File Config
Bisa langsung inline di file service:
Environment=NODE_ENV=production
Environment=API_KEY=abc123
Environment=DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
Tapi kalau ada banyak variables atau ada secret yang gak mau kamu taruh di file service (yang readable semua user), pakai file terpisah:
[Service]
EnvironmentFile=/etc/flaskapp/env.conf
ExecStart=/home/ubuntu/flaskapp/venv/bin/python app.py
Isi /etc/flaskapp/env.conf:
NODE_ENV=production
API_KEY=abc123
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
Set permission file ini supaya cuma user service yang bisa baca:
sudo chmod 600 /etc/flaskapp/env.conf
sudo chown ubuntu:ubuntu /etc/flaskapp/env.conf
Restart Policy yang Tepat
Parameter Restart= di section [Service] menentukan kapan systemd harus restart service. Pilihannya:
- always restart dalam kondisi apapun (exit code 0, crash, kill). Default yang paling aman untuk production.
- on-failure restart cuma kalau exit code bukan 0. Kalau app sengaja di-stop dengan
systemctl stop, gak akan restart. - on-abnormal restart kalau crash atau timeout, tapi gak kalau exit normal.
- no (default) gak pernah restart.
Saya selalu pakai Restart=always dengan RestartSec=5 untuk app production. Tapi kalau kamu punu script yang sengaja exit setelah selesai (misal: batch processing), pakai Type=oneshot dengan Restart=no.
Cron vs Systemd Timer
Banyak developer pakai cron buat schedule task. Systemd punya alternatif: systemd timer. Keunggulannya:
- Logging otomatis output masuk journalctl, gak perlu redirect ke file
- Dependency timer bisa tunggu service lain ready dulu
- Persisten kalau VPS mati saat jadwal task lewat, systemd timer bisa jalanin saat boot berikutnya (kalau
Persistent=true) - Monitoring
systemctl list-timersnunjukin semua timer dalam satu layar
Contoh systemd timer untuk backup harian:
# /etc/systemd/system/backup.service
[Unit]
Description=Daily Database Backup
[Service]
Type=oneshot
User=ubuntu
ExecStart=/home/ubuntu/scripts/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 3 AM
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable backup.timer
sudo systemctl start backup.timer
# Cek semua timer
systemctl list-timers
Troubleshooting: Service Gak Mau Start
Paling sering service gak jalan karena masalah permission atau path yang salah. Checklist-nya:
- Path ExecStart harus absolut gak boleh
python, harus/usr/bin/pythonatau/home/ubuntu/venv/bin/python - User harus punya akses kalau
User=ubuntu, pastikan file app dan working directory dimiliki user ubuntu - Port di bawah 1024 butuh root kalau app jalan di port 80 atau 443, atau pakai
setcap cap_net_bind_service=+ep /usr/bin/node - SELinux/AppArmor di CentOS/RHEL dengan SELinux enforcing, path ExecStart harus benar label context-nya
Urutan debugging yang efektif:
# 1. Cek status dulu
sudo systemctl status flaskapp
# 2. Kalau failed, lihat log
sudo journalctl -u flaskapp -n 50 --no-pager
# 3. Coba jalankan ExecStart manual sebagai user yang sama
sudo -u ubuntu /home/ubuntu/flaskapp/venv/bin/python /home/ubuntu/flaskapp/app.py
# 4. Kalau jalan manual tapi gak jalan di systemd, cek environment vars
sudo systemctl show flaskapp -p Environment
# 5. Cek permission working directory
ls -la /home/ubuntu/flaskapp/
Best Practices untuk Production
Beberapa hal yang saya pelajari dari trial-and-error selama manage VPS production:
- Limit resource pakai
MemoryLimit=512MdanCPUQuota=50%di section[Service]supaya satu service gak bisa habiskan seluruh resource VPS - Log rotation jurnal systemd sudah handle ini, tapi kalau app kamu nulis log sendiri ke file, pastikan setup logrotate
- Gunakan
systemctl editkalau mau override setting tanpa edit file asli, pakaisudo systemctl edit flaskapp. Ini bikin override file di/etc/systemd/system/flaskapp.service.d/yang gak akan ke-replace saat package update - Pisahkan app dan database jangan satu service jalanin dua hal. Bikin service terpisah untuk app, worker, scheduler, dll
- Health check pakai
Type=notifykalau app support sd_notify, atau pakaiWatchdogSec=30yang akan restart service kalau gak respond dalam 30 detik
Kesimpulan
Systemd itu tool yang sudah ada di tiap Linux VPS, tinggal pakai. Gak perlu install pm2, supervisor, atau forever. Dengan file .service sederhana, kamu dapat auto-restart, boot-time startup, centralized logging, dan resource limiting semua gratis, tanpa dependency tambahan.
Kalau kamu masih pakai nohup atau tmux buat jalanin app di background, cobain systemd hari ini. Bikin satu file service, reload, start, dan kelar. App kamu bakal lebih resilient, gak gampang mati, dan auto-restart kalau ada masalah.
Sudah pernah pakai systemd untuk project kamu? Atau masih pakai tools lain? Share pengalaman kamu di kolom komentar saya penasaran apa pendekatan yang paling populer di kalangan developer Indonesia.