Portainer Deployment¶
Portainer is a web-based Docker management UI. If you're already running Portainer to manage your Docker environment, you can deploy Dreadnought as a Stack directly from the Portainer UI.
Prerequisites¶
- Portainer installed and running (Community Edition is free)
- Docker running on the same host
- Access to the Portainer web UI
- A Cloudflare API token — see Cloudflare Setup
Method 1 — Deploy via Git Repository (Recommended)¶
This method keeps the stack in sync with the GitHub repository.
Step 1 — Create a New Stack¶
- Log in to your Portainer instance
- Go to Stacks → Add Stack
- Give it a name:
dreadnought-ddns - Select Repository as the build method
Step 2 — Configure the Repository¶
- Repository URL:
https://github.com/dreadnought-0/Dreadnought-DDNS - Repository reference:
refs/heads/main - Compose path:
docker-compose.yml
Leave Authentication unchecked (the repo is public).
Optional — Enable automatic updates: - Check Automatic updates - Set polling interval (e.g. every 5 minutes) - Portainer will re-pull and redeploy if the repository changes
Step 3 — Set Environment Variables¶
Scroll down to the Environment variables section. Add each variable:
| Name | Value |
|---|---|
CF_API_TOKEN |
Your Cloudflare API token |
ADMIN_EMAIL |
Your login email |
ADMIN_PASSWORD |
A strong password |
SECRET_KEY |
Run openssl rand -hex 32 and paste the result |
POLL_INTERVAL_SECONDS |
300 |
IPV6_ENABLED |
false |
DISCORD_WEBHOOK_URL |
(leave blank or enter webhook URL) |
TZ |
e.g. America/New_York |
Step 4 — Deploy the Stack¶
Click Deploy the stack. Portainer will: 1. Pull the repository 2. Build all three images 3. Start the containers
Build time: 2–5 minutes. Watch progress in the Portainer interface.
Step 5 — Prepare the Data Directory¶
Before containers start successfully, the ./data directory needs to exist with write permissions. In Portainer's terminal or on the host via SSH:
# On the host, in the directory where Portainer stored the stack
# Portainer usually stores stacks in /data/compose/<id>/
ls /data/compose/
# Find the dreadnought stack directory and create ./data inside it
mkdir -p /data/compose/<stack-id>/data
chmod 777 /data/compose/<stack-id>/data
Or click on the container in Portainer → Console → run:
mkdir -p /data && chmod 777 /data
Tip: If you're not sure where Portainer stores the stack files, SSH into the host and run
docker inspect dreadnought-ddns-api-1and look for the volume mount source path.
Method 2 — Deploy via Web Editor (Paste docker-compose.yml)¶
This method lets you paste and customize the compose file directly in Portainer.
Step 1 — Create a New Stack¶
- Go to Stacks → Add Stack
- Name:
dreadnought-ddns - Select Web editor
Step 2 — Paste the Compose File¶
Copy the contents of docker-compose.yml from the repository and paste it into the editor. Then modify the web service's NEXT_PUBLIC_API_URL and other environment variables inline:
services:
api:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "8081:8000"
volumes:
- ./data:/data
environment:
- DATABASE_URL=sqlite:////data/ddns.db
- CF_API_TOKEN=your_token_here
- ADMIN_EMAIL=you@example.com
- ADMIN_PASSWORD=your_password
- SECRET_KEY=your_secret_key
- POLL_INTERVAL_SECONDS=300
- IPV6_ENABLED=false
- DISCORD_WEBHOOK_URL=
- TZ=America/New_York
restart: unless-stopped
worker:
build:
context: ./backend
dockerfile: Dockerfile.worker
volumes:
- ./data:/data
environment:
- DATABASE_URL=sqlite:////data/ddns.db
- CF_API_TOKEN=your_token_here
- POLL_INTERVAL_SECONDS=300
- IPV6_ENABLED=false
- DISCORD_WEBHOOK_URL=
- TZ=America/New_York
restart: unless-stopped
web:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "8082:3000"
environment:
- NEXT_PUBLIC_API_URL=http://your-server-ip:8081
- NODE_ENV=production
depends_on:
- api
restart: unless-stopped
Note: When using the web editor,
build:withcontext:paths refers to relative paths on the Docker host. For this to work, Portainer needs the source code on the host. Consider using the Repository method above instead, or pre-build and push images to a registry.
Step 3 — Deploy¶
Click Deploy the stack.
Method 3 — Use Pre-Built Images¶
If you've built and pushed images to a registry (see Manual Dockerfile Build), configure the stack to use those images:
services:
api:
image: yourusername/dreadnought-api:latest
ports:
- "8081:8000"
volumes:
- dreadnought-data:/data
environment:
- DATABASE_URL=sqlite:////data/ddns.db
- CF_API_TOKEN=your_token_here
- ADMIN_EMAIL=you@example.com
- ADMIN_PASSWORD=your_password
- SECRET_KEY=your_secret_key
- POLL_INTERVAL_SECONDS=300
- IPV6_ENABLED=false
- DISCORD_WEBHOOK_URL=
- TZ=America/New_York
restart: unless-stopped
worker:
image: yourusername/dreadnought-worker:latest
volumes:
- dreadnought-data:/data
environment:
- DATABASE_URL=sqlite:////data/ddns.db
- CF_API_TOKEN=your_token_here
- POLL_INTERVAL_SECONDS=300
- IPV6_ENABLED=false
- DISCORD_WEBHOOK_URL=
- TZ=America/New_York
restart: unless-stopped
web:
image: yourusername/dreadnought-web:latest
ports:
- "8082:3000"
environment:
- NEXT_PUBLIC_API_URL=http://your-server-ip:8081
- NODE_ENV=production
depends_on:
- api
restart: unless-stopped
volumes:
dreadnought-data:
This uses a named Docker volume (dreadnought-data) instead of a host directory — Portainer manages it automatically and permissions are handled by Docker.
Accessing the Dashboard¶
Once running, open:
http://your-server-ip:8082
Log in with your ADMIN_EMAIL and ADMIN_PASSWORD.
Managing the Stack in Portainer¶
| Action | How |
|---|---|
| View container logs | Stacks → dreadnought-ddns → Click service → Logs |
| Restart a service | Stacks → dreadnought-ddns → Click service → Restart |
| Stop all | Stacks → dreadnought-ddns → Stop |
| Update (pull new images) | Stacks → dreadnought-ddns → Pull and redeploy |
| View resource usage | Containers → select container → Stats |
Adding HTTPS¶
Portainer doesn't manage TLS by itself. Options:
- Use Portainer with Traefik — many Portainer setups already include Traefik. Add Traefik labels to the stack services (see Traefik guide).
- Use Nginx on the same host — see Nginx guide.
- Use Caddy on the same host — see Caddy guide.
Troubleshooting¶
Containers fail to start with database error¶
sqlite3.OperationalError: unable to open database file
The ./data directory doesn't exist or isn't writable. See Step 5 in Method 1 above to create and permission it.
Build fails in Portainer¶
- Check the build logs in Portainer (Stacks → your stack → Logs during build)
- Make sure the repository source is configured correctly
- On low-memory systems, the Next.js build may fail — see the Raspberry Pi guide for swap tips
Environment variables not taking effect¶
- After changing variables, click Update the stack in Portainer
- For
NEXT_PUBLIC_API_URL, a full rebuild is required (not just a restart) since it's baked into the frontend at build time