Self-Hosting Binboi on a €5/month VPS
You don't need to rely on the hosted service. Binboi is fully open-source and self-hostable on any Linux machine with a public IP address. This guide gets the full stack running on a cheap VPS in under 20 minutes.
What You're Deploying
Binboi has four components:
| Component | Technology | Role | |---|---|---| | Relay server | Go | Accepts tunnel connections from the CLI, proxies public HTTP/HTTPS to the local client | | Control plane | Next.js | Web dashboard, user management, token issuance | | Database | PostgreSQL | User accounts, tokens, tunnel metadata | | Reverse proxy | Caddy | Wildcard TLS termination, HTTPS for the dashboard |
Everything runs in Docker and is wired together with docker compose.
Requirements
- A VPS with at least 512 MB RAM and 1 vCPU (Hetzner CX11, DigitalOcean Droplet, or equivalent)
- Ubuntu 22.04 or Debian 12
- Docker Engine + Docker Compose v2 installed
- A domain name you control (e.g.
example.com) - A Cloudflare account (for DNS-01 challenge TLS — any supported provider works)
DNS Setup
You need two DNS records pointing to your server's public IP:
A example.com → YOUR_SERVER_IP
A *.example.com → YOUR_SERVER_IP
The wildcard *.example.com record is what enables tunnel subdomains like username.example.com. Propagation typically takes 1–5 minutes on Cloudflare.
Server Setup
SSH into your VPS and clone the repository:
git clone https://github.com/miransas/binboi.git
cd binboi
Install Docker if it's not already present:
curl -fsSL https://get.docker.com | sh
Configure Environment
Copy the example environment file:
cp .env.example .env
Edit .env and set the required values:
# Domain
BINBOI_DOMAIN=example.com
# A random 64-character hex string — used to sign JWTs
JWT_SECRET=$(openssl rand -hex 32)
# Postgres credentials (change these)
POSTGRES_USER=binboi
POSTGRES_PASSWORD=changeme
POSTGRES_DB=binboi
# GitHub OAuth (create an app at github.com/settings/apps)
AUTH_GITHUB_ID=your_client_id
AUTH_GITHUB_SECRET=your_client_secret
AUTH_SECRET=$(openssl rand -hex 32)
# Cloudflare API token with Zone:DNS:Edit permission
CLOUDFLARE_API_TOKEN=your_token_here
The only values that are strictly required for tunnels to work are BINBOI_DOMAIN and JWT_SECRET. Everything else enables specific features (OAuth login, billing, etc.).
Start the Stack
docker compose up -d
This pulls the images, starts Postgres, runs database migrations, and brings up the relay server and control plane. First startup takes about 60 seconds while Docker pulls images.
Check that everything is running:
docker compose ps
You should see all four services in running state. If a service exits immediately, check its logs:
docker compose logs relay
Wildcard TLS with Caddy
Caddy is included in the compose file and handles TLS automatically. It uses the DNS-01 ACME challenge to obtain a wildcard certificate from Let's Encrypt — this is why you need a Cloudflare API token.
The Caddy configuration (in Caddyfile) looks roughly like this:
*.example.com, example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
@dashboard host example.com
handle @dashboard {
reverse_proxy web:3000
}
handle {
reverse_proxy relay:8080
}
}
Caddy will automatically renew the certificate before it expires. You don't need to manage certificates manually.
Test Your First Tunnel
On your local machine, install the CLI and point it at your self-hosted server:
# Set your server as the Binboi host
export BINBOI_API_URL=https://example.com
# Log in (this will open your dashboard in a browser)
binboi login
# Open a tunnel
binboi http 3000
If everything is working, you'll see a subdomain URL like https://sardor.example.com.
Production Checklist
Before inviting other users, work through this checklist:
- [ ] Change the default Postgres password in
.envand rundocker compose up -d --force-recreate postgres - [ ] Set up automatic backups — at minimum, a daily
pg_dumpto object storage - [ ] Restrict SSH access — disable password auth, use key-based auth only
- [ ] Configure a firewall — only ports 22 (SSH), 80 (HTTP), and 443 (HTTPS) should be public
- [ ] Set
AUTH_TRUST_HOST=truein your environment if login redirects fail - [ ] Monitor disk usage — request logs and Postgres data grow over time
- [ ] Pin Docker image versions in
docker-compose.ymlfor reproducible deployments
The full stack runs comfortably on a €5/month Hetzner CX11. For teams with heavy webhook traffic, consider moving Postgres to a managed database and increasing the relay server's memory limit.