CLI to expose a local port via simplified-org.com with one command
npm install @simplified-org/tunnelPortable tunneling stack built on FRP, consisting of:
- FRP server (frps): terminates tunnels and routes subdomains to clients.
- Tunnel Manager API + admin UI (src/): hands out subdomains, tracks activity, exposes WebSocket updates, and serves a localhost-only dashboard.
- CLI (simplified): one-command client that requests a tunnel and runs frpc for you.
Use this README to self-host the full stack (Docker or bare metal), understand the architecture, and see operational quirks.
---
https://. ). frpc to connect to the FRP server using the shared token. frps) accepts the tunnel and vhosts HTTP traffic for that subdomain to the client’s local port. ---
Dockerfile, start.sh, frps.ini.template, docker-compose.yml – FRP server container + compose with API. bin/simplified.js, lib/* – CLI entrypoint, tunnel API client, frpc downloader/runner. src/ – Tunnel Manager API + admin UI. server/index.js HTTP + WebSocket server, middleware, admin gating. server/api.js REST routes. server/tunnelManager.js in-memory + file-backed tunnel state, history, WebSocket broadcasting. server/logger.js request/tunnel logging to file + buffer + WS. server/randomWords.js subdomain generation/validation. admin/ static dashboard (served locally). data/ runtime state/logs (gitignored). test/webapp – simple sample webapp + FRP binaries for local testing.---
*.your-domain pointing to the host running frps (DNS-only/proxied off). 80 (HTTP vhost) and 7000 (FRP control). FRP_TOKEN). ---
bash
cp docker-compose.yml docker-compose.local.yml
edit env values in the file or export FRP_TOKEN/FRP_SERVER_ADDR etc.
docker compose -f docker-compose.local.yml up --build
`
Services:
- frps (ports 80, 7000) built from the Dockerfile; requires FRP_DOMAIN, FRP_BIND_PORT, FRP_HTTP_PORT, FRP_TOKEN, optional FRP_MAX_POOL.
- api (port 4000) runs /src with npm install && npm start; set ADMIN_HOST=0.0.0.0 only if you intend to expose the dashboard and secure it yourself (defaults to localhost when run bare).Recommended extras:
- Mount
./src/data as a volume to keep tunnel/log/history data across restarts.
- Set FRP_SERVER_ADDR to the public IP/DNS of the frps host (defaults to 34.227.103.55 in compose; change this).---
Option B: Docker only (FRP server)
Build and run the FRP server container:
`bash
docker build -t simplified-tunnel-frps .
docker run --rm -p 80:80 -p 7000:7000 \
-e FRP_DOMAIN=your-domain.com \
-e FRP_BIND_PORT=7000 \
-e FRP_HTTP_PORT=80 \
-e FRP_TOKEN=your-token \
-e FRP_MAX_POOL=200 \
simplified-tunnel-frps
`
Then run the Tunnel Manager separately (Node or another container) pointed at this FRP endpoint.---
Option C: Bare metal
FRP server
`bash
export FRP_DOMAIN=your-domain.com
export FRP_BIND_PORT=7000
export FRP_HTTP_PORT=80
export FRP_TOKEN=your-token
place a compatible frps binary in PATH or alongside start.sh
./start.sh
`Tunnel Manager API + admin
`bash
cd src
npm install
TUNNEL_MANAGER_PORT=4000 \
ADMIN_HOST=127.0.0.1 \
FRP_DOMAIN=your-domain.com \
FRP_SERVER_ADDR= \
FRP_BIND_PORT=7000 \
FRP_TOKEN=your-token \
npm start
`
Admin dashboard lives at http://127.0.0.1:4000/admin (localhost-only). APIs under /api.---
CLI (client) usage against your deployment
`bash
npm install -g simplified
SIMPLIFIED_API_BASE=http://:4000 simplified --port 3000
optional: --subdomain my-site
`
- Downloads frpc from GitHub releases (cached at ~/.simplified/frpc).
- Supported platforms: macOS (arm64/amd64), Linux (arm64/amd64), Windows (amd64/arm64).---
Configuration reference
FRP server (start.sh / Dockerfile / compose)
- Required: FRP_DOMAIN, FRP_BIND_PORT, FRP_HTTP_PORT, FRP_TOKEN
- Optional: FRP_MAX_POOL (default 200), FRPS_BIN (custom binary path)Tunnel Manager (
src/config.js)
- TUNNEL_MANAGER_PORT (default 4000)
- ADMIN_HOST (default 127.0.0.1 — set to 0.0.0.0 only when you secure access)
- FRP_DOMAIN (default simplified-org.com)
- FRP_SERVER_ADDR (default localhost)
- FRP_BIND_PORT (default 7000)
- FRP_TOKEN (default supersecret)
- MAX_TUNNELS_PER_USER (default 5)
- TUNNEL_TIMEOUT (default 24h, ms)
- Data files live in src/data: tunnels.json, history.json, requests.log (gitignored).CLI
-
SIMPLIFIED_API_BASE overrides the API URL (defaults to https://api.simplified-org.com).DNS/TLS:
- Create wildcard A record
*. to the frps host.
- TLS terminates at your DNS/CDN; frps serves HTTP only.---
Code architecture and flow
- CLI
- bin/simplified.js: parses flags, calls tunnel API, ensures frpc, spawns it.
- lib/api.js: POST /api/tunnels, handles errors.
- lib/downloader.js: downloads/extracts frpc (v0.61.0) per OS/arch into ~/.simplified.
- lib/tunnel.js: spawns frpc http -s .
- Tunnel Manager (src/server)
- index.js: Express + WS server; logs every request; gates admin routes to localhost; serves /admin; health/root endpoints.
- api.js: REST routes for tunnel CRUD, availability checks, suggestions, stats, admin logs/history/config.
- tunnelManager.js: in-memory map + JSON persistence; random subdomains; conflict resolution; TTL cleanup; WebSocket broadcasts of tunnels/stats; modes (production vs local).
- logger.js: request/tunnel log levels, file append, in-memory buffer, WS fanout, log filtering/cleanup APIs.
- randomWords.js: adjective/noun lists, suffixes, validation and alternative generation.
- config.js: env parsing and defaults.
- admin/: static dashboard (dark theme) consuming /ws for live updates.
- FRP server
- start.sh: validates env, renders frps.ini from template via envsubst, execs frps.
- Dockerfile: alpine base, downloads FRP frps (default v0.52.3) for detected arch, runs as non-root.---
Quirks and operational notes
- Admin access is localhost-only in code. In docker-compose.yml, ADMIN_HOST is set to 0.0.0.0; you must secure that port yourself (firewall, auth, VPN).
- Data persistence: src/data is not volume-mounted by default in compose—mount it to avoid losing tunnels/logs/history.
- FRP versions differ: container pulls frps v0.52.3 while the CLI fetches frpc v0.61.0; align versions if you see protocol warnings.
- Stats persistence is throttled (writes every 10 requests) to reduce disk I/O.
- Tunnel expiry defaults to 24h; expired tunnels are removed and added to history.
- Subdomain suggestions reserve names like admin, api, localhost; conflicts return alternatives.
- HTTPS termination is out of scope; keep DNS/CDN in “DNS only” (no orange cloud) unless you handle TLS separately.
- CLI cache location: ~/.simplified/frpc; removal is manual.
- WebSocket and admin endpoints reject non-local IPs; log entries include IP/User-Agent for auditing.
- Compose uses a hardcoded example IP 34.227.103.55 for FRP_SERVER_ADDR; change it to your host.---
How to propose improvements
Ideas based on current code paths:
- Align frps/frpc versions and make the version configurable in both Dockerfile and CLI.
- Add auth to the admin dashboard and optionally allow remote access with proper protection.
- Persist data to a real store (SQLite/Postgres) and run migrations instead of JSON files.
- Add rate limits / per-IP quotas in requestTunnel to prevent abuse.
- Expose metrics (Prometheus) and health for frps alongside the API health check.
- Support HTTPS termination (LetsEncrypt/ACME) or behind-proxy documentation.
- Provide official images for the API (not just compose-on-the-fly).
- Add integration tests that spin up frps + API + sample frpc to validate end-to-end.---
Testing the sample webapp locally
`bash
cd test/webapp/backend
npm install
npm start # serves http://localhost:3000
`
Use the CLI with --port 3000 against your running manager + frps to publish it.---
Uninstalling the CLI
`bash
npm uninstall -g simplified
rm -rf ~/.simplified/frpc
``