Skip to content

CLI

thq is the TunnelHQ command-line tool. Use it to test any VPN config, share link, or subscription URL from your terminal, manage monitors, Uptime checks, and API keys, and connect the MCP server to your AI editor. It runs on macOS, Linux, WSL, and Windows.

This page describes thq 0.4.0, the current release. Run thq --version to see yours.

The macOS / Linux installer needs nothing installed first: it brings its own Node.js (downloaded from nodejs.org and checked against its published checksums) and keeps it, with thq, in ~/.local/share/tunnelhq. It links thq into /usr/local/bin when run as root, otherwise into ~/.local/bin, which it adds to your PATH if needed. On Windows, and with npm install -g, thq needs Node.js 20 or newer.

Install on macOS, Linux, or WSL
curl -fsSL https://tunnelhq.com/install.sh | bash

thq login uses the device flow: run the command, approve the request in your browser, and you’re signed in. There’s no token to copy. Your credentials are saved to ~/.thq/credentials.json.

Sign in
thq login
Option Description
--no-browser Don’t open the browser; print the approval URL instead.
--qr Print a QR code for the approval URL. On by default when there’s no display, for example over SSH.
--no-qr Don’t print the QR code.
--host <url> Sign in to a different API host.

The approval is refused if your workspace’s plan doesn’t include API access, with the message “API access isn’t included on this workspace’s plan. Upgrade to use the CLI.”

The key thq login creates is an account-wide key, named “CLI · <computer name> · <date>”, which never expires.

thq logout removes the saved credentials and switches the key off on the server. The key stays on the API Keys page as Disabled; to delete it, choose Revoke there, or run thq keys revoke <id> --hard before you log out.

For CI and scripts, set an API key in the environment instead. When THQ_API_KEY is set, it’s used instead of the saved sign-in.

Use an API key in CI
export THQ_API_KEY="thk_..."

thq test checks a VPN config on the spot and saves nothing. The target can be a config file path, a share link, a raw config string, or an https:// subscription URL.

Test a config, a share link, or a subscription
thq test ./wg0.conf
thq test 'vless://<uuid>@vpn.example.com:443?security=reality&...'
thq test https://provider.example.com/sub --first 5 --json
Option Description
--json Machine-readable output, for CI.
--protocol <name> Force the protocol: wireguard, openvpn, ikev2, openconnect, vmess, vless, trojan, shadowsocks, amneziawg, hysteria2, or tuic.
--timeout <seconds> How long to wait. Default 30, minimum 5, maximum 120.
--host <hostname>, --port <number> Server host and port for IKEv2, OpenConnect, and OpenVPN (required for IKEv2 and OpenConnect). WireGuard, AmneziaWG, and share links use their own.
-u, --username; -p, --password Override the credentials.
--remote-id <id> Set the IKEv2 remote ID.
--engine <name> Force an engine: singbox, xray, auto, both, or race. By default, the checker picks one per protocol.
--first <n> Subscription URLs only: test the first n entries. Alias: --limit.
--index <n> Subscription URLs only: test one entry, counting from 1.

A subscription URL tests every entry unless you pass --first or --index.

IKEv2 and OpenConnect don’t need a config: pass the server and the credentials.

Test IKEv2 without a config
thq test --protocol ikev2 --host vpn.example.com -u alice -p secret

thq test works out the protocol from, in order:

  1. --protocol.
  2. The URI scheme, such as vless:// or ss://.
  3. The content: an [Interface] section is WireGuard, or AmneziaWG when it has Jc, Jmin, Jmax, or H1–H4 keys; client and remote lines are OpenVPN. So a .conf file that holds an OpenVPN config is tested as OpenVPN.
  4. The file extension: .conf is WireGuard, .ovpn is OpenVPN.
  5. An http:// or https:// address is a subscription URL.

thq test exits with 0 when the test passes and 1 when it fails, so you can use it in CI.

Tests run on the same checkers as scheduled monitors, through POST /check. They count toward your API rate limit, not your on-demand test quota.

thq servers manages the project’s saved monitors. Every thq servers and thq checks command works in the project in THQ_PROJECT_ID, or the one you pass with --project <id>, and takes --json.

