systemd Service Example¶
This example shows how to run Navigator as a systemd service for production deployments with automatic startup, logging, and process management.
Quick Start¶
# 1. Install Navigator
sudo cp navigator /usr/local/bin/
sudo chmod +x /usr/local/bin/navigator
# 2. Create service file
sudo tee /etc/systemd/system/navigator.service << 'EOF'
[Unit]
Description=Navigator Rails Server
After=network.target
[Service]
Type=simple
User=navigator
ExecStart=/usr/local/bin/navigator /etc/navigator/config.yml
Restart=always
[Install]
WantedBy=multi-user.target
EOF
# 3. Enable and start
sudo systemctl enable navigator
sudo systemctl start navigator
Complete Service Configuration¶
Basic Service File¶
/etc/systemd/system/navigator.service
[Unit]
Description=Navigator Rails Proxy Server
Documentation=https://rubys.github.io/navigator/
After=network.target postgresql.service redis.service
Wants=postgresql.service redis.service
[Service]
Type=simple
User=navigator
Group=navigator
WorkingDirectory=/var/www/app
# Main command
ExecStart=/usr/local/bin/navigator /etc/navigator/production.yml
# Configuration reload without restart
ExecReload=/usr/local/bin/navigator -s reload
# Process management
Restart=always
RestartSec=10
KillSignal=SIGTERM
TimeoutStopSec=60
KillMode=mixed
# Environment variables
Environment=RAILS_ENV=production
Environment=LOG_LEVEL=info
EnvironmentFile=-/etc/navigator/environment
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/www/app/log /var/www/app/tmp /var/www/app/storage
PrivateTmp=true
# Resource limits
LimitNOFILE=65536
LimitNPROC=32768
[Install]
WantedBy=multi-user.target
Environment File¶
/etc/navigator/environment
# Database configuration
DATABASE_URL=postgresql://user:password@localhost/app_production
# Rails secrets
SECRET_KEY_BASE=your-very-long-secret-key-here
RAILS_MASTER_KEY=your-rails-master-key
# Redis configuration
REDIS_URL=redis://localhost:6379
# Monitoring services
NEW_RELIC_LICENSE_KEY=your-license-key
HONEYBADGER_API_KEY=your-api-key
# Custom application settings
RAILS_MAX_THREADS=5
WEB_CONCURRENCY=2
Setup Steps¶
1. Create Navigator User¶
# Create system user
sudo useradd --system --no-create-home --shell /bin/false navigator
# Create group
sudo groupadd navigator
sudo usermod -a -G navigator navigator
# Set up application directory
sudo mkdir -p /var/www/app
sudo chown -R navigator:navigator /var/www/app
sudo chmod -R 755 /var/www/app
2. Install Navigator Binary¶
# Download and install
wget https://github.com/rubys/navigator/releases/latest/download/navigator-linux-amd64.tar.gz
tar xzf navigator-linux-amd64.tar.gz
sudo mv navigator /usr/local/bin/
sudo chmod +x /usr/local/bin/navigator
# Verify installation
navigator --version
3. Create Configuration¶
# Create configuration directory
sudo mkdir -p /etc/navigator
sudo chown root:navigator /etc/navigator
sudo chmod 750 /etc/navigator
# Create production config
sudo tee /etc/navigator/production.yml << 'EOF'
server:
listen: 3000
public_dir: /var/www/app/public
pools:
max_size: 10
idle_timeout: 300
applications:
global_env:
RAILS_ENV: production
RAILS_SERVE_STATIC_FILES: "false"
tenants:
- name: production
path: /
working_dir: /var/www/app
EOF
# Secure configuration
sudo chmod 640 /etc/navigator/production.yml
4. Set Up Environment File¶
# Create environment file
sudo touch /etc/navigator/environment
sudo chown root:navigator /etc/navigator/environment
sudo chmod 640 /etc/navigator/environment
# Add environment variables (edit with your values)
sudo tee /etc/navigator/environment << 'EOF'
DATABASE_URL=postgresql://user:password@localhost/app_production
SECRET_KEY_BASE=your-secret-key-here
REDIS_URL=redis://localhost:6379
EOF
5. Install and Enable Service¶
# Copy service file (using the complete version above)
sudo systemctl daemon-reload
# Enable service for auto-start
sudo systemctl enable navigator
# Start service
sudo systemctl start navigator
# Check status
sudo systemctl status navigator
Service Management Commands¶
Basic Operations¶
# Start Navigator
sudo systemctl start navigator
# Stop Navigator
sudo systemctl stop navigator
# Restart Navigator
sudo systemctl restart navigator
# Reload configuration without restart
sudo systemctl reload navigator
# Enable auto-start on boot
sudo systemctl enable navigator
# Disable auto-start
sudo systemctl disable navigator
Status and Monitoring¶
# Check service status
sudo systemctl status navigator
# View recent logs
sudo journalctl -u navigator -n 50
# Follow logs in real-time
sudo journalctl -u navigator -f
# View logs from today
sudo journalctl -u navigator --since today
# View error logs only
sudo journalctl -u navigator -p err
Configuration Examples¶
High-Availability Setup¶
/etc/systemd/system/navigator.service
[Unit]
Description=Navigator Rails Server (HA)
After=network.target postgresql.service redis.service
Requires=postgresql.service redis.service
[Service]
Type=simple
User=navigator
Group=navigator
WorkingDirectory=/var/www/app
ExecStart=/usr/local/bin/navigator /etc/navigator/production.yml
ExecReload=/usr/local/bin/navigator -s reload
# High availability settings
Restart=always
RestartSec=5
StartLimitInterval=0
# Health checking
ExecStartPre=/usr/local/bin/health-check.sh
TimeoutStartSec=30
TimeoutStopSec=120
# Resource management
LimitNOFILE=65536
LimitNPROC=32768
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
Development Setup¶
/etc/systemd/system/navigator-dev.service
[Unit]
Description=Navigator Rails Server (Development)
After=network.target
[Service]
Type=simple
User=developer
Group=developer
WorkingDirectory=/home/developer/myapp
ExecStart=/usr/local/bin/navigator config/navigator.yml
# Development settings
Restart=on-failure
RestartSec=2
Environment=RAILS_ENV=development
Environment=LOG_LEVEL=debug
# Allow user to see logs easily
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Multi-Instance Setup¶
/etc/systemd/system/navigator@.service
[Unit]
Description=Navigator Rails Server (%i)
After=network.target
[Service]
Type=simple
User=navigator
Group=navigator
WorkingDirectory=/var/www/%i
ExecStart=/usr/local/bin/navigator /etc/navigator/%i.yml
ExecReload=/usr/local/bin/navigator -s reload
Restart=always
RestartSec=10
# Instance-specific environment
EnvironmentFile=/etc/navigator/%i.env
[Install]
WantedBy=multi-user.target
# Start multiple instances
sudo systemctl enable navigator@app1
sudo systemctl enable navigator@app2
sudo systemctl start navigator@app1
sudo systemctl start navigator@app2
Security Hardening¶
Enhanced Security Configuration¶
/etc/systemd/system/navigator.service
[Service]
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
# File system access
ReadWritePaths=/var/www/app/log /var/www/app/tmp /var/www/app/storage
ReadOnlyPaths=/var/www/app
# Network restrictions
IPAddressDeny=any
IPAddressAllow=localhost
IPAddressAllow=127.0.0.1/8
IPAddressAllow=10.0.0.0/8
# System call filtering
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@debug @mount @cpu-emulation @obsolete
Logging Configuration¶
Log Management¶
# Create log directory
sudo mkdir -p /var/log/navigator
sudo chown navigator:navigator /var/log/navigator
# Configure rsyslog for Navigator logs
sudo tee /etc/rsyslog.d/navigator.conf << 'EOF'
# Navigator logs
if $programname == 'navigator' then /var/log/navigator/navigator.log
& stop
EOF
# Restart rsyslog
sudo systemctl restart rsyslog
Log Rotation¶
# Configure log rotation
sudo tee /etc/logrotate.d/navigator << 'EOF'
/var/log/navigator/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 navigator navigator
sharedscripts
postrotate
/usr/bin/systemctl reload navigator
endscript
}
EOF
Monitoring and Health Checks¶
Health Check Script¶
/usr/local/bin/navigator-health-check.sh
#!/bin/bash
# Navigator health check for systemd
# Check process is running
if ! systemctl is-active --quiet navigator; then
echo "Navigator service not active"
exit 1
fi
# Check HTTP response
if ! curl -f -s http://localhost:3000/up > /dev/null; then
echo "Navigator not responding to HTTP requests"
exit 1
fi
# Check log for recent errors
if journalctl -u navigator --since "5 minutes ago" -p err | grep -q "ERROR"; then
echo "Recent errors found in Navigator logs"
exit 1
fi
echo "Navigator health check passed"
exit 0
# Make executable and test
sudo chmod +x /usr/local/bin/navigator-health-check.sh
/usr/local/bin/navigator-health-check.sh
Systemd Monitoring Integration¶
# Add to [Service] section
ExecStartPre=/usr/local/bin/navigator-health-check.sh
WatchdogSec=60
NotifyAccess=all
Troubleshooting¶
Common Issues¶
Service Fails to Start¶
# Check detailed status
sudo systemctl status navigator -l
# Check logs for errors
sudo journalctl -u navigator -n 20
# Validate configuration
sudo -u navigator navigator --validate /etc/navigator/production.yml
# Check file permissions
ls -la /etc/navigator/
ls -la /usr/local/bin/navigator
Service Stops Unexpectedly¶
# Check why service stopped
sudo journalctl -u navigator --since "1 hour ago"
# Look for system events
sudo journalctl --since "1 hour ago" | grep navigator
# Check resource usage
sudo systemctl show navigator --property=MemoryUsage,CPUUsage
Configuration Reload Fails¶
# Test reload manually
sudo systemctl reload navigator
# Check reload logs
sudo journalctl -u navigator | grep reload
# Validate configuration
sudo -u navigator navigator --validate /etc/navigator/production.yml
Service Debugging¶
# Run Navigator manually for debugging
sudo systemctl stop navigator
sudo -u navigator /usr/local/bin/navigator /etc/navigator/production.yml
# Enable debug logging
sudo systemctl edit navigator
# Add:
[Service]
Environment=LOG_LEVEL=debug
# View service environment
sudo systemctl show-environment
sudo systemctl show navigator --property=Environment
Integration Examples¶
nginx + Navigator¶
/etc/nginx/sites-available/navigator
upstream navigator {
server 127.0.0.1:3000 fail_timeout=0;
}
server {
listen 80;
server_name myapp.com;
location / {
proxy_pass http://navigator;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
PostgreSQL Dependencies¶
# Add to [Unit] section
After=postgresql.service
Wants=postgresql.service
# Add to [Service] section
ExecStartPre=/usr/bin/pg_isready -h localhost -p 5432
Load Balancer Health Checks¶
# Add health check endpoint
[Service]
ExecStartPost=/bin/bash -c 'until curl -f http://localhost:3000/up; do sleep 1; done'
Best Practices¶
1. Security¶
- Run as dedicated non-root user
- Use environment files for secrets
- Enable security hardening options
- Restrict file system access
2. Reliability¶
- Configure automatic restart
- Set appropriate timeouts
- Monitor health with watchdog
- Use dependency management
3. Operations¶
- Centralized logging
- Log rotation
- Health monitoring
- Graceful configuration reloads
4. Performance¶
- Optimize resource limits
- Use appropriate restart policies
- Monitor memory and CPU usage
- Scale with multiple instances