Làm ngay trong 5 phút — Các lệnh systemd bạn dùng mỗi ngày
Mới bắt đầu với Linux server? Đây là 5 lệnh bạn sẽ gõ nhiều đến mức thuộc lòng mà không cần cố ý:
# Kiểm tra trạng thái một service
systemctl status nginx
# Khởi động / dừng / khởi động lại
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
# Bật / tắt tự khởi động khi reboot
systemctl enable nginx
systemctl disable nginx
# Reload cấu hình mà không restart (nếu service hỗ trợ)
systemctl reload nginx
Chạy thử ngay với nginx hoặc bất kỳ service nào đang có trên máy. Output màu xanh active (running) là ổn, màu đỏ failed là có chuyện — rất trực quan, không cần đọc docs.
Hiểu systemd hoạt động như thế nào
Ra đời để thay thế SysVinit, systemd hiện là init system mặc định trên hầu hết distro Linux: Ubuntu, Debian, CentOS/AlmaLinux, Fedora… Điểm khác biệt lớn nhất so với thế hệ cũ: khởi động song song, dependency management giữa các service, và journal log tập trung thay vì rải rác khắp /var/log/.
Mỗi thứ systemd quản lý gọi là unit. Bạn sẽ hay gặp nhất 4 loại:
.service— tiến trình chạy nền (nginx, mysql, sshd…).timer— tương tự cron, chạy task theo lịch.socket— socket activation (chỉ khởi động service khi có kết nối đến).mount— quản lý mount điểm
File unit nằm ở 2 nơi chính:
/lib/systemd/system/— do package manager cài, không nên sửa trực tiếp/etc/systemd/system/— override hoặc tạo mới, đây là chỗ bạn làm việc
Tạo systemd service tùy chỉnh cho ứng dụng của bạn
Đây là phần mình dùng nhiều nhất. Mỗi khi deploy script Python hay Node.js lên server, mình đều tạo service file — không bao giờ dùng nohup hay screen nữa.
Ví dụ: deploy một ứng dụng Python chạy ở cổng 8000:
sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Python App
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/myapp
ExecStart=/home/ubuntu/myapp/venv/bin/python app.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
# Reload để systemd nhận file mới
sudo systemctl daemon-reload
# Bật và khởi động
sudo systemctl enable --now myapp
Chú ý Restart=on-failure — service tự khởi động lại khi crash. Hồi tháng trước service của mình bị crash lúc 2h sáng, tự restart trong vòng 5 giây, và mình chỉ biết chuyện đó khi xem log sáng hôm sau. Không cần thức đêm SSH vào xử lý.
Các giá trị Restart hay dùng
no— không tự restart (mặc định)on-failure— restart khi exit code khác 0always— luôn restart, kể cả khi bạnsystemctl stopthủ côngon-abnormal— restart khi bị kill bằng signal
Dùng on-failure cho 99% trường hợp. always nghe có vẻ an toàn nhưng sẽ tạo vòng lặp khởi động vô tận nếu app lỗi ngay khi start — systemd sẽ thử restart đến khi đạt giới hạn rồi đánh dấu failed luôn.
Debug khi service bị lỗi
Service báo failed? Đừng vội panic. Quy trình debug của mình:
# Xem trạng thái chi tiết + vài dòng log cuối
systemctl status myapp -l
# Xem toàn bộ log của service
journalctl -u myapp
# Xem log realtime (theo dõi trực tiếp)
journalctl -u myapp -f
# Chỉ xem log từ lần boot này
journalctl -u myapp -b
# 50 dòng cuối
journalctl -u myapp -n 50
journalctl tập trung tất cả log vào một chỗ, có timestamp, filter được theo unit và theo thời gian. Từ khi quen với nó, mình bỏ hẳn thói quen tail -f /var/log/....
Lỗi kinh điển nhất: sửa file .service xong mà quên chạy daemon-reload. systemd vẫn đang dùng bản cũ trong cache, mọi thay đổi của bạn không có tác dụng. Cứ mỗi lần sửa file là phải reload — không có ngoại lệ.
Nâng cao — Override service mà không sửa file gốc
Bài toán thực tế: muốn tăng giới hạn file descriptor cho nginx lên 65536 (mặc định chỉ 1024), nhưng không muốn sửa /lib/systemd/system/nginx.service vì lần sau apt upgrade sẽ ghi đè mất.
# Dùng lệnh edit — tự tạo thư mục override
sudo systemctl edit nginx
Lệnh trên mở editor và tạo file tại /etc/systemd/system/nginx.service.d/override.conf. Chỉ cần viết phần muốn thay đổi:
[Service]
LimitNOFILE=65536
Environment="EXTRA_OPTS=-g 'worker_processes 4;'"
Muốn kiểm tra kết quả cuối cùng sau khi gộp tất cả override lại:
systemctl cat nginx
Giới hạn tài nguyên với cgroups
Cgroups là tính năng ít người biết nhưng cực kỳ hữu dụng — systemd tích hợp sẵn, cho phép giới hạn CPU và RAM cho từng service:
[Service]
# Giới hạn tối đa 512MB RAM
MemoryMax=512M
# Giới hạn 50% CPU
CPUQuota=50%
# Ưu tiên CPU thấp hơn (mặc định 100)
CPUWeight=50
Trên VPS 2GB RAM chạy 5-6 service cùng lúc, đây là thứ giúp mình ngủ yên hơn — không lo một service nào đó ngốn hết tài nguyên và kéo cả hệ thống xuống theo.
systemd timer — Thay thế cron hiệu quả hơn
Hầu hết cronjob của mình đã chuyển sang systemd timer. Lý do đơn giản: debug dễ hơn nhiều. Log vào journal, xem được lần chạy cuối, lần chạy tiếp theo — không phải mò trong /var/log/syslog như với cron.
Ví dụ chạy script backup lúc 2h sáng mỗi ngày:
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Daily backup script
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 2am
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl enable --now backup.timer
# Xem tất cả timer và trạng thái
systemctl list-timers
Persistent=true xử lý tình huống server bị tắt đúng lúc 2h và bỏ lỡ lịch chạy — timer sẽ chạy bù ngay khi server boot lại, thay vì đợi đến đêm hôm sau.
Tips thực tế từ kinh nghiệm vận hành
1. Dùng --now để enable và start cùng lúc
systemctl enable --now myapp
# Tương đương:
systemctl enable myapp && systemctl start myapp
2. Xem tất cả service đang failed
systemctl --failed
Lệnh đầu tiên mình chạy sau khi server reboot. Nếu có service nào fail, biết ngay — không cần kiểm tra từng cái một.
3. Phân tích thời gian boot
systemd-analyze blame | head -20
Liệt kê service tốn thời gian boot nhất. Trên máy dev của mình, snapd từng ngốn hơn 30 giây — disable đi, boot từ 45s xuống còn 12s.
4. Chạy service với user riêng (security)
Không bao giờ chạy service bằng root nếu không cần thiết. Tạo user riêng:
sudo useradd -r -s /bin/false myappuser
[Service]
User=myappuser
Group=myappuser
# Thêm sandbox nếu muốn
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
5. ExecStartPre / ExecStartPost
Chạy lệnh trước khi service start — ví dụ chờ database thực sự sẵn sàng chứ không chỉ đang khởi động:
[Service]
ExecStartPre=/bin/sh -c 'until pg_isready -h localhost; do sleep 1; done'
ExecStart=/home/ubuntu/myapp/venv/bin/python app.py
Cách này tốt hơn After=postgresql.service vì After chỉ đảm bảo thứ tự start, không đảm bảo postgres đã nhận được kết nối. Mình từng bị lỗi này khi app khởi động xong trước, postgres vẫn đang warm up, kết nối fail ngay từ đầu.
