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.
Install
Section titled “Install”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.
curl -fsSL https://tunnelhq.com/install.sh | bashIn PowerShell 5.1 or newer:
irm https://tunnelhq.com/install.ps1 | iexOr install the package with npm directly:
npm install -g https://tunnelhq.com/releases/latest/tunnelhq-cli.tgzSign in
Section titled “Sign in”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.
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.
export THQ_API_KEY="thk_..."Test a config
Section titled “Test a config”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.
thq test ./wg0.confthq 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.
thq test --protocol ikev2 --host vpn.example.com -u alice -p secretthq test works out the protocol from, in order:
--protocol.- The URI scheme, such as
vless://orss://. - The content: an
[Interface]section is WireGuard, or AmneziaWG when it hasJc,Jmin,Jmax, orH1–H4keys;clientandremotelines are OpenVPN. So a.conffile that holds an OpenVPN config is tested as OpenVPN. - The file extension:
.confis WireGuard,.ovpnis OpenVPN. - An
http://orhttps://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.
Manage monitors
Section titled “Manage monitors”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. |
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 secretManage Uptime checks
Section titled “Manage Uptime checks”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. |
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.comthq checks create --name "Nightly backup" --period 86400 --grace 3600To change or pause a check, use the dashboard, the REST API, or the MCP server. To delete one, use thq servers delete.
Manage status pages
Section titled “Manage status pages”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.--serviceis 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--showis its ID (srv_42) or its name. A group’s name or ID brings its members. create --servicesalso takessuggested(the default) ornone, for an empty page.--typeand--tagadd every monitor of a type, or with a tag, beside any you name. The types aretunnel,website,keyword,ping,port,dns,heartbeat, andgroup.- In
services, an action given without names takes the monitors--typeand--tagpick, 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”.
thq status-pages create "Larkspur VPN"thq status-pages services larkspur-vpn --remove --type heartbeatthq status-pages services larkspur-vpn --add srv_42 "API health" --hide "Old Frankfurt"thq status-pages domain larkspur-vpn status.larkspur.examplethq status-pages domain larkspur-vpn --checkthq status-pages brand larkspur-vpnthq 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.
Manage maintenance
Section titled “Manage maintenance”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
--startand--endasYYYY-MM-DDTHH:mm. With--days, it repeats every week on those days, such as--days mon,wed,fri, and--startand--endareHH:mm. All seven days means every day. --timezoneis an IANA time zone, such asEurope/Berlin. Left out, it’s your computer’s.--monitoris a monitor or group, by ID or name. Repeat it for more; a group brings its members.--noteadds a note shown with the window.- Every
thq maintenancecommand works in the project inTHQ_PROJECT_ID, or the one you pass with--project <id>, and takes--json.
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/Karachithq maintenance update "Nightly backup" --pauseManage alert channels
Section titled “Manage alert channels”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 channelscommand works in the project inTHQ_PROJECT_ID, or the one you pass with--project <id>, and takes--json.
thq channels set "Shop website" "Ops Slack" chn_22thq channels test "Shop website"Manage servers
Section titled “Manage servers”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, or7), 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 hostscommand works in the project inTHQ_PROJECT_ID, or the one you pass with--project <id>, and takes--json.
thq hosts alerts hst_7 --disk 85:300 --cert 21thq hosts list --status offlineManage API keys
Section titled “Manage API keys”| 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. |
Set up the MCP server
Section titled “Set up the MCP server”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. |
Other commands
Section titled “Other commands”| 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.
Interactive REPL
Section titled “Interactive REPL”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. |
Environment variables
Section titled “Environment variables”| 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. |