Advanced Tunnel Options

Overview

When testing a locally running app, Meticulous uses a secure tunnel to connect the cloud test environment to your CI runner. This guide covers advanced tunnel configuration options for complex scenarios.

For most apps, the default tunnel settings work without configuration. Use these advanced options only when you have specific requirements.


Common Tunnel Options

proxy-all-urls

What it does: Allows requests to any URL to be proxied through the tunnel, not just requests to your app URL.

Default: false (only app-url is proxied)

When to use:

  • Your app makes requests to multiple servers/ports
  • You have a separate API server on a different port
  • Your app communicates with a local backend service

Example: Multi-Server Application

Scenario: Your frontend runs on localhost:3000 and your API runs on localhost:8080.

Without proxy-all-urls:

  • Frontend requests (http://localhost:3000): Proxied
  • API requests (http://localhost:8080): Not proxied

With proxy-all-urls:

  • Frontend requests (http://localhost:3000): Proxied
  • API requests (http://localhost:8080): Proxied

GitHub Actions Configuration

- name: Serve frontend
  run: |
    pnpm start &
    sleep 3

- name: Serve API
  run: |
    pnpm start:api &
    sleep 2

- name: Run Meticulous tests
  uses: alwaysmeticulous/report-diffs-action/cloud-compute@v1
  with:
    api-token: ${{ secrets.METICULOUS_API_TOKEN }}
    app-url: "http://localhost:3000"
    proxy-all-urls: "true"

CLI Usage

npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appUrl="http://localhost:3000" \
  --proxyAllUrls

With proxy-all-urls enabled, all HTTP/HTTPS requests from the browser will attempt to proxy through the tunnel. This may add latency if your app makes requests to external services that should remain external.


rewrite-hostname-to-app-url

What it does: Rewrites the hostname in request headers to match your app URL hostname.

Default: false

When to use:

  • Your HTML contains absolute URLs that need rewriting
  • Your server validates the Host header
  • You're testing a deployed build that references production URLs

Example: Absolute URLs in HTML

Problem: Your production build contains:

<script src="https://production.example.com/app.js"></script>

During tests, you want this to load from http://localhost:3000/app.js.

Solution: Use rewrite-hostname-to-app-url to rewrite the hostname.

GitHub Actions Configuration

- name: Run Meticulous tests
  uses: alwaysmeticulous/report-diffs-action/cloud-compute@v1
  with:
    api-token: ${{ secrets.METICULOUS_API_TOKEN }}
    app-url: "http://localhost:3000"
    rewrite-hostname-to-app-url: "true"

When NOT to Use

You don't need this if:

  • Your HTML uses relative URLs (/app.js instead of https://example.com/app.js)
  • Your app dynamically determines URLs based on window.location
  • You're already using companion assets for static files

Preferred alternative: Use relative URLs in your HTML.

<!-- Instead of this: -->
<script src="https://example.com/dist/app.js"></script>

<!-- Use this: -->
<script src="/dist/app.js"></script>

HTTPS Support

local-https

What it does: Configures the tunnel to connect to a local HTTPS server instead of HTTP.

Default: false

When to use:

  • Your app requires HTTPS (e.g., uses HTTPS-only features like Service Workers)
  • You're testing HTTPS-specific functionality
  • Your development server only runs on HTTPS

Basic HTTPS Configuration

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --localHttps

Self-Signed Certificates

If your local HTTPS server uses a self-signed certificate, you have two options:

Option 1: Provide Certificate Files (Recommended)

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --localHttps \
  --localCert="./certs/server.crt" \
  --localKey="./certs/server.key" \
  --localCa="./certs/ca.crt"

Parameters:

  • --localCert: Path to certificate PEM file
  • --localKey: Path to certificate key file
  • --localCa: Path to certificate authority file (for self-signed certs)

Option 2: Allow Invalid Certificates

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --localHttps \
  --allowInvalidCert

Warning: --allowInvalidCert disables certificate validation. Only use in development environments.

GitHub Actions Example with HTTPS

- name: Generate self-signed certificate
  run: |
    mkdir -p certs
    openssl req -x509 -nodes -days 1 -newkey rsa:2048 \
      -keyout certs/server.key -out certs/server.crt \
      -subj "/CN=localhost"

- name: Serve app with HTTPS
  run: |
    pnpm serve:https &
    sleep 5

- name: Run Meticulous tests
  uses: alwaysmeticulous/report-diffs-action/cloud-compute@v1
  with:
    api-token: ${{ secrets.METICULOUS_API_TOKEN }}
    app-url: "https://localhost:3000"
  env:
    # Note: GitHub Actions doesn't directly support these flags
    # Use the CLI command instead for HTTPS scenarios
    LOCAL_HTTPS: "true"
    ALLOW_INVALID_CERT: "true"

Note: For complex HTTPS scenarios, it's often easier to use the CLI command directly in a script rather than the GitHub Action.


Performance Options

http2-connections

What it does: Number of HTTP/2 connections to establish for request multiplexing.

Default: Number of CPU cores

When to use:

  • Your app makes many concurrent requests
  • You want to optimize tunnel throughput
  • You're experiencing tunnel performance issues

Configuration

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --http2Connections=8

Tuning guidelines:

  • Low concurrency apps (< 10 requests): Use default or lower value (2-4)
  • High concurrency apps (> 50 requests): Increase to 8-16
  • Very high concurrency: Up to 32 connections

Monitoring Impact

# Start tunnel with custom connection count
npx @alwaysmeticulous/cli ci start-tunnel \
  --port=3000 \
  --http2Connections=16 \
  --printRequests

Compare test run times with different values to find optimal setting.


enable-dns-cache

What it does: Enables DNS caching for tunnel requests.

Default: false

When to use:

  • The tunnel makes requests to non-localhost domains
  • Your app proxies requests to external APIs
  • You're using proxy-all-urls with external services

Configuration

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --proxyAllUrls \
  --enableDnsCache

When NOT to use:

  • All requests are to localhost (default scenario)
  • Your app doesn't make external requests

Debugging Options

print-requests

What it does: Logs all requests passing through the tunnel.

Default: false

When to use:

  • Debugging tunnel issues
  • Verifying which requests are proxied
  • Troubleshooting companion assets configuration
  • Understanding request flow

Example Output

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --printRequests

Sample output:

Your url is: https://abc123.meticulous.ai
user: meticulous, password: ******

Tue Feb 11 2026 10:30:45 GET /
Tue Feb 11 2026 10:30:46 GET /assets/app.js
Tue Feb 11 2026 10:30:46 GET /assets/styles.css
Tue Feb 11 2026 10:30:47 POST /api/login

GitHub Actions: meticulous-debug Label

For GitHub Actions workflows, add meticulous-debug to your PR title to enable advanced debugging:

  1. Create PR with meticulous-debug in the title
  2. Meticulous will keep the secure tunnel open
  3. You'll receive a comment with tunnel access credentials
  4. Connect to the tunnel to debug your app

Example PR title:

[meticulous-debug] Fix login flow

What you can do:

  • Access your app through the secure tunnel URL
  • Inspect network requests in browser DevTools
  • Test your app in the exact environment where tests run
  • Debug CI-specific issues

The tunnel is protected with HTTP Basic Authentication. Meticulous will provide credentials in a PR comment visible only to users with repository access.


Advanced Configuration

secure-tunnel-host

What it does: Configures a custom tunnel server host.

Default: Meticulous' production tunnel server

When to use: This is an advanced option intended for use by the Meticulous team only.

GitHub Actions

- name: Run Meticulous tests
  uses: alwaysmeticulous/report-diffs-action/cloud-compute@v1
  with:
    api-token: ${{ secrets.METICULOUS_API_TOKEN }}
    app-url: "http://localhost:3000"
    secure-tunnel-host: "tunnel.custom-domain.com"

Note: Most users should not set this option. Contact Meticulous support if you think you need a custom tunnel host.


Common Tunnel Failures

Tunnel Connection Failed

Error: "Failed to establish tunnel connection"

Common causes:

  1. App not running: Ensure your app is running before starting the tunnel

    - name: Start app
      run: |
        pnpm start &
        sleep 5  # Wait for app to be ready
    
  2. Wrong port: Verify the port matches your running app

    # Check which port your app is using
    netstat -tuln | grep LISTEN
    
  3. Firewall blocking: Ensure outbound HTTPS (443) is allowed

Tunnel Timeout

Error: "Tunnel request timeout"

Solutions:

  1. Increase HTTP/2 connections:

    --http2Connections=16
    
  2. Use companion assets for large static files

  3. Check app startup time: Increase sleep duration after starting app

Assets Not Loading Through Tunnel

Problem: Some resources fail to load during tests

Debugging steps:

  1. Enable request printing:

    --printRequests
    

    Check if requests are reaching the tunnel

  2. Check proxy-all-urls: If assets are on a different port, enable proxy-all-urls

  3. Use companion assets: For static assets, use companion assets instead of proxying

  4. Verify relative URLs: Ensure your app uses relative URLs, not absolute URLs

Certificate Errors with HTTPS

Error: "SSL certificate problem: self signed certificate"

Solutions:

  1. Provide certificate files (recommended):

    --localCert=./cert.pem --localKey=./key.pem --localCa=./ca.pem
    
  2. Allow invalid certificates (development only):

    --allowInvalidCert
    

Complete Configuration Examples

Basic Multi-Server Setup

- name: Start frontend
  run: |
    pnpm start:frontend &

- name: Start API
  run: |
    pnpm start:api &

- name: Wait for services
  run: sleep 5

- name: Run Meticulous tests
  uses: alwaysmeticulous/report-diffs-action/cloud-compute@v1
  with:
    api-token: ${{ secrets.METICULOUS_API_TOKEN }}
    app-url: "http://localhost:3000"
    proxy-all-urls: "true"

HTTPS with Self-Signed Certificate

#!/bin/bash

# Generate certificate
openssl req -x509 -nodes -days 1 -newkey rsa:2048 \
  -keyout server.key -out server.crt \
  -subj "/CN=localhost"

# Start HTTPS server
pnpm start:https &
sleep 5

# Run tests
npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appUrl="https://localhost:3000" \
  --localHttps \
  --localCert="./server.crt" \
  --localKey="./server.key" \
  --allowInvalidCert

High-Performance Configuration

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --http2Connections=16 \
  --enableDnsCache \
  --proxyAllUrls

Debugging Configuration

npx @alwaysmeticulous/cli ci start-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --port=3000 \
  --printRequests \
  --proxyAllUrls

CLI Reference Summary

ci start-tunnel Command

npx @alwaysmeticulous/cli ci start-tunnel [options]

Required:

  • --port / -p: Port of your local server

Common Options:

  • --apiToken: Meticulous API token
  • --localHost / -l: Tunnel to this host (default: localhost)
  • --proxyAllUrls: Proxy all URLs, not just app URL (default: false)
  • --printRequests: Log all requests (default: false)

HTTPS Options:

  • --localHttps: Connect to HTTPS server (default: false)
  • --localCert: Path to certificate file
  • --localKey: Path to key file
  • --localCa: Path to CA file
  • --allowInvalidCert: Ignore certificate errors (default: false)

Performance Options:

  • --http2Connections: Number of HTTP/2 connections (default: CPU cores)
  • --enableDnsCache: Enable DNS caching (default: false)

Advanced Options:

  • --rewriteHostnameToAppUrl: Rewrite request hostnames (default: false)
  • --host / -h: Custom tunnel server host
  • --subdomain / -s: Request specific tunnel subdomain

Decision Tree: When to Use Tunnel Options

START: Do you need advanced tunnel configuration?

├─ App on multiple ports/servers?
│  └─ YES → Use proxy-all-urls: true
│
├─ App requires HTTPS?
│  └─ YES → Use localHttps with certificate files or allowInvalidCert
│
├─ HTML has absolute URLs?
│  ├─ Can change to relative URLs? → YES → Change URLs (preferred)
│  └─ Cannot change URLs? → YES → Use rewrite-hostname-to-app-url
│
├─ Large static assets slowing tunnel?
│  └─ YES → Use companion assets (not tunnel options)
│
├─ Many concurrent requests?
│  └─ YES → Increase http2-connections (8-16)
│
├─ Proxying to external domains?
│  └─ YES → Use enableDnsCache + proxyAllUrls
│
└─ Debugging tunnel issues?
   └─ YES → Use printRequests or meticulous-debug PR label

Summary

Most users don't need tunnel options. The defaults work for standard apps.

Common scenarios:

  • Multi-server apps: Use proxy-all-urls
  • HTTPS apps: Use local-https with certificate options
  • High concurrency: Tune http2-connections
  • Debugging: Use print-requests or meticulous-debug label

Prefer alternatives when possible:

  • Use relative URLs instead of rewrite-hostname-to-app-url
  • Use companion assets for large static files instead of proxying
  • Use localhost/HTTP in CI instead of HTTPS when possible

For additional help, contact Meticulous support or check the troubleshooting guide.