Deployment Guide

Deploy Rackd in production

This guide covers various deployment methods for Rackd in production environments.

Docker Deployment

Basic Docker Run

# Create data directory
mkdir -p /opt/rackd/data

# Run container
docker run -d \
  --name rackd \
  -p 8080:8080 \
  -v /opt/rackd/data:/data \
  -e DATA_DIR=/data \
  ghcr.io/martinsuchenak/rackd:latest

Docker with Environment Variables

docker run -d \
  --name rackd \
  -p 8080:8080 \
  -v /opt/rackd/data:/data \
  -e DATA_DIR=/data \
  -e LOG_LEVEL=info \
  -e LOG_FORMAT=json \
  -e ENCRYPTION_KEY=your-64-hex-char-key \
  -e INITIAL_ADMIN_USERNAME=admin \
  -e INITIAL_ADMIN_PASSWORD=your-secure-password \
  ghcr.io/martinsuchenak/rackd:latest

Docker Compose

Create docker-compose.yml:

version: '3.8'

services:
  rackd:
    image: ghcr.io/martinsuchenak/rackd:latest
    container_name: rackd
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./data:/data
    environment:
      - DATA_DIR=/data
      - LOG_LEVEL=info
      - LOG_FORMAT=json
      - ENCRYPTION_KEY=${ENCRYPTION_KEY}
      - INITIAL_ADMIN_USERNAME=${INITIAL_ADMIN_USERNAME:-admin}
      - INITIAL_ADMIN_PASSWORD=${INITIAL_ADMIN_PASSWORD}
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/healthz"]
      interval: 30s
      timeout: 5s
      retries: 3

  nginx:
    image: nginx:alpine
    container_name: rackd-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - rackd

Create .env file:

ENCRYPTION_KEY=your-64-hex-char-key
INITIAL_ADMIN_USERNAME=admin
INITIAL_ADMIN_PASSWORD=your-secure-password

Deploy:

docker-compose up -d

Docker Networking for Discovery

The default Docker bridge network NATs all container traffic, which breaks Layer-2 discovery features: no ARP visibility (MAC addresses and vendors), and broadcast protocols (mDNS/NetBIOS/LLDP) cannot cross the bridge — only unicast TCP/ICMP probing works.

For full discovery capability, run rackd with host networking and bind the API to loopback behind your TLS reverse proxy:

services:
  rackd:
    image: ghcr.io/martinsuchenak/rackd:latest
    container_name: rackd
    restart: unless-stopped
    network_mode: host            # share the host network namespace
    volumes:
      - ./data:/data
    environment:
      - DATA_DIR=/data
      - LISTEN_ADDR=127.0.0.1:8080  # only the local proxy can reach the API
      - ENCRYPTION_KEY=${ENCRYPTION_KEY}
      - INITIAL_ADMIN_USERNAME=${INITIAL_ADMIN_USERNAME:-admin}
      - INITIAL_ADMIN_PASSWORD=${INITIAL_ADMIN_PASSWORD}

No ports: mapping is used (or needed) with host networking. Alternative without host networking: configure SNMP credentials — SNMP is UDP unicast and works from bridged containers, yielding hostnames, interfaces and MACs.

Nomad Deployment

The Nomad job file is available at deploy/nomad.hcl.

Prerequisites

  1. Configure host volume in Nomad client:
# nomad.hcl
client {
  host_volume "rackd-data" {
    path      = "/opt/nomad/rackd-data"
    read_only = false
  }
}
  1. Set Nomad variables:
nomad var put nomad/jobs/rackd \
  api_auth_token="your-secure-token" \
  mcp_auth_token="your-mcp-token"

Deploy

nomad job run deploy/nomad.hcl

Systemd Service

Binary Installation

# Download and install
curl -LO https://github.com/martinsuchenak/rackd/releases/latest/download/rackd-linux-amd64
sudo mv rackd-linux-amd64 /usr/local/bin/rackd
sudo chmod +x /usr/local/bin/rackd

# Create user and directories
sudo useradd -r -s /bin/false rackd
sudo mkdir -p /var/lib/rackd /etc/rackd
sudo chown rackd:rackd /var/lib/rackd

Service Configuration

Create /etc/systemd/system/rackd.service:

[Unit]
Description=Rackd IPAM and Device Inventory
After=network.target
Wants=network.target

[Service]
Type=simple
User=rackd
Group=rackd
ExecStart=/usr/local/bin/rackd server
Restart=always
RestartSec=5
Environment=DATA_DIR=/var/lib/rackd
Environment=LISTEN_ADDR=:8080
Environment=LOG_LEVEL=info
EnvironmentFile=-/etc/rackd/rackd.env

