gopher

module
v0.1.0-alpha.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2026 License: MIT

README ΒΆ

🐹 Gopher

Public router for private services. Self-hosted reverse tunnel system with automatic HTTPS and subdomain routing. Expose homelab services, research servers, or any private machine via clean URLs β€” no port forwarding needed.

Example:

photos.yourdomain.com β†’ Immich on home NAS (192.168.1.50:2283)
lab.yourdomain.com    β†’ Jupyter on university server (no public IP)
vault.yourdomain.com  β†’ Bitwarden on Raspberry Pi (behind NAT)

Built on Caddy and rathole

Gopher would not exist without two excellent open-source projects:

Caddy handles all HTTPS termination and subdomain routing on the VPS. It automatically provisions and renews TLS certificates via Let's Encrypt, with zero configuration required from the user. Gopher generates and manages the Caddyfile for you, but Caddy is doing the actual reverse proxying.

rathole is the tunnel engine. It's a Rust-based, extremely lightweight TCP/UDP tunnel that machines use to punch through NAT and firewalls by maintaining a persistent outbound connection to the VPS. Gopher manages the rathole server config and deploys rathole client configs to each machine β€” but rathole is what makes the tunnels actually work.

If you find Gopher useful, please consider starring those projects too.


How It Works

Run Gopher on a VPS. It manages Caddy (reverse proxy) and rathole (tunnel server). Private machines establish outbound tunnels. Gopher routes incoming traffic by subdomain.

Internet
   β”‚
   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Public VPS (Gopher runs here)                  β”‚
β”‚                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Caddy (80/443) β”‚   β”‚  rathole server     β”‚  β”‚
β”‚  β”‚  auto-HTTPS     │──▢│  (port 2333)        β”‚  β”‚
│  │  subdomain→port │   │  tunnels listening  │  │
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
└────────────────────────────────-β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚  outbound TCP tunnel
                   β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚  Private network (home/lab/office)        β”‚
         β”‚                                           β”‚
         β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
         β”‚  β”‚  Immich VM   β”‚  β”‚  Bitwarden VM    β”‚  β”‚
         β”‚  β”‚  rathole cli β”‚  β”‚  rathole cli     β”‚  β”‚
         β”‚  β”‚  :2283       β”‚  β”‚  :80             β”‚  β”‚
         β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Traffic flow: photos.yourdomain.com β†’ Caddy (VPS) β†’ rathole tunnel β†’ rathole client β†’ localhost:2283 (Immich)

Key insight: Machines connect outbound to the VPS, bypassing NAT and firewalls. The VPS routes incoming traffic back through those established tunnels.


Installation

Gopher ships as a single self-contained binary for Linux. No runtime dependencies β€” Caddy and rathole are downloaded automatically during setup.

Requirements
  • Linux VPS (Ubuntu 22.04+ or RHEL 8+ recommended), x86_64 or arm64
  • A domain with a wildcard DNS A record pointing at your VPS: *.yourdomain.com β†’ <VPS IP>
  • Ports 22, 80, 443, and 2333 reachable on the VPS
Download

