Production Deployment¶
This guide covers deploying Navigator in production environments with best practices for security, performance, and reliability.
Quick Start¶
# 1. Install Navigator
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
# 2. Create configuration
sudo mkdir -p /etc/navigator
sudo cp config.yml /etc/navigator/production.yml
# 3. Set up systemd service
sudo cp navigator.service /etc/systemd/system/
sudo systemctl enable navigator
sudo systemctl start navigator
System Requirements¶
Hardware Requirements¶
Component | Minimum | Recommended | Notes |
---|---|---|---|
CPU | 1 core | 2+ cores | Per Rails process |
Memory | 1GB | 4GB+ | Rails apps are memory-intensive |
Storage | 5GB | 20GB+ | Logs, uploads, assets |
Network | 100Mbps | 1Gbps+ | For high traffic sites |
Software Requirements¶
Software | Version | Purpose |
---|---|---|
Linux | Ubuntu 20.04+, RHEL 8+ | Production OS |
Ruby | 3.0+ | Rails applications |
Node.js | 16+ | Asset compilation |
Database | PostgreSQL 12+, MySQL 8+ | Application data |
Redis | 6.0+ | Caching, sessions |
Installation¶
Binary Installation (Recommended)¶
# Download latest release
cd /tmp
wget https://github.com/rubys/navigator/releases/latest/download/navigator-linux-amd64.tar.gz
# Extract and install
tar xzf navigator-linux-amd64.tar.gz
sudo mv navigator /usr/local/bin/
sudo chmod +x /usr/local/bin/navigator
# Verify installation
navigator --version
Building from Source¶
# Install Go 1.21+
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# Clone and build
git clone https://github.com/rubys/navigator.git
cd navigator
make build
sudo cp bin/navigator /usr/local/bin/
Configuration¶
Production Configuration¶
/etc/navigator/production.yml
server:
listen: 3000
hostname: myapp.com
public_dir: /var/www/app/public
pools:
max_size: 20 # Scale based on server capacity
idle_timeout: 600 # 10 minutes for production
start_port: 4000
# Authentication for admin areas
auth:
enabled: true
realm: "Production Application"
htpasswd: /etc/navigator/htpasswd
public_paths:
- /assets/
- /robots.txt
- /favicon.ico
- "*.css"
- "*.js"
# Optimized static file serving
static:
directories:
- path: /assets/
root: /var/www/app/public/assets/
cache: 31536000 # 1 year for fingerprinted assets
- path: /images/
root: /var/www/app/public/images/
cache: 86400 # 1 day for images
extensions: [css, js, png, jpg, gif, ico, svg, woff, woff2]
applications:
global_env:
RAILS_ENV: production
RAILS_SERVE_STATIC_FILES: "false"
RAILS_LOG_TO_STDOUT: "true"
SECRET_KEY_BASE: "${SECRET_KEY_BASE}"
DATABASE_URL: "${DATABASE_URL}"
REDIS_URL: "${REDIS_URL}"
tenants:
- name: production
path: /
working_dir: /var/www/app
# Managed processes
managed_processes:
- name: redis
command: redis-server
args: [/etc/redis/redis.conf]
auto_restart: true
- name: sidekiq
command: bundle
args: [exec, sidekiq]
working_dir: /var/www/app
env:
RAILS_ENV: production
auto_restart: true
start_delay: 2
Environment Variables¶
/etc/navigator/environment
# Database
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
REDIS_URL=redis://localhost:6379
# Monitoring
NEW_RELIC_LICENSE_KEY=your-license-key
HONEYBADGER_API_KEY=your-api-key
systemd Service¶
Service Configuration¶
/etc/systemd/system/navigator.service
[Unit]
Description=Navigator Rails Proxy Server
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
# Reload configuration without restart
ExecReload=/usr/local/bin/navigator -s reload
# Process management
Restart=always
RestartSec=10
KillSignal=SIGTERM
TimeoutStopSec=60
# Environment
Environment=RAILS_ENV=production
Environment=LOG_LEVEL=info
EnvironmentFile=-/etc/navigator/environment
# Security
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/www/app/log /var/www/app/tmp /var/www/app/storage
# Resource limits
LimitNOFILE=65536
LimitNPROC=32768
[Install]
WantedBy=multi-user.target
Service Management¶
# Enable and start service
sudo systemctl enable navigator
sudo systemctl start navigator
# Check status
sudo systemctl status navigator
# View logs
sudo journalctl -u navigator -f
# Reload configuration
sudo systemctl reload navigator
# Restart service
sudo systemctl restart navigator
User and Permissions¶
Create Navigator User¶
# Create dedicated user
sudo useradd --system --no-create-home --shell /bin/false navigator
# Create group
sudo groupadd navigator
sudo usermod -a -G navigator navigator
# Set up directories
sudo mkdir -p /var/www/app
sudo chown -R navigator:navigator /var/www/app
sudo chmod -R 755 /var/www/app
# Configuration permissions
sudo chown -R root:navigator /etc/navigator
sudo chmod -R 640 /etc/navigator
File Permissions¶
# Application files
sudo chown -R navigator:navigator /var/www/app
sudo find /var/www/app -type f -exec chmod 644 {} \;
sudo find /var/www/app -type d -exec chmod 755 {} \;
# Writable directories
sudo chmod 755 /var/www/app/log
sudo chmod 755 /var/www/app/tmp
sudo chmod 755 /var/www/app/storage
# Configuration security
sudo chmod 600 /etc/navigator/production.yml
sudo chmod 600 /etc/navigator/environment
Security¶
Authentication Setup¶
# Create htpasswd file
sudo htpasswd -c /etc/navigator/htpasswd admin
sudo htpasswd /etc/navigator/htpasswd user1
# Secure htpasswd file
sudo chown root:navigator /etc/navigator/htpasswd
sudo chmod 640 /etc/navigator/htpasswd
Firewall Configuration¶
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow SSH (adjust port as needed)
sudo ufw allow 22/tcp
# Enable firewall
sudo ufw --force enable
SSL/TLS Termination¶
For production, use a reverse proxy for SSL termination:
/etc/nginx/sites-available/navigator
server {
listen 80;
server_name myapp.com www.myapp.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name myapp.com www.myapp.com;
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/private.key;
# SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $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;
}
}
Monitoring and Logging¶
Log Configuration¶
# Create log directory
sudo mkdir -p /var/log/navigator
sudo chown navigator:navigator /var/log/navigator
# 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
postrotate
/usr/local/bin/navigator -s reload
endscript
}
EOF
Health Checks¶
#!/bin/bash
# /usr/local/bin/health-check.sh
# Check Navigator process
if ! pgrep -f navigator > /dev/null; then
echo "ERROR: Navigator not running"
exit 1
fi
# Check HTTP response
if ! curl -f http://localhost:3000/up > /dev/null 2>&1; then
echo "ERROR: Navigator not responding"
exit 1
fi
echo "OK: Navigator healthy"
exit 0
# Make executable and test
sudo chmod +x /usr/local/bin/health-check.sh
/usr/local/bin/health-check.sh
Monitoring Integration¶
New Relic¶
# Add to applications.global_env
NEW_RELIC_LICENSE_KEY: "${NEW_RELIC_LICENSE_KEY}"
NEW_RELIC_APP_NAME: "MyApp Production"
Prometheus Metrics¶
# Custom metrics script
#!/bin/bash
# /usr/local/bin/navigator-metrics.sh
# Process count
echo "navigator_processes $(pgrep -f navigator | wc -l)"
# Memory usage
echo "navigator_memory_bytes $(ps -o pid,rss -p $(pgrep -f navigator) | tail -n +2 | awk '{sum+=$2} END {print sum*1024}')"
# Request count (from logs)
echo "navigator_requests_total $(grep -c 'GET\|POST' /var/log/navigator/access.log)"
Performance Tuning¶
Resource Optimization¶
# Optimize for server capacity
pools:
max_size: 20 # 2GB RAM = ~10 processes, 4GB = ~20
idle_timeout: 600 # Keep processes alive longer
start_port: 4000
# Efficient static file serving
static:
directories:
- path: /assets/
root: /var/www/app/public/assets/
cache: 31536000 # Long cache for assets
Database Optimization¶
# PostgreSQL connection pooling
DATABASE_URL=postgresql://user:pass@localhost/app?pool=25
# Redis optimization
REDIS_URL=redis://localhost:6379/0?pool_size=10
System Tuning¶
# Increase file descriptor limits
echo "navigator soft nofile 65536" >> /etc/security/limits.conf
echo "navigator hard nofile 65536" >> /etc/security/limits.conf
# Kernel network tuning
echo 'net.core.somaxconn = 32768' >> /etc/sysctl.conf
echo 'net.ipv4.ip_local_port_range = 1024 65535' >> /etc/sysctl.conf
sysctl -p
Backup and Recovery¶
Configuration Backup¶
#!/bin/bash
# /usr/local/bin/backup-navigator.sh
BACKUP_DIR="/backup/navigator/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
# Backup configuration
cp -r /etc/navigator "$BACKUP_DIR/"
# Backup application
tar czf "$BACKUP_DIR/app.tar.gz" /var/www/app
echo "Backup completed: $BACKUP_DIR"
Disaster Recovery¶
#!/bin/bash
# /usr/local/bin/restore-navigator.sh
BACKUP_DIR="$1"
if [[ -z "$BACKUP_DIR" ]]; then
echo "Usage: $0 /path/to/backup"
exit 1
fi
# Stop Navigator
sudo systemctl stop navigator
# Restore configuration
sudo cp -r "$BACKUP_DIR/navigator" /etc/
# Restore application
tar xzf "$BACKUP_DIR/app.tar.gz" -C /
# Fix permissions
sudo chown -R navigator:navigator /var/www/app
# Start Navigator
sudo systemctl start navigator
Troubleshooting¶
Common Issues¶
Navigator Won't Start¶
# Check configuration
navigator --validate /etc/navigator/production.yml
# Check permissions
ls -la /etc/navigator/
sudo -u navigator navigator /etc/navigator/production.yml
# Check systemd logs
sudo journalctl -u navigator -n 50
High Memory Usage¶
# Check Rails processes
ps aux | grep -E "(navigator|rails|ruby)" | sort -k 4 -nr
# Monitor memory over time
while true; do
ps -o pid,rss,cmd -p $(pgrep -f rails) | tail -n +2 | awk '{sum+=$2} END {print sum/1024 " MB"}'
sleep 5
done
Poor Performance¶
# Check process count
ps aux | grep rails | wc -l
# Monitor response times
tail -f /var/log/navigator.log | grep -E "completed|duration"
# Check database connections
sudo -u postgres psql -c "SELECT count(*) FROM pg_stat_activity WHERE datname='app_production';"
Performance Monitoring¶
# Request monitoring
tail -f /var/log/navigator.log | grep -E "(GET|POST)" | head -20
# Process monitoring
watch 'ps aux | grep -E "(navigator|rails)" | head -10'
# Memory monitoring
watch 'free -h'
Best Practices¶
1. Configuration Management¶
- Version control all configuration files
- Use environment variables for secrets
- Validate configuration before deployment
- Test configuration changes in staging first
2. Security¶
- Run Navigator as dedicated non-root user
- Use strong authentication for admin areas
- Keep secrets in environment files, not config
- Regular security updates
3. Monitoring¶
- Set up health checks
- Monitor logs for errors
- Track resource usage
- Alert on service failures
4. Deployment¶
- Use blue-green deployments
- Test thoroughly in staging
- Have rollback procedures ready
- Automate common tasks