Self-Hosting
zod-vault server is a single binary with SQLite storage. No external databases required.
Quick Start
Section titled “Quick Start”Docker
Section titled “Docker”docker run -d \ --name zod-vault \ -p 3000:3000 \ -e JWT_SECRET="$(openssl rand -hex 32)" \ -v vault-data:/app/data \ ghcr.io/nicodlz/zod-vault-serverDocker Compose
Section titled “Docker Compose”version: "3.8"
services: zod-vault: image: ghcr.io/nicodlz/zod-vault-server ports: - "3000:3000" environment: - JWT_SECRET=${JWT_SECRET} volumes: - vault-data:/app/data restart: unless-stopped
volumes: vault-data:Configuration
Section titled “Configuration”| Variable | Required | Default | Description |
|---|---|---|---|
JWT_SECRET | Yes | - | Secret for signing JWTs (32+ chars) |
JWT_ISSUER | No | zod-vault | JWT issuer claim |
JWT_ACCESS_EXPIRY | No | 15m | Access token lifetime |
JWT_REFRESH_EXPIRY | No | 7d | Refresh token lifetime |
DB_PATH | No | ./data/vault.db | SQLite database path |
PORT | No | 3000 | HTTP port |
Generating a JWT Secret
Section titled “Generating a JWT Secret”openssl rand -hex 32Platform Guides
Section titled “Platform Guides”Coolify
Section titled “Coolify”- Create new Application → Docker Image
- Image:
ghcr.io/nicodlz/zod-vault-server - Add environment variable:
JWT_SECRET - Add persistent storage:
/app/data - Deploy
Railway
Section titled “Railway”- New Project → Deploy from GitHub
- Select
packages/serveras root - Add
JWT_SECRETenvironment variable - Deploy
Fly.io
Section titled “Fly.io”app = "my-zod-vault"
[build] dockerfile = "packages/server/Dockerfile"
[env] PORT = "8080"
[mounts] source = "vault_data" destination = "/app/data"fly secrets set JWT_SECRET="$(openssl rand -hex 32)"fly deployVPS (Ubuntu)
Section titled “VPS (Ubuntu)”# Install Node.jscurl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -sudo apt-get install -y nodejs
# Clone and buildgit clone https://github.com/nicodlz/zod-vault.gitcd zod-vault/packages/servernpm install && npm run build
# Create systemd servicesudo tee /etc/systemd/system/zod-vault.service << EOF[Unit]Description=zod-vault serverAfter=network.target
[Service]Type=simpleUser=www-dataWorkingDirectory=/opt/zod-vault/packages/serverEnvironment=JWT_SECRET=your-secret-hereExecStart=/usr/bin/node dist/index.jsRestart=on-failure
[Install]WantedBy=multi-user.targetEOF
sudo systemctl enable --now zod-vaultReverse Proxy
Section titled “Reverse Proxy”server { listen 443 ssl http2; server_name vault.example.com;
ssl_certificate /etc/letsencrypt/live/vault.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/vault.example.com/privkey.pem;
location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; 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; }}vault.example.com { reverse_proxy localhost:3000}Backups
Section titled “Backups”SQLite database is a single file:
# While server is running (safe)sqlite3 /app/data/vault.db ".backup /backups/vault-$(date +%Y%m%d).db"Health Check
Section titled “Health Check”curl https://vault.example.com/health# => {"status":"ok","timestamp":1234567890}Security Checklist
Section titled “Security Checklist”- HTTPS in production
- Strong JWT_SECRET (32+ random bytes)
- Run as non-root user
- Firewall (only expose 443)
- Regular backups
- Keep server updated