Lynx Proxy

June 4, 2026 · View on GitHub

English | 简体中文

Crates.io License Crates

Lynx Proxy is a Rust-based HTTP(S) / WebSocket proxy and traffic inspector for local development. Built on hyper, axum, and tower, it helps you inspect APIs, rewrite traffic with rules, inject scripts, and point static assets to local services — without installing a separate runtime.

Why Lynx

  • Single binary — install with one script; the Web UI ships inside the CLI.
  • Local-first — bind to loopback by default; your traffic stays on your machine.
  • Developer-oriented — list & tree views, DSL filters, rules, and a built-in Compose panel.

Features

Protocols & client

  • HTTP(S) and WebSocket(S) interception
  • Embedded Web UI (Vue 3 + Vite), light/dark theme, PWA-friendly
  • Real-time request stream over WebSocket

Network panel

  • Table view — sortable virtualized list with request/response detail
  • Tree view — group by host and path
  • DSL filter — filter captured traffic with match expressions
  • Focus / Ignore — quick capture filters from the toolbar or context menu

Rules

Each rule has a match expression (matchExpr), one or more actions (handlers), plus priority and enabled. The network panel DSL filter uses the same syntax as matchExpr; it only filters the UI list and does not rewrite traffic.

How matching runs

  • Every enabled rule whose matchExpr matches the request is included (not first-match-only).
  • Handlers from all matching rules are merged and run in executionOrder ascending (lower runs first).
  • Block and Local file can return a response during the request phase and skip the upstream call.
  • After the upstream response, Modify response, HTML script injector, Delay (afterRequest / both), and Throttle run again on the response body/stream.
flowchart LR
  req[IncomingRequest] --> match[Eval matchExpr on RequestFacts]
  match --> merge[Merge handlers from all matching rules]
  merge --> sort[Sort by executionOrder]
  sort --> reqHandlers[Request-phase handlers]
  reqHandlers -->|short-circuit| resp[Return synthetic response]
  reqHandlers -->|continue| upstream[Upstream fetch]
  upstream --> resHandlers[Response-phase handlers]

Focus / Ignore (toolbar or context menu) uses domain capture filters in Settings, not matchExpr. You can still right-click a request to copy cURL or create a rule from its URL.

matchExpr DSL

Expressions combine URL-like fragments with optional curl-style flags. Logical operators AND, OR, NOT (and and / or / not) and parentheses are supported. Line comments start with #.

FormExampleMeaning
Hostexample.comHost match (includes subdomains, e.g. api.example.com)
Host + portexample.com:8080Host and port
Path/api/v1Path prefix (/api also matches /api/foo)
Glob/api/*/v1, /api/**/trackSingle-segment * or multi-segment **
Full URLhttps://example.com/api?a=1Scheme, host, port, path, query
Query only?user_id=123Query parameter subset match (extra params allowed)
LogicA AND B, NOT A, (A OR B)Combine sub-expressions

curl-style flags (after a URL fragment; combined with AND):

FlagRole
-X / --requestHTTP method, e.g. -X POST
-H / --headerHeader equality, e.g. -H Authorization=Bearer (name case-insensitive)
-q / --queryQuery substring, e.g. -q foo=bar

Examples:

