Bare Metal — Systemd (No Docker)¶
This guide deploys Dreadnought directly on a Linux host using systemd services — no Docker required. Use this when: - Docker is not available on your system - You prefer not to use containers - You need to integrate with an existing Python/Node process supervisor
This is the most complex deployment method. If Docker is available, consider using Docker Compose instead.
Prerequisites¶
- Ubuntu 22.04 / Debian 12 (or similar Linux with systemd)
- Python 3.12
- Node.js 18+
sudoaccess
Step 1 — Install System Dependencies¶
sudo apt update
sudo apt install -y \
python3.12 \
python3.12-venv \
python3-pip \
nodejs \
npm \
sqlite3 \
git
Verify versions:
python3.12 --version # Should be 3.12.x
node --version # Should be 18.x or higher
npm --version
Installing Node.js 18+ on Ubuntu (if the default is too old):
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
Step 2 — Create a Dedicated User and Directories¶
Run all services under a dedicated non-root user for security:
# Create dreadnought system user (no login shell, no home directory prompt)
sudo useradd -r -s /bin/false -d /opt/dreadnought dreadnought
# Create application directories
sudo mkdir -p /opt/dreadnought/backend
sudo mkdir -p /opt/dreadnought/frontend
# Create data directory (SQLite database lives here)
sudo mkdir -p /var/lib/dreadnought
sudo chown dreadnought:dreadnought /var/lib/dreadnought
sudo chmod 755 /var/lib/dreadnought
Step 3 — Clone and Install the Application¶
# Clone into a temporary location first
git clone https://github.com/dreadnought-0/Dreadnought-DDNS.git /tmp/dreadnought-src
# Copy backend files
sudo cp -r /tmp/dreadnought-src/backend/* /opt/dreadnought/backend/
sudo chown -R dreadnought:dreadnought /opt/dreadnought/backend
# Copy frontend files
sudo cp -r /tmp/dreadnought-src/frontend/* /opt/dreadnought/frontend/
sudo chown -R dreadnought:dreadnought /opt/dreadnought/frontend
# Clean up
rm -rf /tmp/dreadnought-src
Step 4 — Install Python Dependencies¶
# Create Python virtual environment
sudo -u dreadnought python3.12 -m venv /opt/dreadnought/backend/venv
# Install dependencies into the venv
sudo -u dreadnought /opt/dreadnought/backend/venv/bin/pip install \
--no-cache-dir \
-r /opt/dreadnought/backend/requirements.txt
Step 5 — Build the Frontend¶
# Install Node dependencies
sudo -u dreadnought npm install --prefix /opt/dreadnought/frontend
# Build the Next.js app (creates .next/standalone output)
sudo -u dreadnought npm run build --prefix /opt/dreadnought/frontend
The build creates a standalone server at /opt/dreadnought/frontend/.next/standalone/server.js.
Step 6 — Create the Environment File¶
sudo nano /etc/dreadnought.env
Add your configuration:
# Cloudflare
CF_API_TOKEN=your_cloudflare_api_token_here
# Admin credentials
ADMIN_EMAIL=you@example.com
ADMIN_PASSWORD=a-strong-password
# Session security — generate with: openssl rand -hex 32
SECRET_KEY=paste-your-64-char-hex-key-here
# Sync settings
POLL_INTERVAL_SECONDS=300
IPV6_ENABLED=false
# Notifications (optional)
DISCORD_WEBHOOK_URL=
# Database (points to the data directory we created)
DATABASE_URL=sqlite:////var/lib/dreadnought/ddns.db
# Timezone
TZ=America/New_York
Secure the file — it contains sensitive values:
sudo chmod 600 /etc/dreadnought.env
sudo chown root:dreadnought /etc/dreadnought.env
Step 7 — Create Systemd Service Files¶
You need three service files: one for the API, one for the worker, and one for the frontend.
API Service¶
sudo nano /etc/systemd/system/dreadnought-api.service
[Unit]
Description=Dreadnought DDNS API
Documentation=https://github.com/dreadnought-0/Dreadnought-DDNS
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=dreadnought
Group=dreadnought
WorkingDirectory=/opt/dreadnought/backend
EnvironmentFile=/etc/dreadnought.env
ExecStart=/opt/dreadnought/backend/venv/bin/uvicorn \
main:app \
--host 127.0.0.1 \
--port 8000
Restart=on-failure
RestartSec=10
StartLimitInterval=60
StartLimitBurst=3
# Security hardening
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/dreadnought
CapabilityBoundingSet=
[Install]
WantedBy=multi-user.target
Worker Service¶
sudo nano /etc/systemd/system/dreadnought-worker.service
[Unit]
Description=Dreadnought DDNS Worker
Documentation=https://github.com/dreadnought-0/Dreadnought-DDNS
After=network-online.target dreadnought-api.service
Wants=network-online.target
Requires=dreadnought-api.service
[Service]
Type=exec
User=dreadnought
Group=dreadnought
WorkingDirectory=/opt/dreadnought/backend
EnvironmentFile=/etc/dreadnought.env
ExecStart=/opt/dreadnought/backend/venv/bin/python worker.py
Restart=on-failure
RestartSec=10
StartLimitInterval=60
StartLimitBurst=3
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/dreadnought
CapabilityBoundingSet=
[Install]
WantedBy=multi-user.target
Frontend Service¶
sudo nano /etc/systemd/system/dreadnought-web.service
[Unit]
Description=Dreadnought DDNS Frontend
Documentation=https://github.com/dreadnought-0/Dreadnought-DDNS
After=network-online.target dreadnought-api.service
Wants=network-online.target
[Service]
Type=exec
User=dreadnought
Group=dreadnought
WorkingDirectory=/opt/dreadnought/frontend/.next/standalone
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=HOSTNAME=127.0.0.1
Environment=NEXT_PUBLIC_API_URL=https://ddns-api.yourdomain.com
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=10
StartLimitInterval=60
StartLimitBurst=3
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
CapabilityBoundingSet=
[Install]
WantedBy=multi-user.target
Step 8 — Enable and Start Services¶
# Reload systemd to pick up new service files
sudo systemctl daemon-reload
# Enable services to start at boot
sudo systemctl enable dreadnought-api
sudo systemctl enable dreadnought-worker
sudo systemctl enable dreadnought-web
# Start services
sudo systemctl start dreadnought-api
sudo systemctl start dreadnought-worker
sudo systemctl start dreadnought-web
# Check status of all three
sudo systemctl status dreadnought-api dreadnought-worker dreadnought-web
All three should show active (running).
Step 9 — Set Up a Reverse Proxy¶
Since the API binds to 127.0.0.1:8000 and the frontend to 127.0.0.1:3000, you need a reverse proxy to expose them publicly. Choose one:
Managing Services¶
# View logs (live)
sudo journalctl -u dreadnought-api -f
sudo journalctl -u dreadnought-worker -f
sudo journalctl -u dreadnought-web -f
# View recent logs (last 100 lines)
sudo journalctl -u dreadnought-api -n 100
# Restart a service
sudo systemctl restart dreadnought-api
# Stop all
sudo systemctl stop dreadnought-api dreadnought-worker dreadnought-web
# Start all
sudo systemctl start dreadnought-api dreadnought-worker dreadnought-web
Updating (Systemd)¶
# 1. Stop all services
sudo systemctl stop dreadnought-api dreadnought-worker dreadnought-web
# 2. Pull latest code
cd /tmp
rm -rf dreadnought-src
git clone https://github.com/dreadnought-0/Dreadnought-DDNS.git dreadnought-src
# 3. Update backend files
sudo cp -r /tmp/dreadnought-src/backend/* /opt/dreadnought/backend/
sudo chown -R dreadnought:dreadnought /opt/dreadnought/backend
# 4. Update Python dependencies
sudo -u dreadnought /opt/dreadnought/backend/venv/bin/pip install \
--no-cache-dir \
-r /opt/dreadnought/backend/requirements.txt
# 5. Update frontend files
sudo cp -r /tmp/dreadnought-src/frontend/* /opt/dreadnought/frontend/
sudo chown -R dreadnought:dreadnought /opt/dreadnought/frontend
# 6. Rebuild frontend
sudo -u dreadnought npm install --prefix /opt/dreadnought/frontend
sudo -u dreadnought npm run build --prefix /opt/dreadnought/frontend
# 7. Restart services
sudo systemctl start dreadnought-api dreadnought-worker dreadnought-web
# 8. Verify
sudo systemctl status dreadnought-api dreadnought-worker dreadnought-web
Note: The database at
/var/lib/dreadnought/ddns.dbis never touched during an update. Your data is preserved.
Backup¶
# Single file backup
sudo -u dreadnought cp /var/lib/dreadnought/ddns.db \
/var/lib/dreadnought/ddns_$(date +%Y%m%d_%H%M%S).db
# Automated daily backup via cron
sudo crontab -u dreadnought -e
# Add:
0 2 * * * cp /var/lib/dreadnought/ddns.db /var/backups/ddns_$(date +\%Y\%m\%d).db
Troubleshooting Systemd Deployments¶
"Module not found" or ImportError¶
The Python venv path might be wrong, or dependencies aren't installed:
sudo -u dreadnought /opt/dreadnought/backend/venv/bin/python -c "import fastapi; print('OK')"
If it fails:
sudo -u dreadnought /opt/dreadnought/backend/venv/bin/pip install -r /opt/dreadnought/backend/requirements.txt
"Cannot open database" error¶
# Check permissions
ls -la /var/lib/dreadnought/
sudo chown dreadnought:dreadnought /var/lib/dreadnought
sudo chmod 755 /var/lib/dreadnought
Frontend shows blank page or JS errors¶
The NEXT_PUBLIC_API_URL in the frontend service file may be wrong. Update it to match your actual API URL, then rebuild:
sudo nano /etc/systemd/system/dreadnought-web.service
# Update NEXT_PUBLIC_API_URL
sudo -u dreadnought npm run build --prefix /opt/dreadnought/frontend
sudo systemctl daemon-reload
sudo systemctl restart dreadnought-web
Service exits immediately¶
Check the logs:
sudo journalctl -u dreadnought-api --since "5 min ago"
Common causes:
- Missing or incorrect values in /etc/dreadnought.env
- Python version mismatch (needs 3.12)
- File permission issues