Self-hosted · HTTP(S) & TCP · v0.15.0

Your own ngrok on a server you own.

Two binaries — seikan-server (public edge) and seikan (client). One outbound TLS+yamux tunnel exposes services behind NAT/firewalls.

your machine
$ seikan serve app.example.com 3000
✓ https://app.example.com is live → localhost:3000

No inbound ports. Browser-trusted HTTPS. The client just dials out.

How it works

A public server and a client that lives next to your service. The client dials out to the server over one TLS connection — so nothing needs an open inbound port.

Public internet
Browser & TCP clients

Hit https://app.example.com or a public TCP port.

Seikan server
Public host

Terminates HTTPS (per-domain Let's Encrypt) and raw TCP, routes by Host, and serves the admin API.

⇅ one TLS + yamux tunnel
Seikan client
Behind NAT / firewall

Dials out, authenticates with a token, and forwards to localhost:3000.

1

Run the server

Start seikan-server on a public host. It gets HTTPS automatically and exposes an authenticated admin API. Create a frontend (an HTTPS domain or a TCP port) and it hands back a connect token.

2

Connect the client

The client dials the server's tunnel port and authenticates with the token — outbound only. It works behind NAT, double-NAT, and restrictive firewalls. No port-forwarding, ever.

3

Traffic flows

Public requests to your domain or port are proxied over the multiplexed tunnel to the client, which forwards them to your local service. Drops reconnect automatically.

Secure by design. The tunnel is TLS with the server authenticated against the public CA chain, and each client attaches with a 256-bit per-frontend connect token (stored only as a hash). Secrets never travel in cleartext.

Everything you'd expect — and you own it

No third party in the path of your traffic. No per-tunnel limits or seat pricing.

Automatic HTTPS

Per-domain Let's Encrypt certificates issued on demand — browser-trusted, no manual renewals.

Raw TCP passthrough

Expose SSH, Postgres, Redis, MQTT or a game server on a stable public port — end-to-end if the app brings its own TLS.

Works behind NAT

The client dials out, so home-labs and office boxes go public with zero inbound ports and no port-forwarding.

Multi-tenant

Issue scoped sub-tokens; each tenant manages only their own frontends. Revoking cascades cleanly.

Scale & failover

Run several clients on one frontend: HTTP load-balances with sticky sessions; TCP runs active/standby with automatic failover.

Self-hosted

You hold the certificates and the data in an embedded database. No external services, no vendor in the loop.

Two static binaries

Server and client, no runtime dependencies. One command installs each and sets up a hardened systemd service.

Hardened by default

Runs as an unprivileged user under a locked-down systemd unit; hashed secrets and per-IP brute-force lockout.

What people use it for

Anywhere you'd reach for a tunnel to put something local on the public internet.

Dev previews & demos

Share a work-in-progress on a real, browser-trusted HTTPS URL — your own domain — without deploying.

Webhook development

Receive Stripe, GitHub, or Slack webhooks straight to code on your laptop, over HTTPS, with no redeploys.

Home-lab & behind NAT

Expose an office or home service with no inbound ports — works behind double-NAT and strict firewalls.

Remote TCP services

Reach SSH, Postgres, Redis, RDP or MQTT on a stable public port — a simple VPN-free link between networks.

AI agent & tool callbacks

Let a cloud AI platform call back into a local tool, MCP server, or function endpoint during development.

Zero-downtime scale-out

Run several clients on one frontend for rolling restarts across machines, with sticky sessions and failover.

Ready to run your own tunnel?

The full installation guide for the server and client lives in the docs — each installs with a single command.

# on your public host curl -fsSL https://hub.okonomi.cloud/p/seikan/server/linux/amd64 | sudo sh