Skip to main content

Overview

Portless supports HTTP/2 over TLS (HTTPS) to significantly speed up dev servers that serve many unbundled files. Browsers limit HTTP/1.1 to 6 connections per host, which bottlenecks dev servers like Vite, Nuxt, and others. HTTP/2 multiplexes all requests over a single connection, eliminating this bottleneck. Portless automatically generates and manages TLS certificates using a local Certificate Authority (CA), and can trust them in your system keychain on first run.

Quick Start

1

Start proxy with HTTPS

On first run, portless will prompt for sudo once to add the CA to your system trust store. After that, no more prompts and no browser warnings.
2

Access your apps securely

All your portless apps now use HTTPS:

How It Works

When you start the proxy with --https, portless:
  1. Generates a local CA - Creates an elliptic curve (prime256v1) private key and self-signed CA certificate valid for 10 years
  2. Generates server certificates - Creates certificates signed by the CA for localhost and *.localhost (valid for 1 year)
  3. Starts an HTTP/2 server - Uses Node.js http2.createSecureServer with HTTP/1.1 fallback for WebSocket support
  4. Handles SNI - Generates per-hostname certificates on-demand for subdomains
Portless uses Server Name Indication (SNI) to generate certificates on-demand. Each subdomain (like myapp.localhost, api.myapp.localhost) gets its own certificate because *.localhost sits at the public-suffix boundary and TLS specs don’t permit wildcard certificates there (RFC 2606 §2).

Certificate Management

Automatic Generation

Certificates are stored in your state directory:
  • Port < 1024 (sudo mode): /tmp/portless/
  • Port >= 1024 (user mode): ~/.portless/
Files created:

Automatic Renewal

Portless checks certificate validity on startup and automatically regenerates:
  • Expired certificates
  • Certificates expiring within 7 days
  • Certificates using weak signatures (SHA-1)

Trusting the CA

If you skipped the sudo prompt on first run, trust the CA later:
On macOS, portless trust adds the CA to your login keychain. On Linux, it copies the CA to your distro’s trust store and runs the appropriate update command.

Supported Linux Distributions

Configuration

Using Environment Variables

Make HTTPS permanent by setting an environment variable:

Disabling HTTPS

If PORTLESS_HTTPS is set but you want to disable it for a specific session:

Using Custom Certificates

If you already have certificates (e.g., from mkcert):
Using --cert and --key automatically implies --https. You don’t need to specify both.

Real-World Examples

Development Workflow

Port 443 (No Port in URL)

Run on the standard HTTPS port to eliminate the port number from URLs:
Access apps at:
Ports below 1024 require sudo. The proxy will run as root, and state files move to /tmp/portless (shared between root and user processes).

Mixed HTTP/HTTPS

The proxy supports both HTTP and HTTPS connections simultaneously when started with --https. It inspects the first byte of each connection:
  • 0x16 (TLS ClientHello) → routes to HTTP/2 server
  • Other → routes to HTTP/1.1 server
This means you can access apps via both:

Environment Variables

Portless injects these variables into child processes:

Troubleshooting

Browser Shows Certificate Warning

The CA isn’t trusted yet. Run:

Permission Denied on Linux

Make sure you’re running with sudo:

Safari Not Loading HTTPS

Safari relies on the system DNS resolver. If you see certificate errors:
  1. Trust the CA:
  2. Add routes to /etc/hosts:

Certificate Expired

Portless automatically regenerates expired certificates on startup. If you see an expired certificate:
  1. Stop the proxy:
  2. Start with HTTPS:
Certificates are valid for:
  • CA: 10 years
  • Server certs: 1 year
  • Auto-renewal: 7 days before expiry

OpenSSL Not Found

Portless requires openssl to generate certificates. It ships with macOS and most Linux distributions. If it’s missing:

Technical Details

Certificate Specifications

CA Certificate:
  • Algorithm: ECDSA with prime256v1 curve
  • Signature: SHA-256
  • Validity: 10 years
  • Extensions:
    • basicConstraints=critical,CA:TRUE
    • keyUsage=critical,keyCertSign,cRLSign
Server Certificates:
  • Algorithm: ECDSA with prime256v1 curve
  • Signature: SHA-256
  • Validity: 1 year
  • Extensions:
    • basicConstraints=CA:FALSE
    • keyUsage=digitalSignature,keyEncipherment
    • extendedKeyUsage=serverAuth
    • subjectAltName=DNS:localhost,DNS:*.localhost (default cert)
    • Per-hostname certs include exact SAN + wildcard for same level

SNI (Server Name Indication)

For each subdomain, portless generates a certificate with:
  • The exact hostname (e.g., chat.myapp.localhost)
  • A wildcard for siblings at the same level (e.g., *.myapp.localhost)
This allows multiple subdomains to share a cached certificate while respecting TLS public-suffix boundary rules.

HTTP/2 + HTTP/1.1 Fallback

Portless uses http2.createSecureServer with allowHTTP1: true, which:
  • Enables HTTP/2 multiplexing for regular requests
  • Falls back to HTTP/1.1 for WebSocket upgrades
  • Strips hop-by-hop headers (Connection, Transfer-Encoding, etc.) when proxying to HTTP/1.1 backends

State Directory

Certificate location depends on proxy port:
Override with: