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.
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.
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
Hostheader - 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.jsinstead ofhttps://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>
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
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.
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.
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-urlswith 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
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:
- Create PR with
meticulous-debugin the title - Meticulous will keep the secure tunnel open
- You'll receive a comment with tunnel access credentials
- 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.
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.
Error: "Failed to establish tunnel connection"
Common causes:
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 readyWrong port: Verify the port matches your running app
# Check which port your app is using netstat -tuln | grep LISTENFirewall blocking: Ensure outbound HTTPS (443) is allowed
Error: "Tunnel request timeout"
Solutions:
Increase HTTP/2 connections:
--http2Connections=16Use companion assets for large static files
Check app startup time: Increase sleep duration after starting app
Problem: Some resources fail to load during tests
Debugging steps:
Enable request printing:
--printRequestsCheck if requests are reaching the tunnel
Check proxy-all-urls: If assets are on a different port, enable
proxy-all-urlsUse companion assets: For static assets, use companion assets instead of proxying
Verify relative URLs: Ensure your app uses relative URLs, not absolute URLs
Error: "SSL certificate problem: self signed certificate"
Solutions:
Provide certificate files (recommended):
--localCert=./cert.pem --localKey=./key.pem --localCa=./ca.pemAllow invalid certificates (development only):
--allowInvalidCert
- 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"
#!/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
npx @alwaysmeticulous/cli ci start-tunnel \
--apiToken="$METICULOUS_API_TOKEN" \
--port=3000 \
--http2Connections=16 \
--enableDnsCache \
--proxyAllUrls
npx @alwaysmeticulous/cli ci start-tunnel \
--apiToken="$METICULOUS_API_TOKEN" \
--port=3000 \
--printRequests \
--proxyAllUrls
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
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
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-httpswith certificate options - High concurrency: Tune
http2-connections - Debugging: Use
print-requestsormeticulous-debuglabel
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.