Deploying Boltstore in Production
A step-by-step guide for each installation method: binary, npm, or Docker.
Choose Your Installation
| Method | Good for | Runtime needed |
|---|---|---|
| Binary | VPS, bare metal, no dependencies | None (self-contained) |
| npm | Already have Bun on the server | Bun |
| Docker | Containerized infrastructure | Docker |
Method 1: Binary (Shell Script or Manual)
Install via shell script
curl -fsSL https://boltstore.dev/install.sh | shThe script detects your OS and architecture, downloads the correct binary from GitHub Releases, and installs it to /usr/local/bin/boltstore. For a specific version:
curl -fsSL https://boltstore.dev/install.sh | sh -s -- --version v1.0.0Install manually
Download from GitHub Releases:
# macOS Apple Silicon
curl -fsSL -o boltstore https://github.com/boltstore/boltstore/releases/latest/download/boltstore-darwin-arm64
chmod +x boltstore
sudo mv boltstore /usr/local/bin/
# Linux x86_64
curl -fsSL -o boltstore https://github.com/boltstore/boltstore/releases/latest/download/boltstore-linux-x64
chmod +x boltstore
sudo mv boltstore /usr/local/bin/Where things are
| Item | Default location |
|---|---|
| Binary | /usr/local/bin/boltstore |
| Data directory | ./data (relative to working directory) — configure with DATABASE_PATH |
| Config file | ./boltstore.yaml or ./boltstore.json |
Set a fixed data directory and system user for production:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin boltstore
sudo mkdir -p /var/lib/boltstore
sudo chown boltstore:boltstore /var/lib/boltstoreFor testing without systemd, skip the user and just:
sudo mkdir -p /var/lib/boltstore
sudo chown $USER:$USER /var/lib/boltstore
cd /var/lib/boltstoreConfigure
Create boltstore.yaml in your data directory:
port: 8080
databasePath: /var/lib/boltstore
logLevel: info
adminKey: "your-strong-random-key"
maxBodySize: 10
requestTimeoutMs: 30000
# Restrict CORS in production
corsOrigins:
- "https://myapp.com"
# Trust your reverse proxy
trustedProxies:
- "127.0.0.1"Or use environment variables:
export PORT=8080
export BOLTSTORE_ADMIN_KEY="your-strong-random-key"
export DATABASE_PATH="/var/lib/boltstore"Generate a strong admin key:
openssl rand -base64 48 | tr -d '\n' && echoThe admin key is single-use. Create your first admin account via the dashboard or
POST /api/admin/setupimmediately after starting. Once consumed, additional admins require an existing admin session.
Run it
Foreground (test):
cd /var/lib/boltstore
boltstore serveDaemon with systemd — see Systemd Service below.
Method 2: npm
Install
Requires Bun on the server:
curl -fsSL https://bun.sh/install | bashThen install Boltstore globally:
npm install -g boltstoreVerify:
boltstore --helpWhere things are
| Item | Default location |
|---|---|
| Command | Global npm bin ($(npm root -g)/../bin/boltstore) |
| Data directory | ./data (configure with DATABASE_PATH) |
| Config | Same as binary — boltstore.yaml or env vars |
Configure and run
Same as Method 1. Create /var/lib/boltstore, set up boltstore.yaml, and run:
cd /var/lib/boltstore
boltstore serveUse systemd to daemonize — see Systemd Service below.
Method 3: Docker (build from source)
Boltstore ships with a Dockerfile and docker-compose.yml. Clone the repo, build the image, and run it.
git clone https://github.com/boltstore/boltstore.git
cd boltstore
docker compose up -dThe shipped docker-compose.yml is production-ready out of the box — it handles port binding, volume persistence, health checks, and restart policies. You only need to set the admin key:
BOLTSTORE_ADMIN_KEY="your-key" docker compose up -dCustomizing
Override defaults with environment variables in docker-compose.yml or pass them inline:
BOLTSTORE_ADMIN_KEY="your-key" \
CORS_ORIGINS="https://myapp.com" \
docker compose up -dAvailable env vars: PORT, DATABASE_PATH, LOG_LEVEL, BOLTSTORE_ADMIN_KEY, CORS_ORIGINS, CORS_METHODS, CORS_HEADERS, TRUSTED_PROXIES.
Where things are
| Item | Location |
|---|---|
| Data | Docker volume boltstore-data → /app/data in container |
| Config | Environment variables |
| Port | Binds to 8080 — place behind a reverse proxy (see below) |
Systemd Service
For binary and npm installations only. Docker handles daemonizing via docker compose up -d.
Create /etc/systemd/system/boltstore.service:
[Unit]
Description=Boltstore — SQLite Database-as-a-Service
After=network.target
[Service]
Type=simple
User=boltstore
Group=boltstore
WorkingDirectory=/var/lib/boltstore
ExecStart=/usr/local/bin/boltstore serve
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/boltstore
PrivateTmp=yes
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable boltstore --now
sudo systemctl status boltstoreReverse Proxy
Boltstore speaks plain HTTP. Always place it behind a reverse proxy for HTTPS.
Caddy
Install Caddy on your server:
# Debian / Ubuntu
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/deb.debian.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddyCreate /etc/caddy/Caddyfile:
api.myapp.com {
reverse_proxy localhost:8080
}Start it:
sudo systemctl enable caddy --nowCaddy auto-provisions Let's Encrypt TLS certificates.
nginx
Install nginx:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d api.myapp.comEdit /etc/nginx/sites-available/boltstore:
server {
listen 443 ssl http2;
server_name api.myapp.com;
ssl_certificate /etc/letsencrypt/live/api.myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.myapp.com/privkey.pem;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
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;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
client_max_body_size 100m;
}
}Enable and reload:
sudo ln -s /etc/nginx/sites-available/boltstore /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxDocker
The shipped docker-compose.yml binds boltstore to port 8080. Point your host-level Caddy or nginx reverse proxy at localhost:8080 — same config as above.
Rate Limiting
Boltstore has built-in rate limiting for auth endpoints only:
| Endpoint | Limit |
|---|---|
| Login / Setup | 5 attempts per 15 minutes per IP (always on) |
| API key verification | Disabled by default — configurable via env var |
Data endpoints (records, tables, query) are intentionally unthrottled. Boltstore is a server-to-server DBaaS — API keys are issued to developers, not end users. Throttling data operations would harm legitimate backend workloads.
API key rate limiting
API keys are 48-char random strings — brute-forcing is mathematically infeasible. Rate limiting API key verification is disabled by default. If you want to enable it (e.g., to limit misconfigured clients from flooding your server), set the env var:
BOLTSTORE_API_KEY_RATE_LIMIT=100This limits failed API key lookups to 100 per minute per IP per database. Set to 0 or leave unset to disable.
Reverse proxy rate limiting (optional)
If you want rate limiting on data endpoints, add it at the reverse proxy level:
nginx:
# In http block
limit_req_zone $binary_remote_addr zone=boltstore_data:10m rate=600r/m;
# In server block
location /api/databases/ {
limit_req zone=boltstore_data burst=100 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:8080;
# ... rest of proxy settings
}Caddy:
api.myapp.com {
rate_limit {
zone dynamic {
key {remote_host}
events 600
window 1m
}
}
reverse_proxy localhost:8080
}Backups
SQLite databases using WAL mode can be copied safely while the server is running.
Option A: Simple file copy (cron)
#!/bin/bash
# Save as /etc/cron.daily/boltstore-backup
BACKUP_DIR="/backups/boltstore/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
cp /var/lib/boltstore/*.db "$BACKUP_DIR/"
# Keep only the last 7 days
find /backups/boltstore -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;sudo chmod +x /etc/cron.daily/boltstore-backupOption B: sqlite3 .backup (zero-downtime)
#!/bin/bash
# Save as /etc/cron.daily/boltstore-backup
BACKUP_DIR="/backups/boltstore/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
for db in /var/lib/boltstore/*.db; do
name=$(basename "$db" .db)
sqlite3 "$db" ".backup $BACKUP_DIR/$name-$(date +%H%M).db"
done
find /backups/boltstore -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;For Docker, run the backup from the host targeting the volume mount, or use docker exec:
docker exec boltstore sh -c 'sqlite3 /app/data/myapp.db ".backup /tmp/backup.db"'
docker cp boltstore:/tmp/backup.db ./myapp-$(date +%Y-%m-%d).dbMonitoring
Health check
curl -s https://api.myapp.com/api/health | jq
# { "status": "ok", "version": "1.0.0", "databases": 5 }Logs
# systemd (binary and npm)
journalctl -u boltstore -f --output=cat
# Docker
docker logs -f boltstoreKey metrics to watch
| Metric | How |
|---|---|
| Disk space | df -h /var/lib/boltstore |
| Database count | /api/health |
| Memory usage | htop or docker stats |
| Response time | nginx/Caddy access logs |
Security Checklist
| Step | Notes |
|---|---|
☐ Generate a strong adminKey | openssl rand -base64 48 |
| ☐ Create first admin account immediately | POST /api/admin/setup via dashboard |
☐ Set CORS_ORIGINS to your domain | Never use * in production |
☐ Configure TRUSTED_PROXIES | Your reverse proxy IP(s) |
| ☐ Run as non-root user | boltstore system user |
| ☐ Restrict data dir permissions | chmod 700 /var/lib/boltstore |
| ☐ Place behind HTTPS reverse proxy | Caddy or nginx with Let's Encrypt |
| ☐ Set up daily backups | cron + cp or sqlite3 .backup |
| ☐ Monitor disk usage | Alert at 80% |
| ☐ Restrict firewall | Only expose proxy ports 80/443, not 8080 |
Upgrade
Binary
# Stop the service
sudo systemctl stop boltstore
# Download and install the new version
curl -fsSL https://boltstore.dev/install.sh | sh
# Restart
sudo systemctl start boltstorenpm
sudo systemctl stop boltstore
npm update -g boltstore
sudo systemctl start boltstoreDocker
cd /path/to/boltstore
git pull origin main
docker compose up -d --buildAlways check the changelog for breaking changes between versions.
Troubleshooting
Permission errors ("attempt to write a readonly database" / "INTERNAL_ERROR")
The data directory is owned by the wrong user. After reinstalling or copying files, fix permissions:
sudo chown -R boltstore:boltstore /var/lib/boltstore
sudo systemctl restart boltstore::ffff:127.0.0.1 in activity logs (Cloudflare users)
Two steps to show real client IPs:
- Add Cloudflare's IP ranges to
trustedProxiesinboltstore.yamlso Boltstore trusts thecf-connecting-ipheader:
trustedProxies:
- "127.0.0.1"
- "::1"
- "173.245.48.0/20"
- "103.21.244.0/22"
- "103.22.200.0/22"
- "103.31.4.0/22"
- "141.101.64.0/18"
- "108.162.192.0/18"
- "190.93.240.0/20"
- "188.114.96.0/20"
- "197.234.240.0/22"
- "198.41.128.0/17"
- "162.158.0.0/15"
- "104.16.0.0/13"
- "104.24.0.0/14"
- "172.64.0.0/13"
- "131.0.72.0/22"
- "2400:cb00::/32"
- "2606:4700::/32"
- "2803:f800::/32"
- "2405:b500::/32"
- "2405:8100::/32"
- "2a06:98c0::/29"
- "2c0f:f248::/32"- Boltstore automatically strips the
::ffff:prefix from IPv4-mapped addresses, so::ffff:127.0.0.1becomes127.0.0.1and matches your trusted list.
Dashboard returns "not built" after reinstall
The admin dashboard ships as admin-dist.tar.gz alongside the binary. The install script extracts it to /usr/local/bin/admin/dist/. If missing, reinstall:
curl -fsSL https://boltstore.dev/install.sh | shFonts don't load on the dashboard
The CSP only allows fonts from fonts.bunny.net. If you modified the admin template to use Google Fonts, revert to bunny.net or update the CSP in the server source.
systemd fails with "Failed at step USER spawning"
The boltstore system user hasn't been created:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin boltstore
sudo chown -R boltstore:boltstore /var/lib/boltstore
sudo systemctl restart boltstore