Latest stable release:

ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
TAG=$(curl -fsSL https://api.github.com/repos/smalex-z/gopher/releases/latest | grep '"tag_name"' | cut -d'"' -f4)
curl -fsSL "https://github.com/smalex-z/gopher/releases/download/${TAG}/gopher-linux-${ARCH}" -o gopher && chmod +x gopher

Latest pre-release (recommended for now β€” no stable release yet):

ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
TAG=$(curl -fsSL https://api.github.com/repos/smalex-z/gopher/releases | grep -m1 '"tag_name"' | cut -d'"' -f4)
curl -fsSL "https://github.com/smalex-z/gopher/releases/download/${TAG}/gopher-linux-${ARCH}" -o gopher && chmod +x gopher

You can verify your download against the checksums file on the releases page.

Run
# Start the web UI (listens on :8080)
./gopher

# Install as a systemd service (runs on boot, survives reboots)
sudo ./gopher install

# Service management
sudo systemctl status gopher
sudo systemctl restart gopher

# Uninstall
sudo ./gopher uninstall

On first start, visit http://<your-vps-ip>:8080 and complete the setup wizard:

  1. Password β€” set your admin password
  2. Local services β€” install Caddy and rathole on this machine (or skip for rathole-only)
  3. Firewall β€” choose how network rules are managed (Gopher-managed is recommended)
  4. SSH key β€” generate or upload an SSH key pair used to access bootstrapped machines

Setup Workflow

After the wizard, you're at the main dashboard:

1. Add Machines (Machines tab)

  • Click Bootstrap New Machine
  • Copy the one-liner and run it on any machine you want to expose
  • It installs rathole client and establishes a reverse tunnel back to your VPS

2. Create Tunnels (Tunnels tab)

  • Select a machine, enter a subdomain (e.g. photos) and the local port (e.g. 2283)
  • Click Create Tunnel
  • https://photos.yourdomain.com is live with automatic TLS in seconds

Gopher supports HTTP, raw TCP, and UDP tunnels.


Use Cases

Homelab:

photos.home.com   β†’ Jellyfin media server
vault.home.com    β†’ Bitwarden password manager
files.home.com    β†’ Nextcloud file sync
monitor.home.com  β†’ Grafana dashboards

Research Lab:

jupyter.lab.edu   β†’ Jupyter notebook server
vnc1.lab.edu      β†’ VNC to lab workstation
data.lab.edu      β†’ Dataset browser

Multi-site:

nas.example.com      β†’ Home NAS (Maryland)
jupyter.example.com  β†’ Lab server (UCLA)
media.example.com    β†’ Friend's shared Plex

Comparison

Gopher ngrok Cloudflare Tunnel Port Forwarding
Cost VPS (~$3–5/mo) $8–20/mo Free* None
Custom domain βœ… πŸ’° Paid tier ⚠️ CF DNS required βœ…
Permanent URLs βœ… ❌ Ephemeral βœ… βœ…
Self-hosted βœ… ❌ ❌ N/A
Vendor lock-in ❌ βœ… βœ… ❌
Protocol support HTTP / TCP / UDP HTTP / TCP HTTP only** All
Works behind NAT βœ… βœ… βœ… ❌
Automatic HTTPS βœ… βœ… βœ… ❌
Traffic privacy βœ… You control ❌ ngrok sees all ❌ CF sees all βœ…

* Free with limitations
** Non-HTTP protocols require Cloudflare Access (paid)


Firewall Setup

Gopher needs four ports reachable on your VPS: 22 (SSH), 80 (HTTP), 443 (HTTPS), and 2333 (rathole control).

Note: Automatic firewall management is planned for a future release. For now, open the required ports manually using the instructions below.

OS-level firewall (on the VPS itself)

If your VPS is running UFW:

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 2333/tcp
sudo ufw enable

If it's running firewalld (RHEL/CentOS):

sudo firewall-cmd --permanent --add-port=22/tcp
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=2333/tcp
sudo firewall-cmd --reload

Or with raw iptables:

sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2333 -j ACCEPT
# Save rules so they persist after reboot
sudo iptables-save | sudo tee /etc/iptables/rules.v4   # Debian/Ubuntu
# sudo iptables-save | sudo tee /etc/sysconfig/iptables  # RHEL/CentOS

Each tunnel you create also gets its own port (starting around 20000). You'll need to open those too as you add tunnels β€” Gopher shows the assigned port when you create one.

Cloud-level firewall / security groups

Most cloud providers have a firewall that sits in front of the VM and blocks traffic before it ever reaches the OS. You need to open ports there as well.

Oracle Cloud (OCI) β€” the most common gotcha, since the default security list blocks almost everything:

  1. Go to Networking β†’ Virtual Cloud Networks β†’ your VCN β†’ Security Lists
  2. Edit the Default Security List (or whichever is attached to your subnet)
  3. Add ingress rules for TCP ports 80, 443, and 2333 from source 0.0.0.0/0
  4. Port 22 is usually already open

Alternatively, use a Network Security Group attached to your instance instead of the security list.

AWS EC2:

  1. Go to EC2 β†’ Instances β†’ your instance β†’ Security
  2. Click the security group link
  3. Edit Inbound rules β†’ add TCP 80, 443, 2333 from 0.0.0.0/0

Hetzner:

  1. Go to Firewall in the Cloud Console
  2. Add inbound rules for TCP 80, 443, 2333
  3. Apply the firewall to your server

DigitalOcean:

  1. Go to Networking β†’ Firewalls
  2. Create or edit a firewall, add TCP 80, 443, 2333 inbound
  3. Apply it to your droplet

VPS Recommendations

Tested providers:

  • Oracle Cloud Free Tier β€” 4 vCPU ARM, 24 GB RAM, 4 Gbps β€” best free option for Gopher
  • Hetzner β€” ~€4/month β€” reliable and cheap
  • DigitalOcean / Vultr β€” $6/month droplet works well
  • AWS EC2 β€” t2.micro is free tier eligible but networking is slow (~0.05 Gbps)

Minimum: 1 vCPU, 512 MB RAM handles 10+ tunnels comfortably.


Project Structure

gopher/
β”œβ”€β”€ cmd/server/
β”‚   β”œβ”€β”€ main.go                     # Entry point; embeds frontend
β”‚   └── frontend/dist/              # Compiled React app (embedded at build time)
β”œβ”€β”€ frontend/                       # React + TypeScript + Tailwind
β”‚   └── src/
β”‚       β”œβ”€β”€ pages/                  # Dashboard, Machines, Tunnels, Server, Setup
β”‚       └── components/             # UI components
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ api/                        # Chi router + HTTP handlers
β”‚   β”œβ”€β”€ config/                     # Caddyfile + rathole TOML generation
β”‚   β”œβ”€β”€ db/                         # SQLite (GORM) models + migrations
β”‚   β”œβ”€β”€ service/                    # Business logic (install, tunnels, firewall, …)
β”‚   └── ssh/                        # SSH client + VPS/machine deploy scripts
└── scripts/
    β”œβ”€β”€ build.sh                    # Build frontend then Go binary
    └── dev.sh                      # Dev mode with hot reload

Tech Stack

Backend: Go 1.21+, Chi router, GORM + glebarez/sqlite (pure-Go, no CGO), golang.org/x/crypto/ssh

Frontend: React 18 + TypeScript, Vite, Tailwind CSS β€” embedded in the binary via //go:embed

Infrastructure (managed by Gopher): Caddy 2 for HTTPS + routing, rathole for tunneling


Development

# Dev mode (hot reload on both frontend and backend)
./scripts/dev.sh
# Frontend: http://localhost:5173
# Backend:  http://localhost:8080

# Production build
./scripts/build.sh
./gopher

Contributing

Issues and PRs welcome. See open issues.

Areas that would help most:

  • Testing on different distros and VPS providers
  • Bug reports with reproduction steps

License

MIT β€” see LICENSE

Acknowledgments

Gopher is a thin management layer on top of two great projects: Caddy by Matt Holt and the team, and rathole (originally by rapiz1). Without them there is no Gopher.

Directories ΒΆ

Path Synopsis
cmd
server command
internal
api
db
ssh

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL