Local Development

Tunnel Server Development Setup

Set up the Portr tunnel server for local development, so you can run and contribute to the SSH-based tunneling backend on your machine.

The tunnel server is built using Go and handles the server-selected client tunnel transport for HTTP/TCP connections. SSH is the default transport; WebSocket can be selected with PORTR_TRANSPORT=websocket.

Requirements

  • Go (1.25+)
  • PostgreSQL (16+) or SQLite (3.0+)

Setup Process

Configure environment variables

Create a new .env file using the .env.template file as a reference.

Start the server

go run ./cmd/portrd start tunnel

You should see output similar to:

time=2024-03-29T19:16:35.023+05:30 level=INFO msg="Starting SSH server" port=:2222
time=2024-03-29T19:16:35.023+05:30 level=INFO msg="starting proxy server" port=:8001
time=2024-03-29T19:16:35.023+05:30 level=INFO msg="Starting 1 cron jobs"

With the default PORTR_TRANSPORT=ssh, this starts:

  • SSH tunnel server on port :2222
  • Proxy server on port :8001 for wildcard HTTP and upgraded WebSocket traffic

With PORTR_TRANSPORT=websocket, the proxy also serves the WebSocket tunnel endpoint at /_portr/tunnel/connect instead of starting the SSH server.

When running the combined server with go run ./cmd/portrd start all, the admin server listens on :8000 by default and the selected tunnel transport listens on its configured port.

Server Architecture

The tunnel server consists of several components:

Tunnel Transport

  • Starts SSH or WebSocket based on PORTR_TRANSPORT
  • Handles incoming tunnel connections from clients
  • Authenticates clients using tokens

Proxy Server

  • Routes incoming HTTP requests to the appropriate tunnels
  • Handles subdomain routing
  • Manages SSL termination in production

Cron Jobs

  • Cleans up expired tunnel connections
  • Performs maintenance tasks

Development Workflow

Available Commands

# Start the server
go run ./cmd/portrd start tunnel

# Build Go packages
make buildgo

# Run tests
make testgo

# Format code
go fmt ./...

# Run linting
go vet ./...

Configuration

For all configuration variables, check out the tunnel server config file.

Key configuration options include:

  • Database connection: PostgreSQL connection string
  • Transport settings: PORTR_TRANSPORT, PORTR_SSH_URL, PORTR_WS_URL, and authentication
  • Proxy settings: HTTP server configuration
  • Security settings: Token validation and access control

Testing Tunnel Connections

Make sure the admin server is running before testing tunnel connections, as it handles client authentication.

Local Testing

  1. Start the admin server
  2. Start the tunnel server
  3. Build and run the client to create a test tunnel

Connection Flow

  1. Client reads transport from the generated config
  2. Client connects to ssh_url or ws_url based on that transport
  3. The selected tunnel transport validates the client token with the server
  4. HTTP tunnels register one or more workers; TCP tunnels register one remote TCP listener
  5. Proxy server routes incoming requests or TCP bytes to the client

Troubleshooting

Common Issues

Port conflicts: Ensure the selected transport port is available (2222 for SSH by default, 8001 for WebSocket/proxy by default).

Database connection errors: Verify your PostgreSQL instance is running and accessible.

Tunnel connection failures: Check that the generated client config matches the server transport and that the client has valid credentials.

Debugging

Enable tunnel debug logging with:

PORTR_TUNNEL_DEBUG=true

View detailed logs to troubleshoot connection issues:

# Follow server logs
go run ./cmd/portrd start tunnel