Share any folder to the internet. One command. No cloudflared. No ngrok. Your files, your tunnel, your rules.
Browser → *.shareiscare.dev → Cloudflare Worker (Durable Object) ←WebSocket→ your machine
brew install rodrwan/tap/shareiscaregit clone https://github.com/rodrwan/shareiscare.git
cd shareiscare
make build # → ./bin/shareiscareThe binary is self-contained — UIs are embedded via go:embed.
# Share the current directory
shareiscare
# Share a specific folder with a custom hash
shareiscare --hash myproject --dir ./dist
# With password and bandwidth limit
shareiscare --password secret123 --max-bandwidth 1024📁 Sharing: /Users/rod/projects/my-app
🌍 Public: https://a1b2c3d4e5f67890.shareiscare.dev
🔐 Admin: http://127.0.0.1:9898?token=f3a1b2c3...
🔒 Password protection enabled
📊 Daily bandwidth limit: 1024 MB
✅ Tunnel connected
The URL is stable across restarts — the hash and tunnel secret are persisted in .shareiscare.json. To force a new URL: shareiscare --new-hash.
| Flag | Default | Description |
|---|---|---|
--hash |
auto (16-char hex) | Subdomain hash for your URL |
--new-hash |
false |
Force a new hash and URL |
--dir |
. |
Directory to share |
--password |
— | Password for public access (HTTP Basic Auth) |
--max-bandwidth |
0 (unlimited) |
Daily bandwidth limit in MB |
--admin-port |
9898 |
Admin panel port |
--config |
<dir>/.shareiscare.json |
Path to config file |
--no-admin |
false |
Disable admin panel |
--no-defaults |
false |
Don't seed default sensitive patterns |
--max-zip |
100 MB |
Max size for ZIP downloads |
--version |
— | Print version and exit |
shareiscare starts a local admin server on 127.0.0.1:9898 (only accessible from your machine) protected with an auto-generated token.
From there you can:
- Hide/show files with gitignore-style patterns (e.g.
*.log,secrets/) - Enable/disable default patterns (
.env,.git/,*.key,*.pem,node_modules/, etc.) - View the file tree with visibility status
Rules are persisted in .shareiscare.json.
| Endpoint | Method | Description |
|---|---|---|
/__admin/api/rules |
GET |
List rules |
/__admin/api/rules |
POST |
Add rule |
/__admin/api/rules |
DELETE |
Remove rule |
/__admin/api/defaults |
GET / PUT |
Query/toggle default patterns |
/__admin/api/tree |
GET |
Full tree with visibility |
Auth via ?token=<token> or Authorization: Bearer <token>.
- Default sensitive patterns:
.env,.git/,*.key,*.pem,*.sqlite,credentials, etc. — automatically hidden on startup - Dotfiles: never served
- Symlinks: validated to not escape the root directory
- 404 instead of 403: hidden files return 404 to avoid leaking their existence
- Security headers:
X-Content-Type-Options,X-Frame-Options,Referrer-Policy, CSP
| Protection | Variable (wrangler.toml) |
Default |
|---|---|---|
| Rate limit per IP | RATE_LIMIT_RPM |
60 req/min |
| Hash validation | — | [a-z0-9]{4,64} |
| Request body limit | MAX_REQUEST_BODY_MB |
100 MB |
| Active tunnel limit | MAX_TUNNELS |
50 |
| Orphan DO cleanup | CLEANUP_HOURS |
24 h |
The tunnel limit uses an internal registry DO that maintains an atomic counter. When a DO is cleaned up due to inactivity, the counter is decremented automatically.
All values are configurable in worker/wrangler.toml:
[vars]
MAX_TUNNELS = "50"
MAX_REQUEST_BODY_MB = "100"
RATE_LIMIT_RPM = "60"
CLEANUP_HOURS = "24"| Protection | Flag |
|---|---|
| Password (HTTP Basic Auth) | --password |
| Daily bandwidth limit | --max-bandwidth |
┌─────────────┐ ┌──────────────────────────────┐
│ Browser │ HTTPS │ Cloudflare Edge │
│ (visitor) │ ──────▶ │ Worker → TunnelDO (by hash) │
└─────────────┘ └──────────────┬───────────────┘
│ WebSocket (wss://)
┌──────────────▼───────────────┐
│ shareiscare (Go binary) │
│ │
│ shareHandler → files │
│ adminHandler → rules │
│ RulesEngine → visibility │
└──────────────────────────────┘
- Browser requests
https://myHash.shareiscare.dev/docs/ - Worker validates hash + rate limit, serializes the request to JSON (body in base64)
- Durable Object forwards via WebSocket to the Go client
shareHandlerchecks password, rules and bandwidth, serves the file in memory- Response travels back via WebSocket → Worker → Browser
A regular Worker is stateless — it can't maintain a WebSocket across requests. Durable Objects are stateful instances at the edge: each hash maps to a unique DO that maintains the WebSocket and the pending request map. It uses the WebSocket Hibernation API so the DO sleeps between messages and only consumes CPU during actual activity.
To use your own domain instead of shareiscare.dev:
npm install -g wrangler
wrangler loginEdit worker/wrangler.toml:
[[routes]]
pattern = "*.yourdomain.com/*"
zone_name = "yourdomain.com"In Cloudflare Dashboard → your zone → DNS:
| Type | Name | Address | Proxy |
|---|---|---|---|
| A | * | 192.0.2.1 | Proxied |
(The IP is a placeholder — the Worker intercepts first)
make deployIn cmd/shareiscare/main.go, replace shareiscare.dev with your domain and recompile with make build.
make build # Compile → ./bin/shareiscare
make run # Build + run (current directory)
make run-hash HASH=abc # Run with specific hash
make vet # go vet
make test # Tests
make deploy # Deploy Worker to Cloudflare
make dev # Worker in local dev modePublished automatically via GoReleaser when pushing a v* tag. CI runs tests, generates binaries for darwin/linux (amd64/arm64), and publishes the formula to rodrwan/homebrew-tap.
| Error | Cause | Solution |
|---|---|---|
tunnel: connect failed: no such host |
Worker not deployed or wildcard DNS missing | dig +short @1.1.1.1 test.yourdomain.com |
503 No client connected |
Go binary is not running | Start shareiscare |
429 Rate limit exceeded |
Too many requests from your IP | Wait 60s or adjust RATE_LIMIT_RPM |
429 tunnel limit reached |
Active tunnel limit reached | Adjust MAX_TUNNELS |
403 invalid secret |
DO secret mismatch | Use --new-hash or wait for cleanup |
invalid hash |
Hash doesn't match [a-z0-9]{4,64} |
Use only lowercase letters and digits |
Durable Objects not supported |
Free Workers plan | Enable Workers Paid (~$5/month) |
| Wildcard DNS not working | DNS record in DNS-only mode | Switch to Proxied (orange cloud) |
MIT