Command Description
thq servers list List monitors. --family chooses tunnel (the default), uptime, or all. Filter with --status, --protocol, --search, and --active-only; --limit defaults to 100.
thq servers create <input> --name <name> Create a VPN monitor from a config file, share link, or raw config. It takes thq test’s connection options (--protocol, --host, --port, -u, -p, --remote-id), plus --proto udp or tcp for OpenVPN, --ip for a WireGuard or AmneziaWG config without an Endpoint line, --interval, --tag (repeat it for more), and --paused. For OpenConnect and IKEv2, leave out the input and pass --host, --username, and --password.
thq servers delete <id> --yes Delete a monitor or an Uptime check by its ID, srv_123 or 123. --yes is always required, with --json too.
Create monitors
thq servers create wg.conf --name "WG Frankfurt"
thq servers create 'vless://<uuid>@host:443' --name "VLESS EU"
thq servers create '' --protocol openconnect --name "OC Corp" \
--host vpn.example.com --username alice --password secret

thq checks list lists the project’s Uptime checks. Filter with --type, --status, --search, and --active-only; --limit defaults to 100.

thq checks create <target> --name <name> creates a check. Without --type, the target sets the type, the same way the dashboard does:

Target Creates
https://example.com or example.com/health A website check, with https:// added if it’s missing. With --keyword, a keyword check.
db.example.com:5432 or [2001:db8::1]:443 A TCP port check. --port overrides the port.
8.8.8.8 (an IP address) A ping check.
example.com (a bare hostname) A website check, with https:// added. Add --type ping to ping it instead.
1.1.1.1 --domain example.com A DNS check. The target is the DNS server; --keyword is text the answer must contain.
No target, with --period A heartbeat. The command prints the address your job calls.

Targets must be public addresses: private and reserved ones are refused.

Option Description
--type <type> http, keyword, ping, port, dns, or push (a heartbeat).
--keyword <text> Keyword check: text the page must contain. DNS check: text the answer must contain.
--invert-keyword Keyword check: alert when the text is found.
--accept <codes> Website and keyword checks: accepted status codes, such as 200-299,301. Default 200-299.
--port <n> TCP port check: the port.
--domain <name> DNS check: the domain to ask about.
--period <seconds> Heartbeat: the longest time between two calls from your job. Default 86400.
--grace <seconds> Heartbeat: how late a call can be before it’s down. Default 3600.
--interval <seconds> Seconds between checks. Left out, the recommended default.
--tag <name> Add a tag. Repeat it for more.
--paused Create the check paused.
Create Uptime checks
thq checks create https://example.com --name "Homepage"
thq checks create https://example.com/login --name "Login" --keyword "Sign in"
thq checks create db.example.com:5432 --name "Postgres"
thq checks create 1.1.1.1 --name "Resolver" --domain example.com
thq checks create --name "Nightly backup" --period 86400 --grace 3600

To change or pause a check, use the dashboard, the REST API, or the MCP server. To delete one, use thq servers delete.

Make a status page, choose what it shows, and post incidents and updates from a terminal or a script.

Command Description
thq status-pages list List the project’s status pages.
thq status-pages create <name> Make a page, a draft until you publish it in the dashboard. Without --services, --type, or --tag it shows the suggested set: tunnels and website checks that aren’t paused. --slug <slug> sets its address, <slug>.tunnelhq.net.
thq status-pages services <page> [--add …] [--remove …] [--hide …] [--show …] Add, remove, hide, or show many services at once. Removing takes a service off the page; the tunnel or check stays.
thq status-pages domain <page> <domain> Put the page on your own domain, such as status.example.com, and print the DNS record to add. --check looks the record up and switches on HTTPS once it points to TunnelHQ. --remove takes the domain off.
thq status-pages brand <page> [--use …] Take the logo, dark logo, favicon, and share image from the page’s website. --use saves only those you name: logo, logo_dark, favicon, share_image.
thq status-pages incidents <page> [--status open|resolved] List a page’s incidents, with their updates.
thq status-pages open <page> --title <text> --impact <impact> --service <service> --message <text> Open an incident. --impact is degraded, partial, or full. Repeat --service for each affected service. --status sets the first status: investigating (the default), identified, or monitoring.
thq status-pages update <page> <incident> --status <status> --message <text> Post an update. --status is investigating, identified, monitoring, or resolved; resolved closes the incident.

