Systemd mengelola lebih dari 70% sistem Linux dalam produksi dan merupakan init system standar untuk Ubuntu, Debian, CentOS, dan setiap distribusi Linux utama. Namun sebagian besar tutorial untuk menjalankan aplikasi Node.js dalam produksi masih merekomendasikan pm2 — manajer proses userspace yang menduplikasi fungsi yang sudah dibangun ke dalam systemd. Di Commsult Indonesia, saya memigrasikan semua background worker NestJS kami dari pm2 ke service systemd native.
pm2 sangat baik untuk pengembangan dan prototyping namun menambahkan lapisan yang tidak diperlukan dalam produksi. Systemd menangani: startup otomatis saat boot, restart otomatis saat crash dengan backoff yang dapat dikonfigurasi, batas CPU dan memori yang diterapkan oleh kernel, log terstruktur melalui journald yang dapat diakses dengan journalctl, dan integrasi dengan systemctl untuk status dan kontrol.
File service systemd berada di /etc/systemd/system/your-service.service dan memiliki tiga bagian: [Unit] mendeskripsikan service dan dependensinya, [Service] mendefinisikan cara menjalankan service, dan [Install] menentukan kapan service dimulai. Restart=on-failure me-restart saat crash namun tidak pada exit bersih — perilaku yang tepat untuk produksi.
Jangan pernah hardcode secret di file service. Gunakan EnvironmentFile=/etc/your-service/.env untuk memuat variabel lingkungan dari file dengan izin 640 yang dimiliki oleh root dan pengguna service Anda. File ini hanya dapat dibaca oleh pengguna service dan root, tidak dapat dibaca semua orang seperti file .env di direktori aplikasi.
# /etc/systemd/system/nestjs-app.service
[Unit]
Description=NestJS Production App
Documentation=https://nestjs.com
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=nestjs
WorkingDirectory=/opt/nestjs/app
ExecStart=/usr/bin/node dist/main.js
EnvironmentFile=/etc/nestjs/.env
Restart=on-failure
RestartSec=10s
StartLimitIntervalSec=60
StartLimitBurst=3
# Resource limits
MemoryMax=512M
LimitNOFILE=65535
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/opt/nestjs/app/uploads
# Logging
StandardOutput=journal+console
StandardError=journal+console
SyslogIdentifier=nestjs-app
[Install]
WantedBy=multi-user.targetDari pengalaman saya menjalankan service NestJS di Commsult Indonesia, gunakan direktif StandardOutput=journal+console dan StandardError=journal+console untuk mengirim stdout/stderr ke journald DAN ke konsol secara bersamaan. Tambahkan direktif SyslogIdentifier=your-service-name dan log ditandai dengan nama service Anda — kritis untuk pemfilteran saat Anda memiliki 10+ service yang semuanya menulis ke journald.
Perilaku restart systemd dikendalikan oleh Restart=, RestartSec=, dan StartLimitIntervalSec= / StartLimitBurst=. Untuk service produksi: Restart=on-failure me-restart pada kode exit bukan nol, RestartSec=5s menunggu 5 detik antar restart (mencegah crash loop ketat dari memukuli CPU), StartLimitIntervalSec=60 dan StartLimitBurst=5 berarti jika service me-restart 5 kali dalam 60 detik, systemd menyerah.
Systemd dapat menerapkan batas sumber daya langsung di file service: MemoryMax=512M (OOM-kill service jika melebihi 512MB), CPUQuota=50% (batasi ke setengah CPU core), LimitNOFILE=65535 (batas file descriptor untuk service), dan direktif hardening keamanan: PrivateTmp=true, ProtectSystem=strict, NoNewPrivileges=true.
# systemctl management commands
systemctl daemon-reload # reload after editing service files
systemctl enable nestjs-app # start on boot
systemctl start nestjs-app # start now
systemctl status nestjs-app # status + last 10 log lines
systemctl restart nestjs-app # restart service
# journalctl log access
journalctl -u nestjs-app -f # tail live logs
journalctl -u nestjs-app --since today
journalctl -u nestjs-app -p err # errors only
# Systemd timer (cron replacement)
# /etc/systemd/system/backup.timer
# [Timer]
# OnCalendar=daily
# OnBootSec=15min
# Persistent=true
#
# [Install]
# WantedBy=timers.target
systemctl enable --now backup.timer
systemctl list-timers # show all timers + next runPerintah systemctl penting: systemctl start/stop/restart your-service, systemctl enable your-service (mulai saat boot), systemctl status your-service (menampilkan 10 baris log terakhir plus PID dan penggunaan sumber daya), systemctl daemon-reload (diperlukan setelah mengedit file service), dan journalctl -u your-service -f (tail log untuk service).
Saya menghabiskan beberapa jam men-debug service yang mulai sebelum dependensi PostgreSQL-nya siap. After=postgresql.service hanya menjamin urutan — ia tidak memeriksa apakah PostgreSQL benar-benar siap menerima koneksi. Untuk aplikasi NestJS yang membutuhkan PostgreSQL, gunakan After=postgresql.service ditambah logika retry tingkat aplikasi.
Systemd timer adalah pengganti modern untuk pekerjaan cron, dengan logging yang lebih baik, manajemen dependensi, dan penanganan pekerjaan yang terlewat. Buat file .service yang mendeskripsikan apa yang akan dijalankan dan file .timer yang mendeskripsikan kapan menjalankannya. Gunakan OnCalendar=daily untuk pekerjaan sekali sehari.
Template service systemd NestJS produksi saya mencakup: User=nestjs (akun service khusus), WorkingDirectory=/opt/nestjs/app, ExecStart=/usr/bin/node dist/main.js, EnvironmentFile=/etc/nestjs/.env, Restart=on-failure dengan RestartSec=10s dan StartLimitBurst=3, MemoryMax=512M, LimitNOFILE=65535, NoNewPrivileges=true, PrivateTmp=true.