bindler
v2.1.0
Published
CLI for managing multiple projects behind Cloudflare Tunnel with Nginx and PM2
Downloads
1,699
Maintainers
Readme
bindler
cli for managing multiple projects behind cloudflare tunnel with nginx and pm2.
install
npm install -g bindlerupdate to latest
npm update -g bindleryou'll also need:
- node.js 18+
- nginx -
brew install nginx(mac) orapt install nginx(linux) - pm2 -
npm install -g pm2 - cloudflared (optional) -
brew install cloudflaredor see https://pkg.cloudflare.com
run bindler setup to install missing dependencies automatically.
quick start
bindler init # setup wizard
bindler new # add a project
sudo bindler apply # apply nginx configusage
# check your system
bindler doctor
# create a project (interactive)
bindler new
# or with flags
bindler new --name mysite --hostname mysite.local --local
bindler new --name api --type npm --hostname api.example.com --start "npm start"
# apply nginx config
sudo bindler apply
# start npm apps
bindler start myapp
# check status
bindler statuscommands
projects
| command | description |
|---------|-------------|
| new | create and register a project |
| list | list all projects (--json for scripting) |
| status | show detailed status of all projects |
| update <name> | update project configuration |
| edit <name> | edit project in $EDITOR |
| remove <name> | remove a project |
| clone <source> <name> | clone a project config (--copy to copy files) |
| open [name] | open project in browser |
processes
| command | description |
|---------|-------------|
| start [name] | start an npm project with pm2 |
| stop [name] | stop an npm project |
| restart [name] | restart an npm project |
| logs [name] | show project logs (-f to follow, --all for all projects) |
| watch [name] | watch for file changes and auto-restart |
| deploy [name] | git pull + npm install + restart |
use --all with start/stop/restart to manage all npm projects at once.
if you don't specify a project name, you'll get an interactive selector.
development
| command | description |
|---------|-------------|
| dev [name] | start in dev mode with hot reload |
| watch [name] | watch for changes and auto-restart |
| env [name] | view/modify environment variables |
# view env vars
bindler env myapp
# set env vars
bindler env myapp --set API_KEY=secret NODE_ENV=production
# unset env vars
bindler env myapp --unset DEBUG
# output as json
bindler env myapp --jsonsystem
| command | description |
|---------|-------------|
| apply | generate and apply nginx config + dns routes |
| doctor | run diagnostics and check dependencies |
| ports | show allocated ports |
| info | show bindler information |
| check <hostname> | check dns and http accessibility |
| setup | install missing dependencies |
| health | check health of all projects |
| stats | show cpu and memory stats |
configuration
| command | description |
|---------|-------------|
| init | interactive setup wizard |
| config [action] [key] [value] | view or modify bindler config |
| backup | backup configuration |
| restore [file] | restore from backup |
cloudflare
| command | description |
|---------|-------------|
| tunnel [action] | manage tunnel (status, start, stop, login, create, list) |
| ssl [hostname] | request ssl certificate (direct mode) |
other
| command | description |
|---------|-------------|
| completion [shell] | generate shell completion script (bash, zsh, fish) |
local development
for local-only projects (no cloudflare), use the --local flag:
bindler new --localthen add the hostname to /etc/hosts:
echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hostsaccess at http://myapp.local:8080
vps / direct mode
if you have a vps and don't need cloudflare tunnel, use direct mode:
bindler setup --directthis will:
- set nginx to listen on port 80 directly
- skip cloudflare dns routing
- optionally set up ssl with let's encrypt (certbot)
your projects will be accessible at https://app.yourdomain.com (no port needed).
# add a project
bindler new --name myapp --hostname app.yourdomain.com
# apply config + get ssl certificate
sudo bindler applypath-based routing
host multiple projects on the same hostname with different base paths:
# main app at example.com/
bindler new --name frontend --hostname example.com --type static
# api at example.com/api
bindler new --name api --hostname example.com --base-path /api --type npm --start "npm start"
# admin at example.com/admin
bindler new --name admin --hostname example.com --base-path /admin --type staticcloning projects
clone a project configuration to create a staging environment or duplicate:
# clone config only
bindler clone myapp myapp-staging
# clone config and copy files
bindler clone myapp myapp-staging --copy
# with custom hostname and path
bindler clone myapp myapp-staging --hostname staging.example.com --path /var/www/stagingthe --copy flag copies project files but excludes node_modules, .git, and build directories.
watch mode
auto-restart npm projects when files change:
bindler watch myappby default, ignores: node_modules, .git, dist, build, .next, .nuxt, coverage
add custom ignore patterns:
bindler watch myapp --ignore logs,tmp,.cacheenvironment variables
manage environment variables for your projects:
# view all env vars
bindler env myapp
# set variables
bindler env myapp --set PORT=3000 NODE_ENV=production API_KEY=secret
# unset variables
bindler env myapp --unset DEBUG VERBOSE
# export as json (for scripting)
bindler env myapp --jsonenv vars are automatically injected when starting projects with bindler start.
deployment
deploy updates to a project:
bindler deploy myappthis runs:
git pull- fetch latest changesnpm install- install dependenciespm2 restart- restart the app
skip steps with flags:
bindler deploy myapp --skip-pull
bindler deploy myapp --skip-install
bindler deploy myapp --skip-restartbackup and restore
backup your bindler configuration:
# backup to default location
bindler backup
# backup to specific file
bindler backup --output ~/bindler-backup.jsonrestore from backup:
bindler restore ~/bindler-backup.json
# overwrite existing config
bindler restore ~/bindler-backup.json --forcesecurity
configure security settings per project in the config file:
{
"name": "api",
"security": {
"basicAuth": {
"enabled": true,
"realm": "API Access",
"users": [
{ "username": "admin", "password": "secret" }
]
},
"ipAllowlist": ["192.168.1.0/24", "10.0.0.1"],
"ipBlocklist": ["1.2.3.4"],
"rateLimit": {
"enabled": true,
"requestsPerSecond": 10,
"burst": 20
},
"headers": {
"hsts": true,
"xFrameOptions": "DENY",
"xContentTypeOptions": true,
"xXssProtection": true,
"contentSecurityPolicy": "default-src 'self'"
}
}
}shell completion
generate shell completions for tab-completion:
# bash
bindler completion bash >> ~/.bashrc
# zsh
bindler completion zsh >> ~/.zshrc
# fish
bindler completion fish > ~/.config/fish/completions/bindler.fishhow it works
tunnel mode (default):
internet -> cloudflare -> cloudflared tunnel -> nginx (:8080) -> your projectsdirect mode (vps):
internet -> nginx (:80/:443) -> your projectsnginx routes by hostname. static sites serve files directly, npm apps run via pm2 and get proxied.
config
stored in ~/.config/bindler/config.json
{
"defaults": {
"nginxListen": "127.0.0.1:8080",
"tunnelName": "homelab"
},
"projects": []
}cloudflare tunnel setup
cloudflared tunnel login
cloudflared tunnel create homelabcreate ~/.cloudflared/config.yml:
tunnel: homelab
credentials-file: ~/.cloudflared/<tunnel-id>.json
ingress:
- service: http://localhost:8080run it:
cloudflared tunnel run homelabbindler will auto-create dns routes when you run bindler apply.
license
mit