Every thq status-pages command works in the project in THQ_PROJECT_ID, or the one you pass with --project <id>, and takes --json.

  • <page> is the page’s ID (sp_12), its address (larkspur-vpn), or its name.
  • --service is a service’s ID (sps_40) or its name on the page, including a group’s members. If no service matches, the command fails and lists the page’s services instead of guessing.
  • A monitor for --services, --add, --remove, --hide, or --show is its ID (srv_42) or its name. A group’s name or ID brings its members.
  • create --services also takes suggested (the default) or none, for an empty page. --type and --tag add every monitor of a type, or with a tag, beside any you name. The types are tunnel, website, keyword, ping, port, dns, heartbeat, and group.
  • In services, an action given without names takes the monitors --type and --tag pick, as in --remove --type heartbeat.

A page shows up to 400 services, a server’s tunnels counting once. The commands print the count, such as “103 of 400 services”.

Make a page, then trim it
thq status-pages create "Larkspur VPN"
thq status-pages services larkspur-vpn --remove --type heartbeat
thq status-pages services larkspur-vpn --add srv_42 "API health" --hide "Old Frankfurt"
Put a page on your own domain, with your logo
thq status-pages domain larkspur-vpn status.larkspur.example
thq status-pages domain larkspur-vpn --check
thq status-pages brand larkspur-vpn
Open an incident, then resolve it
thq status-pages open larkspur-vpn --title "OpenVPN failing in Frankfurt" --impact partial --service "OpenVPN Frankfurt" --message "Connections are failing. We are looking into it."
thq status-pages update larkspur-vpn spi_7 --status resolved --message "Connections work again."

Publishing, the rest of a page’s look, and its password aren’t in the CLI: use the dashboard, the REST API, or the MCP server.

Plan maintenance windows from a terminal or a script. While one runs, checks and alerts pause for what it covers, and your status pages show it.

Command Description
thq maintenance list List the project’s windows, with when each runs, what it covers, and where it stands.
thq maintenance create <title> --start <when> --end <when> Plan a window. Name what it covers with --monitor, or use --covers tunnels, uptime, or all.
thq maintenance update <window> … Change a window: only what you give changes. --pause pauses it, --resume resumes it, --title renames it.
thq maintenance end <window> End a running one-time window now. Checks and alerts resume within a minute.
thq maintenance cancel <window> --yes Delete a window, planned or running. Without --yes, it only says what it would delete.
  • <window> is the window’s ID (mnt_4) or its title.
  • A one-time window takes --start and --end as YYYY-MM-DDTHH:mm. With --days, it repeats every week on those days, such as --days mon,wed,fri, and --start and --end are HH:mm. All seven days means every day.
  • --timezone is an IANA time zone, such as Europe/Berlin. Left out, it’s your computer’s.
  • --monitor is a monitor or group, by ID or name. Repeat it for more; a group brings its members.
  • --note adds a note shown with the window.
  • Every thq maintenance command works in the project in THQ_PROJECT_ID, or the one you pass with --project <id>, and takes --json.
Plan maintenance
thq maintenance create "Frankfurt upgrade" --start 2026-11-12T02:00 --end 2026-11-12T04:00 --timezone Europe/Berlin --monitor "OpenVPN Frankfurt"
thq maintenance create "Nightly backup" --days mon,wed,fri --start 02:00 --end 02:30 --covers uptime --timezone Asia/Karachi
thq maintenance update "Nightly backup" --pause

Choose where a monitor’s alerts go, and check that they arrive. New channels are made in the dashboard under Integrations, where their secrets are entered.

Command Description
thq channels list List the project’s alert channels, with each one’s type and whether it’s on.
thq channels show <monitor> The channels a check’s or tunnel’s alerts go to.
thq channels set <monitor> <channel>… Set the channels its alerts go to. This replaces its list, so name every channel it should keep.
thq channels set <monitor> --none Its alerts go to no channel.
thq channels test <monitor> Send a test alert through each of its channels, and show which took it.
  • <monitor> and <channel> are an ID (srv_12, chn_22) or a name. If two share a name, use the ID.
  • Setting channels and sending a test alert need a role that can edit monitors. A test reaches at most 10 channels, and you can send 10 test messages an hour.
  • Every thq channels command works in the project in THQ_PROJECT_ID, or the one you pass with --project <id>, and takes --json.
Route a check's alerts
thq channels set "Shop website" "Ops Slack" chn_22
thq channels test "Shop website"

Add servers, read them, and set their alerts from a terminal or a script.

