Khi chạy Node.js, Python, Go hoặc một ứng dụng tự viết trên VPS Ubuntu, mở chương trình bằng terminal rồi để đó không phải cách vận hành ổn định. Nếu phiên SSH bị đóng, tiến trình crash hoặc VPS reboot, ứng dụng có thể dừng hoàn toàn. Systemd cho phép biến ứng dụng thành một service được hệ điều hành quản lý: tự khởi động khi boot, tự restart theo chính sách, chạy bằng user riêng, nhận biến môi trường và ghi log vào journal. Bài viết này hướng dẫn từ cấu trúc unit file, `ExecStart`, `WorkingDirectory`, `User`, `Restart`, `EnvironmentFile`, `daemon-reload`, `enable`, `journalctl` đến cách xử lý lỗi `status=203/EXEC`, restart loop và quyền file.
Nếu bạn đang chạy một ứng dụng bằng lệnh như:
node app.js
hoặc:
python3 app.py
thì tiến trình đó thường phụ thuộc vào phiên terminal hiện tại. Khi SSH bị đóng, VPS reboot hoặc ứng dụng crash, chương trình có thể ngừng chạy.
Trên Ubuntu Server hiện đại, cách tiêu chuẩn để quản lý daemon/service là systemd. Bạn có thể tạo một file .service để systemd chịu trách nhiệm start, stop, restart, tự chạy sau boot, quản lý user và ghi log.
Nếu bạn mới làm quen terminal, hãy đọc trước bài Các lệnh Linux cơ bản trên VPS Ubuntu. Nếu ứng dụng chạy trong container, bài Cài Docker và Docker Compose trên VPS Ubuntu có thể phù hợp hơn.
1. Systemd là gì?
Systemd là service manager và init system được Ubuntu Server hiện đại sử dụng để quản lý:
- service;
- timer;
- mount;
- socket;
- target;
- dependency lúc boot.
Với ứng dụng tự viết, bạn thường tạo service unit có đuôi .service.
2. Vì sao nên dùng systemd thay vì chạy app thủ công?
Systemd giúp:
- tự chạy app sau reboot;
- tự restart khi process lỗi;
- chạy bằng user không phải root;
- kiểm soát working directory;
- truyền biến môi trường;
- xem log bằng
journalctl; - giới hạn tài nguyên nếu cần;
- quản lý dependency với network hoặc service khác.
3. Ví dụ ứng dụng trong bài
Giả sử ứng dụng nằm ở:
/opt/myapp
và file chạy chính là:
/opt/myapp/app.py
User chạy ứng dụng:
appuser
Bạn có thể thay bằng Node.js, Go binary hoặc lệnh thật của ứng dụng.
4. Tạo user riêng cho service
Không nên chạy mọi ứng dụng bằng root.
Tạo system user:
sudo useradd --system --home /opt/myapp --shell /usr/sbin/nologin appuser
Đặt ownership:
sudo chown -R appuser:appuser /opt/myapp
Nếu ứng dụng cần truy cập file ở nơi khác, hãy cấp đúng quyền cần thiết thay vì đưa user vào sudo.
5. Kiểm tra ứng dụng chạy thủ công trước
Trước khi tạo service, chạy đúng lệnh bằng user mục tiêu:
sudo -u appuser /usr/bin/python3 /opt/myapp/app.py
Nếu lệnh này không chạy được, systemd cũng sẽ không sửa được lỗi của ứng dụng.
6. Xác định đường dẫn executable tuyệt đối
Dùng:
which python3
Ví dụ:
/usr/bin/python3
Với Node.js:
which node
Systemd nên dùng đường dẫn rõ ràng trong ExecStart.
7. Tạo file service
Tạo:
sudo nano /etc/systemd/system/myapp.service
Ví dụ cơ bản:
[Unit]
Description=My Application
After=network.target
[Service]
Type=exec
User=appuser
Group=appuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
8. Giải thích phần [Unit]
[Unit]
Description=My Application
After=network.target
Description giúp hiển thị tên dễ hiểu.
After=network.target chỉ xác định thứ tự tương đối với network target; nó không đảm bảo Internet bên ngoài đã sẵn sàng hoàn toàn.
Nếu ứng dụng cần network-online, có thể cân nhắc dependency phù hợp hơn nhưng cần hiểu network stack của VPS.
9. Type=exec là gì?
Systemd hỗ trợ nhiều Type như:
simple;exec;forking;oneshot;notify;dbus.
Với ứng dụng foreground hiện đại, Type=exec hoặc simple thường phù hợp.
Tài liệu systemd hiện khuyến nghị Type=exec trong nhiều trường hợp vì service manager chỉ coi bước exec thành công khi executable thật sự được gọi.
10. User và Group
User=appuser
Group=appuser
Service sẽ chạy bằng quyền của user này thay vì root.
Đây là một lớp bảo mật rất quan trọng.
11. WorkingDirectory
WorkingDirectory=/opt/myapp
Nếu ứng dụng dùng path tương đối như:
./config.json
thì working directory phải đúng.
Nếu thiếu, ứng dụng có thể chạy nhưng không tìm thấy file config.
12. ExecStart
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Đây là lệnh systemd chạy khi service start.
Với Node.js:
ExecStart=/usr/bin/node /opt/myapp/server.js
Với binary Go:
ExecStart=/opt/myapp/myserver
13. Restart=on-failure
Restart=on-failure
RestartSec=5
on-failure giúp restart khi process exit lỗi hoặc bị kết thúc bất thường theo các điều kiện systemd hỗ trợ.
Không nên dùng Restart=always máy móc cho mọi service vì có thể tạo restart loop vô hạn ngay cả khi ứng dụng tự exit hợp lệ.
14. Bật service sau boot
Sau khi tạo file:
sudo systemctl daemon-reload
Start:
sudo systemctl start myapp
Kiểm tra:
sudo systemctl status myapp
Nếu ổn:
sudo systemctl enable myapp
Hoặc gộp:
sudo systemctl enable --now myapp
15. Vì sao phải chạy daemon-reload?
Systemd giữ cache unit file.
Sau khi tạo hoặc sửa file .service, chạy:
sudo systemctl daemon-reload
để systemd đọc lại unit definition.
16. Xem log bằng journalctl
sudo journalctl -u myapp
100 dòng cuối:
sudo journalctl -u myapp -n 100
Theo dõi realtime:
sudo journalctl -u myapp -f
Log từ boot hiện tại:
sudo journalctl -u myapp -b
17. stdout và stderr đi đâu?
Mặc định trong nhiều cấu hình systemd, stdout/stderr của service được gửi vào journal.
Bạn không cần redirect > app.log 2>&1 trong ExecStart nếu muốn dùng journal.
18. Biến môi trường trực tiếp trong service
Ví dụ:
Environment="APP_ENV=production"
Environment="PORT=8080"
Nhưng không nên đặt secret nhạy cảm trực tiếp trong unit file nếu file dễ được nhiều user đọc.
19. Dùng EnvironmentFile
Tạo:
sudo nano /etc/myapp.env
Ví dụ:
APP_ENV=production
PORT=8080
DATABASE_URL=mysql://...
Giới hạn quyền:
sudo chown root:appuser /etc/myapp.env
sudo chmod 640 /etc/myapp.env
Trong service:
EnvironmentFile=/etc/myapp.env
Sau đó:
sudo systemctl daemon-reload
sudo systemctl restart myapp
20. Không dùng shell syntax trực tiếp trong ExecStart
Systemd không chạy ExecStart qua shell theo cách bạn gõ trong terminal.
Ví dụ này không nên dùng trực tiếp:
ExecStart=cd /opt/myapp && python3 app.py
Hãy dùng:
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Nếu thật sự cần shell, phải gọi rõ:
ExecStart=/bin/bash -lc '...'
nhưng nên tránh nếu không cần.
21. Lỗi status=203/EXEC
Đây là lỗi phổ biến khi executable không chạy được.
Kiểm tra:
- đường dẫn trong
ExecStart; - file có tồn tại không;
- permission execute;
- shebang;
- architecture binary.
Ví dụ:
ls -l /opt/myapp/myserver
file /opt/myapp/myserver
22. Service restart liên tục
Kiểm tra:
sudo systemctl status myapp
sudo journalctl -u myapp -n 200
Có thể app crash ngay khi start và Restart=on-failure làm nó lặp lại.
Sửa lỗi app trước thay vì chỉ tăng RestartSec.
23. Start limit
Systemd có cơ chế rate limit restart để tránh vòng lặp quá nhanh.
Nếu service báo start request repeated too quickly, hãy sửa lỗi gốc rồi chạy:
sudo systemctl reset-failed myapp
sudo systemctl start myapp
24. Service cần database khởi động trước
Bạn có thể thêm:
After=mysql.service
và tùy trường hợp:
Requires=mysql.service
Nhưng dependency chỉ đảm bảo quan hệ service, không đảm bảo database đã sẵn sàng nhận query.
Ứng dụng vẫn nên có retry connection.
25. Restart service sau khi deploy
Sau khi update source:
sudo systemctl restart myapp
Kiểm tra:
sudo systemctl status myapp
Không cần daemon-reload nếu chỉ thay source, không thay unit file.
26. Reload thay restart được không?
Chỉ khi ứng dụng có cơ chế reload config riêng và unit có ExecReload phù hợp.
Nếu không, systemctl reload có thể không hoạt động.
27. Graceful stop
Khi systemctl stop myapp, systemd gửi signal theo cấu hình service.
Ứng dụng nên bắt SIGTERM và shutdown sạch:
- đóng connection;
- flush queue;
- đóng file;
- hoàn tất request đang xử lý.
28. TimeoutStopSec
Nếu app cần thời gian shutdown:
TimeoutStopSec=30
Sau timeout, systemd có thể buộc kết thúc process theo policy.
29. Chạy service Node.js
Ví dụ:
[Unit]
Description=Node API
After=network.target
[Service]
Type=exec
User=nodeapp
Group=nodeapp
WorkingDirectory=/srv/node-api
Environment=NODE_ENV=production
ExecStart=/usr/bin/node /srv/node-api/server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
30. Chạy Python virtualenv
Nếu virtualenv ở:
/opt/myapp/venv
thì dùng trực tiếp interpreter:
ExecStart=/opt/myapp/venv/bin/python /opt/myapp/app.py
Không cần source venv/bin/activate.
31. Chạy Gunicorn
Ví dụ:
ExecStart=/opt/myapp/venv/bin/gunicorn --bind 127.0.0.1:8000 wsgi:app
Nginx có thể reverse proxy tới 127.0.0.1:8000.
32. Giới hạn file descriptor
Nếu app cần nhiều connection:
LimitNOFILE=65535
Chỉ tăng khi workload cần và ứng dụng hỗ trợ.
33. Bảo mật systemd service
Systemd hỗ trợ nhiều hardening option như:
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
Nhưng các option này có thể làm app không đọc/ghi được nơi cần thiết.
Nên bật từng bước và test thay vì copy một block hardening lớn.
34. Kiểm tra unit file
Bạn có thể dùng:
systemd-analyze verify /etc/systemd/system/myapp.service
Lệnh này giúp phát hiện một số lỗi trong unit file.
35. Xem unit file systemd đang dùng
systemctl cat myapp
Điều này hữu ích nếu có override/drop-in.
36. Xem cấu hình runtime
systemctl show myapp
Bạn có thể lọc:
systemctl show myapp -p User -p ExecStart -p Restart
37. Dùng drop-in để override service package
Nếu service do package cung cấp, không nên sửa trực tiếp file trong /lib/systemd/system hoặc /usr/lib/systemd/system.
Dùng:
sudo systemctl edit ten-service
Systemd sẽ tạo override trong /etc/systemd/system/...d/.
38. Tình huống thực tế: app tự chạy sau reboot
Sau khi enable:
sudo reboot
Đăng nhập lại:
systemctl status myapp
Nếu active (running), service đã tự khởi động.
39. Tình huống thực tế: app crash giữa đêm
Với:
Restart=on-failure
RestartSec=5
systemd có thể tự start lại process.
Nhưng bạn vẫn cần monitoring để biết app đã crash. Auto restart không thay thế alert.
40. Kết hợp với Uptime Kuma
Bạn có thể monitor HTTP endpoint của app bằng Uptime Kuma.
Systemd lo process lifecycle, Uptime Kuma lo availability monitoring. Hai lớp này bổ sung cho nhau.
41. Backup unit file
Các file quan trọng:
/etc/systemd/system/myapp.service
/etc/myapp.env
Nên đưa unit file vào repository infrastructure/deploy nếu không chứa secret.
42. Xóa service
sudo systemctl disable --now myapp
sudo rm /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl reset-failed
Sau đó xóa app/user nếu không còn dùng.
43. Checklist tạo systemd service
- App chạy thủ công bằng đúng user.
- Có user riêng.
-
WorkingDirectoryđúng. -
ExecStartdùng path chính xác. -
Restartphù hợp. -
daemon-reloadsau khi sửa unit. -
systemctl enablenếu cần boot startup. -
journalctlđọc được log. - Reboot test.
- Có monitoring.
44. FAQ về systemd service trên VPS Ubuntu
systemd có thay PM2 không?
Không hoàn toàn. PM2 có tính năng riêng cho Node.js, còn systemd là service manager cấp hệ điều hành. Bạn có thể dùng trực tiếp systemd hoặc kết hợp tùy kiến trúc.
Có cần chạy app bằng root không?
Không, trừ khi có lý do đặc biệt. Nên dùng user riêng.
enable khác start thế nào?
start chạy service ngay. enable cấu hình để service được khởi động theo target khi boot.
Có cần daemon-reload mỗi lần restart app không?
Không. Chỉ cần khi unit file/drop-in thay đổi.
Restart=always có tốt không?
Không phải lúc nào. on-failure thường hợp lý hơn cho nhiều daemon vì tránh restart khi process tự exit hợp lệ.
Log service nằm ở đâu?
Có thể xem bằng:
journalctl -u ten-service
Kết luận
Tạo systemd service trên VPS Ubuntu giúp ứng dụng chạy ổn định hơn nhiều so với giữ một terminal SSH mở. Bạn có thể tự động start sau boot, restart khi lỗi, quản lý log và giảm quyền bằng user riêng.
Điểm quan trọng là chạy app foreground, dùng ExecStart chính xác, kiểm tra log khi lỗi và không lạm dụng root hoặc restart loop.
Nếu bạn đang triển khai API, bot hợp lệ, worker hoặc backend 24/7 trên VPS Ubuntu tại HUONG CLOUD, systemd là nền tảng quản lý process nên được thiết lập ngay từ đầu.
Nguồn tham khảo
- Ubuntu manpage – systemd.service: https://manpages.ubuntu.com/manpages/resolute/man5/systemd.service.5.html
- Ubuntu manpage – systemctl: https://manpages.ubuntu.com/manpages/resolute/man1/systemctl.1.html
- systemd documentation: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
Kết luận
Nếu chưa chắc cấu hình hoặc loại dịch vụ nào phù hợp, hãy gửi nhu cầu thực tế để đội ngũ hỗ trợ tư vấn trước khi mua.
Chưa biết nên chọn gói nào?
Xem bảng giá VPS hoặc liên hệ đội ngũ hỗ trợ để chọn cấu hình phù hợp.
Xem bảng giá VPS →