Deploy Burning Ash Protocol on Your Homelab in 15 Minutes

Deploy Burning Ash Protocol on Your Homelab in 15 Minutes
This tutorial walks you through deploying Burning Ash Protocol (BAP) on your homelab using Docker Compose. By the end, you will have a fully functional, self-hosted digital will system with HTTPS, accessible from the internet (or restricted to your local network, depending on your preference).
What you will have after completing this tutorial:
- BAP API running on your homelab server
- BAP web dashboard accessible via HTTPS
- Reverse proxy handling TLS termination
- Automatic database migrations
- A working admin account ready for configuration
Prerequisites:
- A Linux server (Debian, Ubuntu, or similar) with Docker and Docker Compose installed
- A domain name pointed at your server (if you want external access with HTTPS)
- Basic comfort with the command line
- 15 minutes
Step 1: Clone the Repository
Start by cloning the BAP repository to your server. If you prefer a specific release, check the releases page on GitHub and check out the corresponding tag.
git clone https://github.com/baprotocol/bap.git
cd bap
The repository contains three services: the Go API (api/), the Next.js web frontend (web/), and the documentation site (documentation/). For a homelab deployment, you need the API and the web frontend.
Step 2: Generate Secrets and Configure Environment
BAP requires two cryptographic secrets: a JWT secret for authentication tokens and a Master Key for encrypting Data Encryption Keys. Both must be 256-bit (32-byte) random values.
Generate them using OpenSSL:
openssl rand -hex 32
# Copy this output — it becomes your JWT_SECRET
openssl rand -hex 32
# Copy this output — it becomes your MASTER_KEY
Now create your environment file from the example:
cp .env.example .env
Open .env in your editor and configure the essential variables:
# Required secrets
JWT_SECRET=<your-generated-jwt-secret>
MASTER_KEY=<your-generated-master-key>
# Database — SQLite is fine for a homelab
DB_TYPE=sqlite
DATABASE_PATH=./data/bap.db
# Deploy mode — selfhosted disables billing and platform connectors
DEPLOY_MODE=selfhosted
# CORS — must match the URL where you access the web frontend
CORS_ORIGINS=https://bap.yourdomain.com
# API URL for the frontend to call
NEXT_PUBLIC_API_URL=https://bap-api.yourdomain.com/api
# Admin bootstrap — set a temporary secret to create the first admin account
ADMIN_BOOTSTRAP_SECRET=<a-temporary-strong-secret>
Important: Store your MASTER_KEY securely outside the server as well. If you lose it, all encrypted wills become permanently inaccessible. Write it down and store it in a fireproof safe alongside your other critical backups.
Step 3: Docker Compose Configuration
BAP includes a Docker Compose file for development. For a homelab production deployment, you may want to customize it. Here is a production-oriented configuration:
# docker-compose.yml
version: "3.8"
services:
api:
build:
context: ./api
dockerfile: Dockerfile
container_name: bap-api
restart: unless-stopped
env_file: .env
volumes:
- bap-data:/app/data
ports:
- "127.0.0.1:8080:8080"
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/api/health"]
interval: 30s
timeout: 10s
retries: 3
web:
build:
context: ./web
dockerfile: Dockerfile
container_name: bap-web
restart: unless-stopped
env_file: .env
ports:
- "127.0.0.1:3000:3000"
depends_on:
api:
condition: service_healthy
volumes:
bap-data:
driver: local
Note that both services bind to 127.0.0.1 only. This ensures they are not directly accessible from the network --- all external traffic goes through the reverse proxy.
Step 4: Set Up a Reverse Proxy
A reverse proxy serves two purposes: it terminates TLS (HTTPS) and routes requests to the correct service based on the domain name.
You have two good options: Caddy (simpler, automatic HTTPS) or Nginx (more configurable, widely documented).
Option A: Caddy (Recommended for Homelab)
Caddy automatically obtains and renews Let's Encrypt certificates. This is the simplest path to HTTPS.
Create a Caddyfile in your project root:
bap.yourdomain.com {
reverse_proxy localhost:3000
}
bap-api.yourdomain.com {
reverse_proxy localhost:8080
}
Add Caddy to your Docker Compose file:
caddy:
image: caddy:2-alpine
container_name: bap-caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-data:/data
- caddy-config:/config
depends_on:
- api
- web
Add the Caddy volumes to the volumes section:
volumes:
bap-data:
driver: local
caddy-data:
driver: local
caddy-config:
driver: local
That is it. Caddy handles certificate issuance, renewal, and HTTPS redirection automatically.
Option B: Nginx with Certbot
If you prefer Nginx, create an Nginx configuration file:
# /etc/nginx/sites-available/bap
server {
listen 80;
server_name bap.yourdomain.com bap-api.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name bap.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/bap.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/bap.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}
server {
listen 443 ssl http2;
server_name bap-api.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/bap-api.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/bap-api.yourdomain.com/privkey.pem;
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;
}
}
Obtain certificates with Certbot:
sudo certbot --nginx -d bap.yourdomain.com -d bap-api.yourdomain.com
Step 5: Configure DNS
Point your domain names to your server's IP address. If your homelab is behind a home router, you will need to set up port forwarding for ports 80 and 443.
For external access:
Create A records in your DNS provider:
bap.yourdomain.com A <your-public-ip>
bap-api.yourdomain.com A <your-public-ip>
Configure your router to forward ports 80 and 443 to your homelab server's local IP address.
For local-only access:
If you do not want your digital will accessible from the internet (a valid security choice), use local DNS resolution instead. Add entries to your local DNS server (Pi-hole, AdGuard Home, or similar):
bap.yourdomain.com A 192.168.1.x
bap-api.yourdomain.com A 192.168.1.x
For local-only HTTPS with Caddy, you can use Caddy's internal TLS feature:
bap.yourdomain.com {
tls internal
reverse_proxy localhost:3000
}
bap-api.yourdomain.com {
tls internal
reverse_proxy localhost:8080
}
This generates self-signed certificates. You will need to trust Caddy's root CA on your devices to avoid browser warnings.
Step 6: Start the Stack
Build and start all services:
docker compose up -d --build
Watch the logs to confirm everything starts correctly:
docker compose logs -f
You should see:
- The API service running migrations and starting on port 8080
- The web frontend building and starting on port 3000
- Caddy (if using it) obtaining TLS certificates
Once all services are healthy, open your browser and navigate to https://bap.yourdomain.com. You should see the BAP login page.
Step 7: Create the Admin Account
BAP uses a bootstrap endpoint to create the first super-admin account. This endpoint is protected by the ADMIN_BOOTSTRAP_SECRET you configured in Step 2.
curl -X POST https://bap-api.yourdomain.com/api/admin/bootstrap \
-H "Content-Type: application/json" \
-d '{
"email": "admin@yourdomain.com",
"password": "your-strong-admin-password",
"secret": "<your-ADMIN_BOOTSTRAP_SECRET>"
}'
After creating the admin account, remove or change the ADMIN_BOOTSTRAP_SECRET in your .env file and restart the API:
docker compose restart api
This prevents anyone else from creating admin accounts using the bootstrap endpoint.
Step 8: Verify the Deployment
Log in to the web dashboard at https://bap.yourdomain.com using your admin credentials. Verify that:
- You can log in successfully
- The dashboard loads without errors
- You can navigate to the will management section
- You can access the settings page
Create a test will to verify the full encryption pipeline works:
- Create a new will with a test document
- Add a test Survivor (use your own email or phone number)
- Configure liveness check parameters
- Verify the Survivor receives a notification
Step 9: Configure Notification Connectors
For the dead man's switch to function, BAP needs at least one notification channel configured. In self-hosted mode, you provide your own credentials (BYO connectors).
Email (SMTP)
The most essential connector. Configure your SMTP credentials in the dashboard under Settings > Connectors:
- SMTP Host: Your mail server (e.g.,
smtp.gmail.com,smtp.fastmail.com, or your own mail server) - SMTP Port: 587 (TLS) or 465 (SSL)
- Username: Your email address
- Password: An app-specific password (never your main email password)
If you run your own mail server, use that. If you use Gmail, generate an app-specific password in your Google Account security settings.
SMS (Twilio)
For SMS notifications, you need a Twilio account:
- Account SID: Found in your Twilio console
- Auth Token: Found in your Twilio console
- From Number: Your Twilio phone number
Telegram
For Telegram notifications, create a bot via @BotFather and configure the bot token in BAP.
Step 10: Backup Strategy
Your BAP deployment stores encrypted data that by definition cannot be recreated. A backup strategy is essential.
Database Backup
For SQLite, the database is a single file. Back it up regularly:
# Add to crontab: daily backup at 2 AM
0 2 * * * docker compose exec api sqlite3 /app/data/bap.db ".backup '/app/data/backup-$(date +\%Y\%m\%d).db'"
Copy backups to a separate location (a different physical drive, NAS, or encrypted cloud storage).
Master Key Backup
Your Master Key is the most critical secret. If it is lost, all encrypted wills are permanently inaccessible.
- Write it on paper and store it in a fireproof safe
- Store it in a separate password manager vault
- Consider splitting it using Shamir's Secret Sharing (yes, you can use the same technique for your own key)
Configuration Backup
Back up your .env file and Docker Compose configuration. Store them separately from the database backups.
Maintenance
Updates
When new BAP releases are available:
cd bap
git pull origin main
docker compose up -d --build
Database migrations run automatically at API startup. Check the logs after updating to confirm migrations completed successfully.
Monitoring
For a homelab, basic monitoring ensures you know if the service goes down:
- Use Uptime Kuma, Healthchecks.io, or similar to monitor the
/api/healthendpoint - Configure alerts so you know if the service is unreachable
- Check Docker logs periodically for errors
This is especially important for a dead man's switch: if the server is down, liveness checks are not being sent, and the switch cannot trigger.
Security Hardening
For a production homelab deployment, consider these additional security measures:
Firewall rules. Only expose ports 80 and 443. Block all other incoming traffic.
sudo ufw default deny incoming
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP (redirect to HTTPS)
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
Fail2ban. Protect against brute-force attacks on your reverse proxy and SSH.
Automatic updates. Enable unattended security updates for your OS.
Separate user. Run Docker as a non-root user. Do not run BAP services as root inside containers.
VPN access. If your BAP instance is local-only, access it via WireGuard or Tailscale from outside your network rather than exposing ports to the internet.
Troubleshooting
"Connection refused" when accessing the web interface:
Check that all containers are running with docker compose ps. Verify that your reverse proxy is running and correctly configured. Check that DNS is resolving to the correct IP address.
"CORS error" in the browser console:
Ensure CORS_ORIGINS in your .env file exactly matches the URL you use to access the frontend, including the protocol (https://) and port if non-standard.
"Unauthorized" errors when calling the API:
Verify that NEXT_PUBLIC_API_URL in your .env file is correct and accessible from your browser. This is a client-side setting --- the browser calls this URL directly, not the server.
Database migration errors:
Check the API logs with docker compose logs api. If a migration fails, the API will not start. Common causes include file permission issues on the data volume.
Conclusion
You now have a fully self-hosted Burning Ash Protocol instance running on your homelab. Your digital will data is encrypted with AES-256-GCM, protected by keys you control, and accessible only through your infrastructure. No third party can access, modify, or shut down your digital estate plan.
The next steps are to configure your actual will content, add your Survivors, set appropriate liveness check intervals, and test the full flow end-to-end with a test Survivor before considering your deployment production-ready.
Related Articles

Best Self-Hosted Dead Man's Switch Software (2026)
A comprehensive comparison of the best self-hosted dead man's switch tools in 2026, including Burning Ash Protocol, LastSignal, Seppuku, Posthumous, storopoli/dead-man-switch, and EmergencyWP.
Read Protocol
Digital Will for Developers: A Sysadmin's Guide
A practical guide for developers and sysadmins to organize SSH keys, API tokens, infrastructure secrets, CI/CD credentials, DNS management, and server access for digital estate planning.
Read Protocol
Building a Dead Man's Switch API: Architecture Decisions
A technical deep-dive into Burning Ash Protocol's Go API architecture: Chi router, GORM, scheduler design, liveness check polling, encryption layer, and the engineering tradeoffs behind each decision.
Read Protocol
Digital Estate Planning Checklist (Free Template)
A comprehensive digital estate planning checklist organized by category: accounts, cryptocurrency, documents, subscriptions, social media, and business assets. Includes a downloadable markdown template.
Read Protocol