Self-hosting guide
Deploy DeviceSDK on your own server with Docker, configure a reverse proxy, TLS, backups, and multi-server LAN setups
DeviceSDK ships as a single Docker image that serves the API, WebSocket endpoint, and dashboard from one port. This guide covers a production-grade self-hosted setup: reverse proxy, HTTPS, backups, and multi-server LAN configurations.
Prerequisites
- A host running Docker (Linux recommended). Works on a home server, NUC, Raspberry Pi 4/5, VPS, or any VM.
- Ports 80 and 443 reachable from your clients (or just the LAN port if you skip TLS for a private network install).
- A domain name pointing at the host (required for HTTPS).
Quick start
# Create a data directory for the SQLite database and scripts
mkdir -p ~/devicesdk-data
docker run -d \
--name devicesdk \
--restart unless-stopped \
-p 8080:8080 \
-v ~/devicesdk-data:/data \
-e ALLOW_REGISTRATION=false \
-e SECURE_COOKIES=true \
ghcr.io/device-sdk/devicesdk:latest
Open http://localhost:8080 - the first visit creates the admin account. After that, ALLOW_REGISTRATION=false prevents further sign-ups.
Docker Compose (recommended)
Save this as docker-compose.yml and run docker compose up -d:
services:
devicesdk:
image: ghcr.io/device-sdk/devicesdk:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./data:/data
environment:
ALLOW_REGISTRATION: "false"
SECURE_COOKIES: "true"
Environment variables
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP port the server listens on |
DATA_DIR |
./data |
Root for SQLite DB, scripts, firmware |
ALLOW_REGISTRATION |
true |
Allow new account sign-ups |
SECURE_COOKIES |
false |
Set Secure flag on session cookies - must be true behind TLS |
TRUST_PROXY |
false |
Trust X-Forwarded-For headers - enable only behind a reverse proxy |
API_TOKEN_SECRET |
auto-generated | HMAC secret for token hashing. Auto-generated and persisted to DATA_DIR/.api-token-secret on first start; override for multi-instance or reproducible deployments |
MDNS_ENABLED |
true |
Advertise server over mDNS for device auto-discovery |
MDNS_HOSTNAME |
devicesdk |
mDNS short hostname (devices reach devicesdk.local) |
LOG_FILE |
DATA_DIR/server.log |
Server log path |
Reverse proxy and HTTPS/TLS
For LAN-only installs you can skip TLS, but for anything reachable from the internet you must terminate TLS at a reverse proxy.
Caddy (simplest - automatic TLS)
devicesdk.example.com {
reverse_proxy localhost:8080
}
Caddy auto-provisions and renews Let's Encrypt certificates. No other TLS config needed.
nginx
server {
listen 443 ssl;
server_name devicesdk.example.com;
ssl_certificate /etc/ssl/certs/devicesdk.crt;
ssl_certificate_key /etc/ssl/private/devicesdk.key;
# WebSocket upgrade for device connections
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_read_timeout 3600s;
}
}
server {
listen 80;
server_name devicesdk.example.com;
return 301 https://$host$request_uri;
}
After adding the reverse proxy, set TRUST_PROXY=true and SECURE_COOKIES=true in your container environment.
Let's Encrypt with Certbot
certbot certonly --standalone -d devicesdk.example.com
Then reference the generated files from your nginx/Apache config. Certbot renews certificates automatically via a systemd timer or cron job.
Backups
All persistent state lives in DATA_DIR (default ./data). A hot SQLite backup is safe to take while the server is running:
# Backup using SQLite's online backup API (safe while running)
sqlite3 ./data/devicesdk.sqlite ".backup /backups/devicesdk-$(date +%Y%m%d-%H%M%S).sqlite"
# Or stop the container and copy the entire data dir
docker stop devicesdk
cp -r ./data /backups/devicesdk-data-$(date +%Y%m%d)
docker start devicesdk
To restore, stop the container, replace ./data/devicesdk.sqlite with the backup, and restart.
Schedule regular backups with cron:
0 3 * * * sqlite3 /path/to/data/devicesdk.sqlite ".backup /backups/devicesdk-$(date +\%Y\%m\%d).sqlite"
Multi-server LAN considerations
You can run multiple DeviceSDK servers on the same LAN. Each server is independent - devices connect to exactly one server.
mDNS hostnames
By default each server advertises itself as devicesdk.local. To avoid conflicts, give each server a unique hostname:
environment:
MDNS_HOSTNAME: "devicesdk-lab" # → lab.local
Devices will discover the correct server at devicesdk-lab.local.
Shared network storage
If you mount DATA_DIR on a network share (NFS, SMB) shared by multiple servers, each server must have its own subdirectory and must not share the SQLite file. SQLite does not support concurrent writes from multiple processes across a network filesystem.
API_TOKEN_SECRET
HMAC token hashes are keyed with API_TOKEN_SECRET. If you run two servers, do not share the same secret - tokens issued by one server must not be accepted by the other. Each server auto-generates a unique secret and persists it under DATA_DIR/.api-token-secret.
Updating
docker compose pull
docker compose up -d
The server applies database migrations on startup automatically.
Firewall recommendations
| Port | Protocol | Purpose | Expose to |
|---|---|---|---|
| 8080 (or your proxy port) | TCP | API + dashboard + WS | LAN or internet (behind TLS) |
| 443 | TCP | HTTPS (reverse proxy) | Internet |
| 5353 | UDP | mDNS device discovery | LAN only |
Close port 8080 on the internet-facing interface if you use a reverse proxy on 443.