Fix proxy and split server into modules #1

Merged
probablycorey merged 18 commits from probablycorey/fix-proxy-404s into main 2026-03-11 16:35:00 +00:00

Summary

  • Split monolithic server.ts into proxy.ts, binary.ts, and server.ts
  • Switch from unix socket to TCP proxy so Go server sees localhost for auto-login
  • Auto-download Go binary on startup (postinstall hooks dont run on toes)
  • Handle gzip decompression in the double-proxy chain
  • Default PRODUCTION=true for system apps
  • Pass redirects through to browser instead of following internally

Test plan

  • Tronbyt accessible at http://tronbyt.toes.local/
  • Go binary auto-downloads on first run
  • Static assets (CSS/JS) load correctly
  • Registration and login work through proxy

🤖 Generated with Claude Code

## Summary - Split monolithic server.ts into proxy.ts, binary.ts, and server.ts - Switch from unix socket to TCP proxy so Go server sees localhost for auto-login - Auto-download Go binary on startup (postinstall hooks dont run on toes) - Handle gzip decompression in the double-proxy chain - Default PRODUCTION=true for system apps - Pass redirects through to browser instead of following internally ## Test plan - [x] Tronbyt accessible at http://tronbyt.toes.local/ - [x] Go binary auto-downloads on first run - [x] Static assets (CSS/JS) load correctly - [x] Registration and login work through proxy 🤖 Generated with [Claude Code](https://claude.com/claude-code)
probablycorey added 18 commits 2026-03-11 16:33:04 +00:00
The postinstall script doesn't run on toes (package.json is
transformed during deploy), so the binary was never downloaded.
Now the server downloads it from GitHub releases if missing.
Added validate() to catch missing DATA_DIR and non-executable
binary with clear error messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Toes health-checks /ok during startup. The Go server can take a
while to become healthy (cloning system apps repo on first run),
so return 200 while the process is alive but not yet ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Passing req.body (a ReadableStream) for GET requests could cause
the unix socket fetch to hang waiting for body data, especially
when the upstream toes proxy has already stripped content-length.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tronbyt.toes.local resolves to an IPv4 address while toes.local
uses IPv6, so the toes proxy couldn't reach the Bun server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Toes proxy fetches via localhost which may resolve to ::1 on Linux.
Listening on :: accepts both IPv4 and IPv6 connections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Go server returns gzip responses, but when Bun proxies these
through to the toes proxy, the double-proxy causes a ZlibError
during decompression. Stripping accept-encoding tells the Go
server to send uncompressed responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bun decompresses gzip responses internally but leaves the
Content-Encoding: gzip header, causing browsers to fail trying
to decompress already-decompressed content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- proxy.ts: HTTP and WebSocket proxy to Go unix socket
- binary.ts: Go binary download, validation, spawning, lifecycle
- server.ts: entry point wiring everything together

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Streaming req.body through the double proxy (toes -> bun -> go)
caused POST requests to fail. Buffer the body as an ArrayBuffer
first so content-length is set correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bun's fetch has a decompress option that passes responses through
without interpreting content-encoding. This replaces all the manual
header stripping workarounds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Toes' Bun fetch auto-decompresses responses. If Go sends gzip
through our proxy, toes gets raw gzip bytes it can't handle.
Stripping accept-encoding tells Go to send uncompressed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Go server always sends gzip regardless of accept-encoding. Bun
decompresses it automatically but leaves the content-encoding
header. Strip it so the toes proxy doesn't try to decompress
the already-decompressed response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Go server checks if the client is on a private network for
auto-login. Since we proxy over a unix socket, the Go server
can't see the real client IP. Forward it via X-Forwarded-For
and X-Real-IP headers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Proxy to Go server on 127.0.0.1:8000 instead of unix socket.
Go sees localhost connections as trusted for auto-login.
Removes all the unix socket, IP forwarding, and socket path
plumbing complexity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bun's fetch was following Go's 303 redirects internally, which
caused ECONNRESET errors during the auto-login redirect chain.
Let the browser handle redirects instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
probablycorey merged commit a56dfdc422 into main 2026-03-11 16:35:00 +00:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: probablycorey/tronbyt#1
No description provided.