portless

repository·main·Indexed 27 days ago

https://github.com/vercel-labs/portless

A development proxy that provides clean HTTPS URLs (e.g., https://myapp.localhost) for local development. It features support for monorepos, git worktrees, and custom TLDs. Portless includes capabilities for LAN mode via mDNS, Tailscale sharing, and ngrok tunneling to make local services accessible across networks or the public internet.

Tokens
16.5K
Snippets
53
Records
122
Agent score
91%

What's inside portless

  1. Share dev servers via ngrok

    main

    Expose your dev server to the public internet using ngrok with the --ngrok flag.

    Requirements:

    • ngrok CLI must be installed and authenticated.
    • If authentication fails, run ngrok config add-authtoken <token>.

    Set PORTLESS_NGROK=1 in your shell profile or .env to enable ngrok by default.

    portless myapp --ngrok next dev
  2. Install Portless as an OS Startup Service

    main

    To ensure the Portless proxy starts automatically after a system reboot, use the service command. This installs a service in launchd (macOS), systemd (Linux), or Task Scheduler (Windows).

    Commands:

    • portless service install: Install with default settings.
    • portless service install --lan: Install with LAN mode enabled.
    • portless service status: Check the status of the installed service.
    • portless service uninstall: Remove the service.
    • portless clean: Automatically removes the service.

    Note: Installation may require administrator/root privileges to bind to port 443.

    portless service install
    portless service status
    portless service uninstall
  3. Configure proxying between Portless apps

    main

    When using a frontend dev server (like Vite or webpack) to proxy API requests to another Portless app, you must ensure the proxy rewrites the Host header. Failure to do this causes Portless to route the request back to the frontend, creating an infinite loop. Portless will respond with a 508 Loop Detected error if this misconfiguration is detected.

    To fix this, set changeOrigin: true in your proxy configuration.

    // Vite (vite.config.ts)
    server: {
      proxy: {
        "/api": {
          target: "https://api.myapp.localhost",
          changeOrigin: true,
          ws: true,
        },
      },
    }
  4. Portless system requirements

    main

    To use Portless, ensure your environment meets the following requirements:

    • Node.js: version 24 or higher
    • Operating Systems: macOS, Linux, or Windows
    • Optional CLI tools:
      • Tailscale CLI (required for --tailscale and --funnel features)
      • ngrok CLI (required for --ngrok feature)
  5. Configure Node.js to trust the Portless CA

    main

    Portless automatically sets NODE_EXTRA_CA_CERTS in child processes so Node.js trusts the Portless CA. If you are running a separate Node.js process outside of Portless that needs to make requests to Portless apps, you must manually point it to the CA using the NODE_EXTRA_CA_CERTS environment variable.

    Alternatively, you can use the --no-tls flag to use plain HTTP instead of HTTPS.

    NODE_EXTRA_CA_CERTS=~/.portless/ca.pem
  6. Run your app with Portless

    main

    Portless replaces port numbers with stable, named .localhost URLs. It automatically reads the dev script from your package.json and runs it through an HTTPS proxy.

    Automatic App Name Inference

    The app name is inferred from package.json, the git root, or the directory name. To override this, use a portless.json file (e.g., { "name": "myapp" }).

    Running Commands

    You can run the default dev script or provide an explicit command:

    • portless: Runs the dev script from package.json.
    • portless <app-name> <command>: Runs a specific command for a specific app name.

    HTTPS and Ports

    • HTTPS/HTTP/2: Enabled by default. On the first run, Portless generates and trusts a local CA and binds to port 443 (may require sudo on macOS/Linux).
    • Port Assignment: A random port (4000--4999) is assigned via the PORT environment variable. Most frameworks (Next.js, Express, Nuxt) respect this automatically. For frameworks that ignore PORT (Vite, Astro, React Router, Angular, Expo, React Native), Portless auto-injects the --port and --host flags.
  7. Configure Git Worktree support

    main

    Portless automatically detects git worktrees. In a linked worktree, the branch name is prepended as a subdomain, allowing each worktree to have a unique URL without manual configuration.

    • Main worktree: Uses the base name (e.g., https://myapp.localhost).
    • Linked worktree (branch fix-ui): Uses the branch prefix (e.g., https://fix-ui.myapp.localhost).

    To override the base name while preserving the worktree prefix, use the --name flag.

    # Main worktree
    portless run next dev
    
    # Linked worktree on branch "fix-ui"
    portless run next dev
    
    # Override base name while keeping worktree prefix
    portless run --name myapp next dev
  8. Configure Auth Libraries for Portless domains

    main

    To prevent OAuth libraries from constructing localhost callback URLs, you must explicitly set the base URL to match your Portless domain.

    NextAuth / Auth.js

    Set NEXTAUTH_URL (or AUTH_URL for Auth.js v5) in your environment:

    NEXTAUTH_URL=https://myapp.dev

    Passport.js

    Set the callbackURL in your strategy using a BASE_URL environment variable:

    new GoogleStrategy({
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: process.env.BASE_URL + "/auth/google/callback",
    });

    Set BASE_URL=https://myapp.dev in your .env.

    Generic / Manual

    Use the PORTLESS_URL environment variable which is automatically injected by Portless into the child process:

    const baseUrl = process.env.PORTLESS_URL || "http://localhost:3000";
    const callbackUrl = `${baseUrl}/auth/callback`;
  9. Organize services with subdomains

    main

    You can organize services using subdomains. By default, portless operates in strict mode where only explicitly registered subdomains are routed.

    Explicit subdomains:

    portless api.myapp pnpm start
    # -> https://api.myapp.localhost
    
    portless docs.myapp next dev
    # -> https://docs.myapp.localhost

    Wildcard subdomains: To allow any subdomain of a registered route to fall back to that app (e.g., tenant1.myapp.localhost routes to the myapp app), start the proxy with the --wildcard flag.

    portless proxy start --wildcard
    portless api.myapp pnpm start
  10. Configure Next.js for LAN mode

    main

    When using LAN mode (e.g., .local hostnames), you must add your hostnames to the allowedDevOrigins configuration in next.config.js to prevent errors.

    // next.config.js
    module.exports = {
      allowedDevOrigins: ["myapp.local", "*.myapp.local"],
    };