systemd manages every service on modern Linux. If you deploy applications on Linux servers, you need to write service files.
Basic Service File
Create /etc/systemd/system/myapp.service:
[Unit]
Description=My Web Application
Documentation=https://example.com/docs
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=always
RestartSec=5
# Environment
Environment=NODE_ENV=production
Environment=PORT=3000
EnvironmentFile=/opt/myapp/.env
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/myapp/data /var/log/myapp
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myappService Types
| Type | Behavior | Use When |
|---|---|---|
simple | Process stays in foreground | Most applications (Node, Python, Go) |
forking | Process forks and parent exits | Traditional daemons (nginx, Apache) |
oneshot | Runs once and exits | Scripts, migrations, setup tasks |
notify | Process sends ready notification | Apps using sd_notify |
# Oneshot example (database migration)
[Service]
Type=oneshot
ExecStart=/opt/myapp/migrate.sh
RemainAfterExit=yesRestart Policies
# Always restart (production services)
Restart=always
RestartSec=5
# Only restart on failure (not on clean exit)
Restart=on-failure
RestartSec=10
# Limit restart attempts
StartLimitIntervalSec=300
StartLimitBurst=5
# 5 restarts in 300 seconds, then give up| Policy | On Success | On Failure | On Signal |
|---|---|---|---|
no | No | No | No |
always | Yes | Yes | Yes |
on-failure | No | Yes | Yes |
on-abnormal | No | No | Yes |
on-success | Yes | No | No |
Master this topic with hands-on labs
Go beyond reading — build real projects in sandboxed environments with expert video guidance.
Browse Courses →Dependencies and Ordering
[Unit]
# Start after these services
After=network.target postgresql.service redis.service
# Start these services if not running
Wants=postgresql.service redis.service
# Fail if these aren't available
Requires=postgresql.service
# Only start if this is present
ConditionPathExists=/opt/myapp/server.jsMultiple Commands
[Service]
# Pre-start commands
ExecStartPre=/opt/myapp/check-config.sh
ExecStartPre=/opt/myapp/migrate.sh
# Main process
ExecStart=/usr/bin/node /opt/myapp/server.js
# Graceful reload
ExecReload=/bin/kill -HUP $MAINPID
# Cleanup on stop
ExecStopPost=/opt/myapp/cleanup.shResource Limits
[Service]
# Memory limit (kill if exceeded)
MemoryMax=512M
MemoryHigh=384M
# CPU quota (50% of one core)
CPUQuota=50%
# File descriptor limit
LimitNOFILE=65536
# Process limit
LimitNPROC=4096Get weekly IT automation tips
Docker, Ansible, Terraform, MLOps — curated insights delivered to your inbox. No spam.
Subscribe Free →Timers (Cron Replacement)
Create /etc/systemd/system/backup.timer:
[Unit]
Description=Daily backup timer
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.targetCreate /etc/systemd/system/backup.service:
[Unit]
Description=Backup job
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
User=backupsudo systemctl enable backup.timer
sudo systemctl start backup.timer
systemctl list-timersTimer Schedules
OnCalendar=hourly # Every hour
OnCalendar=daily # Every day at midnight
OnCalendar=weekly # Every Monday at midnight
OnCalendar=*-*-* 06:00:00 # Every day at 6 AM
OnCalendar=Mon-Fri *-*-* 09:00:00 # Weekdays at 9 AM
OnCalendar=*-*-01 00:00:00 # First of every monthDebugging Services
# Check status
systemctl status myapp
# View logs
journalctl -u myapp -f # Follow live
journalctl -u myapp --since "1h ago" # Last hour
journalctl -u myapp -p err # Errors only
# Check why a service failed
systemctl show myapp --property=Result
systemctl show myapp --property=ExecMainStatus
# Analyze boot order
systemd-analyze blame
systemd-analyze critical-chain myapp.serviceSecurity Hardening
[Service]
# Run as non-root
User=appuser
Group=appgroup
# Filesystem restrictions
ProtectSystem=strict # Mount / as read-only
ProtectHome=true # Hide /home
PrivateTmp=true # Isolated /tmp
ReadWritePaths=/opt/myapp/data
# Network restrictions
PrivateNetwork=false # Set true if no network needed
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
# System call filtering
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
# Other hardening
NoNewPrivileges=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=trueWhat's Next?
Our Ansible Automation in 30 Minutes course automates service deployment and management across fleets of servers. Our SELinux for System Admins course covers service security policies. First lessons are free. -e ---
Ready to go deeper? Explore our hands-on DevOps courses — practical labs covering Docker, Ansible, Terraform, and more.
Ready to learn by doing?
Stop reading tutorials — start building. Expert video courses with hands-on labs in real sandboxed environments.
Related Articles
SSH Key Setup and Hardening Guide
Set up SSH keys and harden your server. Key generation, agent forwarding, config file management, and security tips for remote access.
Kubernetes Services and Ingress
Expose Kubernetes workloads with ClusterIP, NodePort, LoadBalancer services and Ingress controllers. Practical examples.
Linux Cron Jobs Complete Guide
Master Linux cron jobs for scheduling. Crontab syntax, common patterns, error handling, output logging, and systemd timer alternatives.
Tailscale Zero Trust Networking
Tailscale creates a WireGuard mesh network for zero trust access to servers, Kubernetes clusters, and databases. Learn how Tailscale replaces VPNs.
Talos Linux for Kubernetes
Talos Linux is a minimal, immutable OS designed exclusively for running Kubernetes. Learn why it exists, how it works, and when to use it instead of Ubuntu.
Taskfile Modern Build Automation
Taskfile is a modern alternative to Makefiles for task automation. Learn how to use Task for build scripts, development workflows, and CI/CD tasks with YAML.
Explore topics
Browse more articles on the topics covered here.