# Security
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/rackd

[Install]
WantedBy=multi-user.target

Create /etc/rackd/rackd.env:

ENCRYPTION_KEY=your-64-hex-char-key
INITIAL_ADMIN_USERNAME=admin
INITIAL_ADMIN_PASSWORD=your-secure-password

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable rackd
sudo systemctl start rackd

Reverse Proxy Setup

When running behind a reverse proxy, set TRUST_PROXY=true and TRUSTED_PROXIES to the proxy address (e.g. 127.0.0.1) so rackd honors forwarded headers only from that peer for rate limiting and audit logging, and bind LISTEN_ADDR to loopback so the API is only reachable through the proxy.

Nginx

Create /etc/nginx/sites-available/rackd:

server {
    listen 80;
    server_name rackd.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name rackd.example.com;

    ssl_certificate /etc/ssl/certs/rackd.crt;
    ssl_certificate_key /etc/ssl/private/rackd.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

Traefik

Create traefik.yml:

api:
  dashboard: true

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: [email protected]
      storage: acme.json
      httpChallenge:
        entryPoint: web

providers:
  docker:
    exposedByDefault: false

Update Docker Compose with Traefik labels:

services:
  rackd:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.rackd.rule=Host(`rackd.example.com`)"
      - "traefik.http.routers.rackd.entrypoints=websecure"
      - "traefik.http.routers.rackd.tls.certresolver=letsencrypt"

TLS/HTTPS

Let’s Encrypt with Certbot

# Install certbot
sudo apt install certbot python3-certbot-nginx

# Obtain certificate
sudo certbot --nginx -d rackd.example.com

# Auto-renewal
sudo crontab -e
# Add: 0 12 * * * /usr/bin/certbot renew --quiet

Self-Signed Certificate

# Generate certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout rackd.key -out rackd.crt \
  -subj "/CN=rackd.example.com"

# Install
sudo cp rackd.crt /etc/ssl/certs/
sudo cp rackd.key /etc/ssl/private/
sudo chmod 600 /etc/ssl/private/rackd.key

Production Considerations

Security

  • Use strong authentication tokens
  • Enable HTTPS in production
  • Restrict network access with firewall rules
  • Run with non-root user
  • Regular security updates

Performance

  • Allocate sufficient memory (minimum 256MB)
  • Use SSD storage for database
  • Monitor disk space usage
  • Configure log rotation

Backup Strategy

#!/bin/bash
# backup-rackd.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/rackd"
DATA_DIR="/var/lib/rackd"

mkdir -p $BACKUP_DIR
sqlite3 $DATA_DIR/rackd.db ".backup $BACKUP_DIR/rackd_$DATE.db"
gzip $BACKUP_DIR/rackd_$DATE.db

# Cleanup old backups (keep 30 days)
find $BACKUP_DIR -name "*.gz" -mtime +30 -delete

Log Management

Configure log rotation in /etc/logrotate.d/rackd:

/var/log/rackd/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 644 rackd rackd
    postrotate
        systemctl reload rackd
    endscript
}

Monitoring

Health Checks

Rackd provides a health check endpoint:

curl http://localhost:8080/api/datacenters

Prometheus Metrics

Add monitoring labels to Docker Compose:

services:
  rackd:
    labels:
      - "prometheus.io/scrape=true"
      - "prometheus.io/port=8080"
      - "prometheus.io/path=/metrics"

Basic Monitoring Script

#!/bin/bash
# monitor-rackd.sh
URL="http://localhost:8080/api/datacenters"
TIMEOUT=5

if curl -f -s --max-time $TIMEOUT $URL > /dev/null; then
    echo "Rackd is healthy"
    exit 0
else
    echo "Rackd health check failed"
    exit 1
fi

Uptime Monitoring

Configure external monitoring with services like:

  • Pingdom
  • UptimeRobot
  • StatusCake

Monitor these endpoints:

  • /api/datacenters - API health
  • / - Web UI availability

Troubleshooting

Common Issues

  1. Permission denied on data directory

    sudo chown -R rackd:rackd /var/lib/rackd
    
  2. Port already in use

    sudo netstat -tlnp | grep :8080
    
  3. Database locked

    # Check for stale processes
    ps aux | grep rackd
    

Logs

# Systemd logs
sudo journalctl -u rackd -f

# Docker logs
docker logs -f rackd

# Nomad logs
nomad alloc logs -f <alloc-id>