M1 · Proxies & VPNs page and the Add egress wizard
Each earning service pays once per public IP. Today, extra IPs (proxies, a second site over Tailscale) live at the bottom of Fleet, owner-only, one 9-field form per proxy, no VPN option, and a green Test only proves a TCP connection. This plan gives them their own page, a paste-many dialog, a test that checks each vendor through the proxy, and a CLI line for every action.
Mockup, dark theme, data fake (IPs from 203.0.113.0/24, ASN 64500). Colours, type and components are copied from app/static/css/style.css on origin/main. Purple numbered circles are notes for the reader, not part of the UI.
BEFORE Adding ten proxies today
Fleet → scroll → “Add a proxy”
Lives inside Fleet below the boxes, owner-only (fleet.html:76-80). Not in the nav, not in the setup wizard.
One proxy = Name, Type, Host, Port, User, Password, Cap, Stop %, Reset day, Rotating, Save (fleet.html:92-110). A provider sends a list of 10: ≈ 80 inputs plus 10 Saves.
Types: SOCKS5, HTTP, Tailscale exit (fleet.html:93-96). No WireGuard or OpenVPN file, no provider picker.
Test checks the tunnel and exit IP only (tunnel/cp-probe:8-14): a proxy that 403s PacketStream still shows green, and the copy earns nothing.
Running a copy is a second form with three selects, one copy per submit (fleet.html:114-123).
Keyboard: no shortcut reaches it; Tab from the top of Fleet takes 30+ presses (screenshot 36-kbd-fleet-proxy.png).
SCREEN 1 Proxies & VPNs page, reached with ge
One row per way out to the internet, starting with the box's own line. Status means “the services can earn through it”, not “a socket opened”.
CashPilot
+ Add service$148.32S
Proxies & VPNs
Test allCopy as CLI+ Add egress n
Each service pays once per public IP. Every row here is another IP your services can earn from. How egress works
IPs
4
3 earning
Copies running through egress
5
across 2 boxes
Egress traffic this month
16.4 GB
2.1 GB on capped plans
Net, this month
−$5.88
isp-1 costs more than it earns
Ways out 4
tested 6 min ago · t test selected
Name
Type
Status
Exit IP
Country
IP type
Copies
Traffic
Cost vs earnings
Kill switch
This box's own IP
box-a
Direct
Works
x.x.x.42
Spain
Residential
6
not counted
your own line
n/a
Test
isp-1
203.0.113.10:1080
SOCKS5sticky
Works
x.x.x.10
Spain
Residential/ISP
3
2.1/10 GB
resets on day 1
$3.00/GB cost~$0.20/GB earnedlosing money
On
TestPlace⋯
site-b
exit node at a second site
Tailscale exitvia box-b
Works
x.x.x.77
Spain
Residential
2
14.3 GB
no cap
no cost set~$0.20/GB earned
On
TestPlace⋯
wg-mullvad
mullvad-se-sto.conf
WireGuardfrom file
Works
x.x.x.201
Sweden
Datacenter
0
0 GB
no cap
$5.00/month
On
TestPlace⋯
4 of your services do not pay on datacenter IPs (Honeygain, EarnApp, IPRoyal Pawns, PacketStream). Mysterium and Storj do. Place only the ones that pay
Kill switch: a copy that runs through an egress has no route to the box's own line. If the egress drops, the copy stops instead of leaking out of your home IP.
CashPilot 2.2.0Press g then a page's first letter to jump, / to search, ? for all keys
123456789
1Own nav item, visible to every role.ge jumps here; the hint shows when the link has focus. Today proxies are a section of Fleet behind {% if user.r == 'owner' %} (fleet.html:76). Viewers see the table read-only; only the owner sees Add.
2One primary action, with a key.n opens the Add egress dialog from anywhere on the page. Today: scroll, find the collapsed <details>, open it (3 actions before the first field).
3The box's own IP is row one. It is the baseline every other row is compared to, and it makes the rule “one payout per IP” obvious without reading docs. Exit IPs are masked to the last octet by default (screenshots get shared); Shift-click reveals.
4“Works” means the vendors answer through it, not only that the tunnel opened (see Screen 3). Other values: Partly some vendors blocked, Down, Untested.
5Cost vs earnings. Cost per GB from the plan the user typed; earnings per GB from the copies' own balance history. Red “losing money” when cost > earnings. Today there is a cap but no cost, so a paid proxy can burn money silently.
6Kill switch shown, not assumed. Green only after the test proved the copy has no route to the home line (the probe tries the direct route and expects it to fail).
7Datacenter warning names the services. The list comes from the catalog's residential_ip: true key in services/**/*.yml; the link opens Place with only the services that pay pre-ticked.
8Totals first. How many IPs, how many earn, what egress cost this month. Net in red when negative.
9Copy as CLI(wave 3, L5) puts the equivalent commands on the clipboard: cashpilot egress ls --json, cashpilot egress test --all. The same affordance sits in every dialog footer.
STATES Empty, and the 390-wide phone layout
empty · first visit, owner
Proxies & VPNs
+ Add egress n
This box's own IP
box-a
Works
x.x.x.42
Spain
Residential
6 services
Each service earns once per IP. Add another IP.
Paste a proxy list from your provider, drop a WireGuard or OpenVPN file, or pick a Tailscale exit node at another site. CashPilot tests each one against the services you run before placing anything.
Passwords never leave this server and are never shown again.CancelTest all EnterAdd 3 egresses Ctrl Enter
1234567
1Four tabs, one dialog. Paste covers proxy lists; VPN file or provider takes a WireGuard .conf / OpenVPN .ovpn drop or a provider picker (adds a gluetun-style sidecar, no VPN client on the host); Tailscale is Screen 4; By hand is today's form. Digits switch tabs.
2Paste is the default and is focused on open, so n then Ctrl V is the whole input step. Passwords are masked in the box the moment they are parsed.
3Live preview, one row per line. The parser in app/proxies.py gains parse_proxy_line(); the API takes a list (POST /api/egress/batch). Today the API takes one proxy per call (app/proxies.py:24).
4Bad line in red with the reason, skipped, counted out of the Add button (“Add 3”, not 4). Fixing it in the textarea updates the row at once.
5Shared fields typed once. Ten proxies from one plan share cap, reset day and price. Rotation is measured, not asked (Screen 3).
6Copy as CLI(wave 3, L5) with the exact flags the dialog holds, passwords excluded (the file keeps them). An agent can do the same with one command.
7Test before Add. Enter tests all parsed lines in parallel; Add stays available but warns if a line has not passed. ten proxies: ≈ 80 inputs → 3 keys (n, Ctrl V, Enter) plus one click to add.
Keyboardn opens the dialog, focus in the paste box→Ctrl V pastes, preview fills→Tab reaches Test all→Enter runs it→Esc closes, focus returns to “+ Add egress”
SCREEN 3 Test result: what the IP is, and which vendors answer through it
The probe in tunnel/cp-probe already fetches the exit IP. It gains three checks: IP type from the ASN, rotation from three samples, and a reach test against each deployed service's own endpoints through the egress.
CashPilot
$148.32S
Test · isp-1
tested just now · 6.2 s · Esc close
Exit IP
x.x.x.10 (203.0.113.0/24)
Country
Spain
IP type
Residential/ISPAS64500 Example Telecom
Rotation
3 samples, same IP: sticky(30 s apart)
Latency
84 ms
Kill switch
Ondirect route refused inside the copy's network, as it should be
Vendor reach through isp-15 of your services · 2 can earn here
Service
Result
What it means
Honeygain
OK
API answered 200 in 180 ms
Repocket
OK
API answered 200 in 240 ms
PacketStream
blocked (403)
The proxy provider blocks this vendor's domain. A copy would run and earn nothing.
Traffmonetizer
port closed
The proxy only passes ports 80 and 443; Traffmonetizer needs its own relay port.
EarnApp
not applicable
Cannot run behind a proxy: it keeps data in a volume.
No proxy traffic was spent on blocked vendors: the reach test is one HTTPS request per service, about 40 KB in total.
1IP type with the network's name. Residential, Residential/ISP, Datacenter, Mobile, from the ASN of the exit IP. Users buy “residential” proxies that turn out to be hosting ranges; this shows it before money is spent.
2Rotation is measured. Three samples. Same IP = sticky; different = rotating, and the rotating box ticks itself. Today it is a checkbox the user must know to tick (fleet.html:109).
3Vendor reach, per deployed service. One request to each vendor's endpoint (the new docker.egress list of {host, port} in the service YAML) through the egress. This is the check whose absence made copies run green and earn nothing.
4Failures say what to do, in plain words, not an HTTP dump. Ports come from the service YAML.
5Services that cannot run through any egress are greyed, with the reason the code already enforces (no host networking, ports, volumes or devices, fleet.html:121).
6Place earners pre-selects only the services that passed, on the boxes that already run them, and asks once. Today: one “Run a copy” submit per service per proxy (fleet.html:114-123).
loading · reach test running
Testing isp-1 · exit IP done · rotation 2 of 3 samples · vendors 3 of 5
Esc closes this; the test keeps running and the row updates when it ends.
error · the egress itself is unreachable
Could not connect to 203.0.113.13:1080: connection refused after 5 s. The host is up but nothing listens on that port. Check the port in your provider's panel.
Edit portRetry tRemove
SCREEN 4 Tailscale tab: connect once, pick an exit node
Today the user creates an auth key in the Tailscale admin, pastes it, and types the exit node name or its 100.x address (fleet.html:103-105). Here CashPilot signs in with Tailscale OAuth and lists the nodes that can be exits.
$ cashpilot egress add --tailscale router-2 --name site-cCopy as CLI
CancelAdd 1 exit node
12345
1Connect Tailscale runs an OAuth flow and stores a read-only client. The button greys after it works and the tailnet name shows, with Disconnect beside it. Self-hosted Headscale keeps the By hand tab (login server field).
2A picker instead of a typed name or 100.x address. Online dot, last seen, exit country. Already-added nodes are ticked and labelled. Arrow keys and Space work.
3Offline nodes stay listed but greyed, so the user does not wonder where “travel-router” went.
4Missing-grant state, specific. The error comes back from the tailscale sidecar; the screen names the node and the reason instead of a generic failure.
5The exact JSON to paste, with Copy, and a link that opens the admin page. CashPilot never asks for a write token to the policy file.
CLI · API Same actions without the browser
Every dialog above has a Copy as CLI line (wave 3, L5). The CLI is a thin client over the same REST endpoints (bearer token from Settings → API tokens), so a person in a terminal and an agent such as Claude Code get identical behaviour.
$ cashpilot egress import proxies.txt --default-type socks5 --cap 10GB --reset-day 1 --test
added isp-2 socks5 203.0.113.10:1080 Works Residential/ISP ES sticky
added isp-3 socks5 203.0.113.11:8080 Partly Residential/ISP ES rotating PacketStream blocked (403)added isp-4 http 203.0.113.12:3128 Works Datacenter DE sticky 4 services do not pay on datacenter IPsskipped line 4 203.0.113.13:dave:****** port missing
3 added, 1 skipped. Next: cashpilot copy apply --egress isp-2 --earners$ cashpilot egress test isp-1 --json
{
"name": "isp-1", "status": "works", "exit_ip": "203.0.113.10", "country": "ES",
"ip_type": "residential_isp", "asn": 64500, "asn_name": "Example Telecom",
"rotation": { "samples": 3, "distinct": 1, "verdict": "sticky" },
"kill_switch": true,
"reach": [
{ "service": "honeygain", "result": "ok", "http": 200, "ms": 180 },
{ "service": "repocket", "result": "ok", "http": 200, "ms": 240 },
{ "service": "packetstream", "result": "blocked", "http": 403 },
{ "service": "traffmonetizer", "result": "port_closed" },
{ "service": "earnapp", "result": "not_applicable", "reason": "uses_volume" }
],
"cost": { "per_gb_usd": 3.0, "earned_per_gb_usd": 0.20, "verdict": "losing_money" }
}
$ cashpilot copy apply --egress isp-1 --earners --dry-run
would run honeygain on box-a via isp-1
would run repocket on box-a via isp-1
exit 0 · nothing changed (--dry-run). Exit codes: 0 ok, 1 error, 2 usage, 3 auth or scope, 4 not found, 5 refused for safety, 6 box offline, 7 partial, 8 conflict.
AHuman output by default, --json for agents, stable field names, documented exit codes so a script or an agent can branch without parsing prose.
B--dry-run on every write and a “Next:” hint after each command. Docs page docs/egress.md carries a copy-paste block per provider format, and docs/agents.md lists the commands and exit codes for agents.