Go Binary Service

Deploy a compiled Go binary as a systemd service. Covers the advantages of static binaries, file descriptor limits for high-concurrency servers, and hardening options.

Application Services

Detailed Explanation

Deploying Go Applications with systemd

Go applications compile to static binaries, making them ideal for systemd deployment. There's no runtime to install, no virtual environment to manage, and no dependency resolution at deploy time.

[Unit]
Description=Go API Server
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapi
Restart=always
RestartSec=3
User=apiuser
Group=apiuser
WorkingDirectory=/opt/myapi
Environment="GIN_MODE=release"
Environment="PORT=8080"
Environment="DB_HOST=localhost"
LimitNOFILE=65535
StandardOutput=journal
StandardError=journal

# Hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/myapi/data

[Install]
WantedBy=multi-user.target

Why Go Binaries Are Ideal for systemd

  1. Single file deployment: Copy the binary, create the unit file, done
  2. No runtime dependency: No JVM, Python interpreter, or Node.js needed
  3. Fast startup: Go binaries start in milliseconds
  4. Static linking: All dependencies are compiled into the binary
  5. Signal handling: Go has built-in support for graceful shutdown via os.Signal

File Descriptor Limits

Go HTTP servers using net/http can handle thousands of concurrent connections. The default Linux limit of 1024 file descriptors is often insufficient:

LimitNOFILE=65535

For high-traffic servers handling 10,000+ concurrent connections, you may need even higher values.

Security Hardening

The hardening directives restrict what the service can do:

  • NoNewPrivileges=yes: Prevents the process from gaining additional privileges via setuid/setgid binaries
  • ProtectSystem=strict: Mounts the entire file system as read-only except for /dev, /proc, and /sys
  • ProtectHome=yes: Makes /home, /root, and /run/user inaccessible
  • ReadWritePaths=: Explicitly grants write access to specific directories

Graceful Shutdown

Go applications should handle SIGTERM for graceful shutdown:

ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
defer stop()
// ... start server ...
<-ctx.Done()
// ... graceful shutdown ...

Systemd sends SIGTERM by default when stopping a service. Set TimeoutStopSec= to allow enough time for graceful shutdown:

TimeoutStopSec=30

Use Case

Deploying a high-performance Go API server that handles many concurrent connections, needs fast restarts, and should run with minimal system privileges through security hardening.

Try It — Systemd Unit File Generator

Open full tool