example.com AND /api/v1
https://example.com/health
httpbin.org AND -X POST
(example.com OR /api/) AND NOT https://example.com/health
NOT */rest/* AND -X POST
?operationName=GetFeed

Matching notes

  • Path-only expressions do not check host; query-only expressions do not check path.
  • Query embedded in a URL (?a=1&b=2) uses subset semantics; the live request may include more parameters.
  • Path matching ignores the query string when the expression has no ?… clause.
  • For origin-form requests (path-only URI), host and port come from the Host header.

Actions

A rule may attach multiple actions; use executionOrder to sequence them. Seed demo rules with task readme-demo (see scripts/fixtures/demo-rules.json).

ActionUse caseMain fields
Modify requestChange request before forwardmodifyHeaders, modifyMethod, modifyUrl, modifyBody
Modify responseChange response headers/body/statusmodifyHeaders, modifyBody, modifyStatusCode
BlockReturn an error without upstreamstatusCode, reason
DelaySimulate latencydelayMs, varianceMs, delayType (beforeRequest / afterRequest / both)
ThrottleBandwidth/latency presetpreset (Fast3G / Slow3G / Offline / Custom), optional downloadKbps, uploadKbps, latencyMs
Proxy forwardRewrite upstream targettargetScheme, targetAuthority, targetPath
Local fileRespond from diskfilePath, contentType, statusCode
HTML script injectorInject into HTML responsescontent, injectionPosition (head / body-start / body-end)

Example rule (modify request headers when POSTing to httpbin):

{
  "name": "Inject demo header",
  "enabled": true,
  "priority": 50,
  "capture": { "matchExpr": "httpbin.org AND -X POST" },
  "handlers": [{
    "handlerType": { "type": "modifyRequest", "modifyHeaders": { "X-Lynx-Demo": "readme" } },
    "executionOrder": 10,
    "enabled": true
  }]
}

Compose (API debug)

Send HTTP requests from the UI, edit params/headers/body, and inspect responses — similar to Postman, integrated with the same proxy session.

CLI

  • start / stop / restart — background daemon
  • run — foreground server (default port 7788)
  • status — process, port, and data directory

Cross-platform: Windows, macOS, Linux.

Screenshots

HTTP / HTTPS

HTTP proxy — table view with request detail

WebSocket

WebSocket frames in request detail

Tree view

Tree view grouped by host and path

Rules

Rule list and editor

Context menu

Quick actions from the traffic list

Copy and Focus submenus

Compose

Compose — send and debug requests

CLI status

$ lynx status
=== Lynx Proxy Service Status ===
PID: 101744
Port: 7788
Status: Running
Data Directory: ~/.local/share/lynx
Start Time: 1749816127 seconds since epoch
Process Running: Yes

Usage

Install

Prebuilt releases are published on GitHub Releases. The install scripts are named lynx-cli-installer.* (cargo-dist package name), but they install the lynx command.

Note (v0.4.8 and earlier): installers built before the repo rename still download binaries from suxin2017/lynx-server internally. The script URL can use either lynx-proxy or lynx-server — both hosts mirror the same release assets today. Future releases (after updating repository in Cargo.toml) will point entirely at lynx-proxy.

macOS / Linux (recommended)

curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/suxin2017/lynx-proxy/releases/latest/download/lynx-cli-installer.sh | sh

Windows (PowerShell)

powershell -ExecutionPolicy Bypass -c "irm https://github.com/suxin2017/lynx-proxy/releases/latest/download/lynx-cli-installer.ps1 | iex"

After install:

  • Binary: lynx (not lynx-cli)
  • Default location: ~/.cargo/bin/lynx — add it to your PATH if the installer did not
  • Verify: lynx --version

Manual download (from Releases):

PlatformArchive
macOS (Apple Silicon)lynx-cli-aarch64-apple-darwin.tar.xz
Linux (x64)lynx-cli-x86_64-unknown-linux-gnu.tar.xz
Windows (x64)lynx-cli-x86_64-pc-windows-msvc.zip

Intel Macs are not in the release matrix (avoids long macos-13 CI queues); use the Apple Silicon build under Rosetta or build from source. ARM Linux is not in the release matrix yet — build from source (see Development).

Build from source

git clone https://github.com/suxin2017/lynx-proxy.git
cd lynx-proxy
task build-ui && cargo install --path crates/lynx-cli

Quick start

  1. Start the proxy:

    lynx run
    
  2. Point your browser or app at http://127.0.0.1:7788 (or configure the system HTTP proxy).

  3. Open the Web UI at http://127.0.0.1:7788 and enable capture.

  4. Install the Lynx CA certificate from Settings when you need HTTPS decryption. For mobile Wi‑Fi proxy, use your computer's LAN IP (not 127.0.0.1).

Android one-click proxy (ADB)

In the web UI, open Rules drawer → Android to lazily install platform-tools (or use adb from PATH), list devices, and enable/disable the system HTTP proxy via ADB:

  • Same WiFi (LAN) — proxy host is your computer's LAN IP and Lynx port (not available with --local-only).
  • USB (adb reverse) — sets 127.0.0.1:<port> on the device after port forwarding.

HTTPS still requires installing the Lynx root CA from Settings. Disabling Lynx does not clear the phone proxy — use Disable proxy in the Android panel before exit.

Common commands

lynx run          # foreground, default port 7788
lynx start        # background daemon
lynx stop
lynx restart
lynx status

Options (run / start)

OptionDefaultDescription
--port7788Proxy listen port
--data-dirOS-specificRules and persistent data
--log-levelinfosilent, info, error, debug, trace
--connect-typessesse or short-poll
--local-onlyoffBind to loopback only

Default data directories:

  • Linux: ~/.local/share/lynx
  • macOS: ~/Library/Application Support/lynx
  • Windows: %APPDATA%\suxin2017\lynx\data

Development

Requires Rust, Node.js 20+, and Task.

task setup-ui    # npm ci in ui/
task dev         # proxy :7788 + Vite UI :5173

Other useful tasks:

TaskPurpose
task build-uiProduction UI build → embedded in CLI
task traffic-sampleSend sample HTTP(S) through the proxy
task readme-demoSeed demo traffic & rules for docs
task readme-screenshotsRegenerate images/*.png (uses system Chrome)

See ui/README.md for UI architecture and screenshot workflow.

Contributing

  1. Fork the repo and create a branch.
  2. task setup-ui && task dev
  3. Make changes; run task test and task lint when touching Rust.
  4. Open a Pull Request.

License

MIT — see LICENSE.

Feedback

Questions and ideas: GitHub Issues.

Status

Usable for daily development; features and UI are still evolving — contributions welcome.