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.
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
- Single file deployment: Copy the binary, create the unit file, done
- No runtime dependency: No JVM, Python interpreter, or Node.js needed
- Fast startup: Go binaries start in milliseconds
- Static linking: All dependencies are compiled into the binary
- 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 binariesProtectSystem=strict: Mounts the entire file system as read-only except for/dev,/proc, and/sysProtectHome=yes: Makes/home,/root, and/run/userinaccessibleReadWritePaths=: 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.