Command Description
thq hosts install Print the command that installs the agent. --name and --group add a name and a group. --auto-update or --no-auto-update decides automatic updates; without either, the project’s default does. --rotate makes a new install key; servers already installed keep reporting.
thq hosts list List the project’s servers. Filter with --status, --group, --tag, --search, or --monitor, and order with --sort.
thq hosts get <id> One server in full: readings, system, linked tunnels and checks, alerts, and the uninstall command.
thq hosts history <id> A server’s readings over time. --metric is cpu by default, and --range is 1h, 6h, 24h (the default), or 7d.
thq hosts update <id> Change --name, --group, or --tags. "" clears any of them. --auto-update on or off switches automatic agent updates.
thq hosts update-agent <id> Update the server’s agent to the latest release now.
thq hosts link <id> <monitor> Link a tunnel or check to the server by hand.
thq hosts unlink <id> <monitor> Keep a tunnel or check away from the server, even when the address matches.
thq hosts alerts <id> Show the server’s alerts, or change them with the options below.
thq hosts incidents [<id>] Server incidents of the last 30 days, open first. --open shows only open ones.
thq hosts remove <id> --yes Remove the server from TunnelHQ. Its agent stays installed until you run the uninstall command.

thq hosts alerts changes only what you name:

Option Takes
--offline-after Seconds without a report before it alerts, 90 or more, or off.
--service-after Seconds a watched service is stopped before it alerts, or off.
--cpu, --memory, --disk A percent and seconds, such as 90:600 for above 90% for 10 minutes, or off.
--country on or off.
--cert 7, 14, 21, or 30 days before the certificate expires, or off. Needs agent 1.7.0.
  • <id> is a server’s ID (hst_7, or 7), and <monitor> a tunnel’s or check’s (srv_81).
  • Changing a server needs a role that can edit monitors, and removing one a role that can delete monitors.
  • Every thq hosts command works in the project in THQ_PROJECT_ID, or the one you pass with --project <id>, and takes --json.
Watch a server's disk and certificate
thq hosts alerts hst_7 --disk 85:300 --cert 21
thq hosts list --status offline
Command Description
thq keys list List your API keys.
thq keys create <name> [--expires <ISO date>] Create a workspace key. Keys created this way start with uk. Needs a workspace key in THQ_API_KEY: the account-wide key from thq login is refused. An --expires value that isn’t a date, such as 31/12/2026, is refused.
thq keys revoke <id> [--hard] Disable a key. With --hard, delete it permanently. The ID is the number, or the uk… form.

thq mcp prints the configuration for the MCP server, or applies it for you.

Option Description
--client <name> claude, cursor, windsurf, or cline.
--apply Apply the configuration: runs claude mcp add for Claude Code, or writes the JSON config for the other clients.
--update With --client, clear TunnelHQ’s cached MCP server and add it to that client again, so your editor gets the current release on its next start. Without --client, it changes nothing.
--json Print the configuration snippet and exit.
--api-key <value> Use this key in the configuration.
Command Description
thq whoami Show the account you’re signed in as.
thq doctor Diagnose connection and authentication problems.
thq upgrade Update the CLI. It detects whether you installed it with npm, Homebrew, or the install script. Alias: thq update.
thq install Reinstall the CLI to a stable location and add it to your PATH.

Run thq --help for every command and option.

Run thq with no arguments in an interactive terminal to open the slash-command interface. It doesn’t open when input or output is redirected, or when NO_COLOR is set.

Command Description
/test Test a VPN config, share link, or subscription URL.
/whoami Show your account, plan, and quota.
/keys list, create <name>, or revoke <id>.
/mcp Set up the MCP server.
/doctor Diagnose connection and authentication problems.
/upgrade Update the CLI.
/login, /logout Sign in or out.
/help List every command.
/exit Quit.
Variable Description
THQ_API_KEY API key to use instead of the saved sign-in.
THQ_HOST API host. Defaults to https://dev.tunnelhq.com.
THQ_PROJECT_ID Default project.
THQ_ORG_ID Default workspace.
THQ_HEADLESS 1 or 0 to force headless mode on or off.
THQ_SKIP_UPDATE_CHECK 1 to skip the background check for a newer version.
THQ_INSTALL_DIR Where thq install puts the CLI. Defaults to ~/.local/bin, or %LOCALAPPDATA%\TunnelHQ\bin on Windows.