npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bindler

v2.1.0

Published

CLI for managing multiple projects behind Cloudflare Tunnel with Nginx and PM2

Downloads

1,699

Readme

bindler

cli for managing multiple projects behind cloudflare tunnel with nginx and pm2.

install

npm install -g bindler

update to latest

npm update -g bindler

you'll also need:

  • node.js 18+
  • nginx - brew install nginx (mac) or apt install nginx (linux)
  • pm2 - npm install -g pm2
  • cloudflared (optional) - brew install cloudflared or 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 config

usage

# 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 status

commands

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 --json

system

| 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 --local

then add the hostname to /etc/hosts:

echo "127.0.0.1  myapp.local" | sudo tee -a /etc/hosts

access at http://myapp.local:8080

vps / direct mode

if you have a vps and don't need cloudflare tunnel, use direct mode:

bindler setup --direct

this 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 apply

path-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 static

cloning 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/staging

the --copy flag copies project files but excludes node_modules, .git, and build directories.

watch mode

auto-restart npm projects when files change:

bindler watch myapp

by default, ignores: node_modules, .git, dist, build, .next, .nuxt, coverage

add custom ignore patterns:

bindler watch myapp --ignore logs,tmp,.cache

environment 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 --json

env vars are automatically injected when starting projects with bindler start.

deployment

deploy updates to a project:

bindler deploy myapp

this runs:

  1. git pull - fetch latest changes
  2. npm install - install dependencies
  3. pm2 restart - restart the app

skip steps with flags:

bindler deploy myapp --skip-pull
bindler deploy myapp --skip-install
bindler deploy myapp --skip-restart

backup and restore

backup your bindler configuration:

# backup to default location
bindler backup

# backup to specific file
bindler backup --output ~/bindler-backup.json

restore from backup:

bindler restore ~/bindler-backup.json

# overwrite existing config
bindler restore ~/bindler-backup.json --force

security

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.fish

how it works

tunnel mode (default):

internet -> cloudflare -> cloudflared tunnel -> nginx (:8080) -> your projects

direct mode (vps):

internet -> nginx (:80/:443) -> your projects

nginx 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 homelab

create ~/.cloudflared/config.yml:

tunnel: homelab
credentials-file: ~/.cloudflared/<tunnel-id>.json
ingress:
  - service: http://localhost:8080

run it:

cloudflared tunnel run homelab

bindler will auto-create dns routes when you run bindler apply.

license

mit