Quick start
Three commands take a site running on your computer to a public HTTPS address:
# 1. Install (macOS / Linux; see below for Windows)
$ curl -fsSL https://connect.getwebup.in/install.sh | sh
# 2. Connect the CLI to your account (copy the token from the dashboard)
$ getwebup config add-authtoken <YOUR_AUTHTOKEN>
# 3. Expose http://localhost:3000
$ getwebup http 3000The CLI shows the public URL, for example https://brave-otter-3f9a.tunnel.devai.in, and every request it forwards. Press Ctrl+C to stop the tunnel. No account yet? Sign up for free and copy your authtoken from the dashboard.
Installation
Getwebup is a single self-contained binary for Windows, macOS and Linux on x86-64 and ARM. The install scripts download the right build from this site, verify its SHA-256 checksum and put it on your PATH.
Windows
Run this in PowerShell (no administrator rights needed):
PS> irm https://connect.getwebup.in/install.ps1 | iexIt installs getwebup.exe to %LOCALAPPDATA%\getwebup and adds that folder to your user PATH. Open a new terminal afterwards so the PATH change takes effect.
macOS and Linux
$ curl -fsSL https://connect.getwebup.in/install.sh | shThe script detects your system with uname (Intel and Apple silicon Macs; Linux on x86-64, ARM64 and ARMv7), installs to /usr/local/bin (using sudo when needed) or to ~/.local/bin when sudo is not available. Set GETWEBUP_INSTALL_DIR to choose another folder.
Manual download
Download the binary for your platform from the downloads page, rename it to getwebup (getwebup.exe on Windows), make it executable and put it in a folder on your PATH. Check the installation with:
$ getwebup versionConnect your account
The CLI identifies your account with an authtoken. Your first one is shown right after sign-up; create more on the Authtokens page. Save it once per machine:
$ getwebup config add-authtoken <YOUR_AUTHTOKEN>This writes the token to the config file in your user profile:
| System | Config file |
|---|---|
| Windows | %AppData%\getwebup\getwebup.yml |
| macOS | ~/Library/Application Support/getwebup/getwebup.yml |
| Linux | ~/.config/getwebup/getwebup.yml |
Run getwebup config check to validate the file and print the settings in effect (the token is masked). In CI or containers, set the GETWEBUP_AUTHTOKEN environment variable or pass --authtoken instead; both override the file.
Getwebup Cloud API key
Getwebup Cloud customers connect with their existing Getwebup API key from cloud.getwebup.in instead of an authtoken. Save it without showing it on screen:
$ getwebup config add-api-keyThe CLI asks for the key with hidden input; getwebup config add-api-key - reads it from standard input instead, so it never appears in a command line. The install scripts save it for you when GETWEBUP_API_KEY is set, or ask for it with hidden input:
$ curl -fsSL https://connect.getwebup.in/install.sh | sh # then paste the key at the promptThe key is only ever sent to the Getwebup control server it was saved for, over HTTPS; the CLI refuses other servers unless you pass --trust-server. In CI, set GETWEBUP_API_KEY (GETWEBUP_AUTHTOKEN wins when both are set).
HTTP tunnels
$ getwebup http <address> [flags]Forwards a public HTTPS address to a local web server. WebSockets, server-sent events, uploads and streaming responses work unchanged. The address can be:
| Address | Forwards to |
|---|---|
| 3000 | http://localhost:3000 |
| localhost:8080 | http://localhost:8080 |
| 192.168.1.20:80 | a web server on another machine in your network |
| https://localhost:8443 | a local HTTPS server (self-signed certificates are accepted) |
| Flag | Description |
|---|---|
| --subdomain NAME | Use a subdomain you reserved, giving https://my-app.tunnel.devai.in for my-app. See reserved subdomains. |
| --domain HOST | Serve the tunnel on a verified custom domain such as dev.example.com. See custom domains. |
| --basic-auth USER:PASS | Ask visitors for a username and password. Repeat the flag to allow several users. |
| --host-header VALUE | rewrite sends the local address as Host, any other value is sent as is. Default: the public hostname. See host header rewriting. |
| --inspect=false | Do not record this tunnel's traffic in the request inspector (default true). |
| --name NAME | Label of the tunnel in the CLI and the dashboard. |
| --verify-upstream-tls | Check the certificate of an https:// local address. Off by default because local certificates are usually self-signed. |
Examples:
# a random address, for example brave-otter-3f9a.tunnel.devai.in
$ getwebup http 3000
# your reserved subdomain, protected with a password
$ getwebup http 8080 --subdomain my-app --basic-auth "demo:correct-horse"
# a local HTTPS app on your own domain, with the Host header rewritten
$ getwebup http https://localhost:8443 --domain dev.example.com --host-header rewriteRandom addresses are kept when the CLI reconnects after a network hiccup. For an address that never changes, reserve a subdomain or use a custom domain.
TCP tunnels
$ getwebup tcp <address> [--remote-port PORT] [--name NAME]Forwards a public tcp://tcp.tunnel.devai.in:PORT address to any TCP service: SSH, databases, RDP, game servers, MQTT and more. Without --remote-port you get a random port in the range 20000–29999. To keep the same port, reserve it on the TCP Addresses page and pass it with --remote-port. TCP tunnels are available on paid plans.
# SSH into this machine from anywhere
$ getwebup tcp 22
# Forwarding tcp://tcp.tunnel.devai.in:24012 -> localhost:22
$ ssh -p 24012 you@tcp.tunnel.devai.in
# PostgreSQL on a reserved address
$ getwebup tcp 5432 --remote-port 24012Config file and getwebup start
Define the tunnels you use every day in the config file and start them together. Tunnel names are up to you; each tunnel accepts the same options as the flags above.
# getwebup.yml
authtoken: <YOUR_AUTHTOKEN>
web_addr: 127.0.0.1:4040 # request inspector; "false" turns it off
tunnels:
web:
proto: http
addr: "3000"
subdomain: my-app
api:
proto: http
addr: https://localhost:8443
domain: api.example.com
host_header: rewrite
basic_auth:
- "demo:correct-horse"
docs:
proto: http
addr: "4000"
inspect: false
ssh:
proto: tcp
addr: "22"
remote_port: 24012$ getwebup start web api # start the named tunnels
$ getwebup start --all # start every tunnel in the fileKeys: proto (http or tcp), addr, subdomain, domain, remote_port, basic_auth, host_header and inspect. Unknown keys are reported as errors so typos never go unnoticed; run getwebup config check after editing. Use --config path to use another file.
Global flags
| Flag | Description |
|---|---|
| --config PATH | Use another config file. |
| --authtoken TOKEN | Authtoken for this run (overrides GETWEBUP_AUTHTOKEN and the config file). |
| --server URL | Getwebup server to connect to (overrides GETWEBUP_SERVER and the config file). |
| --web-addr ADDR | Inspector address, default 127.0.0.1:4040; false disables it. |
| --log DEST | Write logs to stdout, stderr, none or a file. Logging to stdout replaces the full-screen status view, which is handy in scripts and containers. |
| --log-level LEVEL | debug, info, warn or error. |
| --log-format FORMAT | text or json. |
Request inspector
While the CLI runs, open http://127.0.0.1:4040 on the same machine. It lists every request that went through your HTTP tunnels, newest first, with method, path, status and duration. Select a request to see its headers and the request and response bodies (JSON is pretty-printed).
- Replay sends the captured request to your local app again, which is ideal for debugging webhooks: fix your code, then replay the exact payload without asking the sender to retry.
- Copy as cURL gives you a command line that reproduces the request.
- Clear empties the list. The inspector keeps the last 200 requests in memory only; nothing is stored on disk or sent to Getwebup.
The inspector only listens on your own machine. If port 4040 is in use (for example by a second getwebup), pass --web-addr 127.0.0.1:4041. Turn it off with --web-addr false, or for one tunnel with --inspect=false.
Reserved subdomains
On paid plans you can reserve subdomains of tunnel.devai.in so that a tunnel always gets the same address, which is useful for OAuth callbacks, webhooks and links you shared with clients.
- Open Domains in the dashboard and reserve a name, for example my-app.
- Start the tunnel with it: getwebup http 3000 --subdomain my-app.
- Your site is online at https://my-app.tunnel.devai.in, and nobody else can use that address.
Names are 3 to 63 lowercase letters, digits and dashes. Some names (such as www, api or admin) are reserved by Getwebup.
Custom domains
Paid plans can serve tunnels on a domain you own, with an HTTPS certificate issued automatically.
- Open Domains and add your hostname, for example dev.example.com.
- At your DNS provider, create the two records shown in the dashboard:
| Type | Name | Value | Purpose |
|---|---|---|---|
| CNAME | dev.example.com | custom.tunnel.devai.in | Sends visitors to Getwebup |
| TXT | _getwebup-challenge.dev.example.com | getwebup-verify=<token from the dashboard> | Proves that you own the domain |
- Click Verify. The domain is marked Verified once the TXT record is visible; DNS changes usually take a few minutes, sometimes up to an hour.
- Start the tunnel: getwebup http 3000 --domain dev.example.com. The certificate is obtained on the first HTTPS request, which can take a few seconds.
Root domains (example.com without a subdomain) cannot have a CNAME record at most providers. Use your provider's ALIAS, ANAME or CNAME-flattening feature pointing to custom.tunnel.devai.in, or use a subdomain. If your provider appends the zone name automatically, enter only the part before it, for example _getwebup-challenge.dev.
Password protection
Keep work in progress private by requiring a username and password. Getwebup checks the credentials at the edge, before any request reaches your machine:
$ getwebup http 3000 --basic-auth "client:preview-2024" --basic-auth "me:another-secret"Browsers show a login prompt; tools such as curl use curl -u client:preview-2024 https://brave-otter-3f9a.tunnel.devai.in. Use long, unique passwords: basic authentication is only as strong as the password.
Host header rewriting
By default your app receives the public hostname in the Host header (for example brave-otter-3f9a.tunnel.devai.in), and X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto describe the original request. Some development servers only answer to their own name and reply with errors such as "Invalid Host header" or a default virtual host. Rewrite the header in that case:
# send "localhost:8080" as the Host header
$ getwebup http 8080 --host-header rewrite
# send a fixed name, for a local virtual host
$ getwebup http 80 --host-header myproject.testBandwidth and limits
Each plan has a monthly bandwidth quota (traffic in both directions through all your tunnels, reset on the first day of each month, UTC), a throughput limit shared by your tunnels, a number of tunnels that can be online at once, and per-tunnel request and connection limits. The pricing page lists them and your Usage page shows where you stand. The CLI and the dashboard warn you at 80% of the quota; at 100% your tunnels show a "Bandwidth limit reached" page until the quota resets or your plan is upgraded.
Troubleshooting
Visitors see a warning page first
On plans with the visitor warning page (the Free plan by default), people who open your tunnel in a browser first see a short page explaining that the site is served through Getwebup, with a Visit site button. It protects everyone against phishing and is remembered for 7 days per browser. API clients, webhooks and scripts are not affected because the page is only shown to browsers. To skip it from your own code or tools, send the request header getwebup-skip-browser-warning with any value:
$ curl -H "getwebup-skip-browser-warning: 1" https://brave-otter-3f9a.tunnel.devai.inPlans without the warning page never show it; compare plans on the pricing page.
Error pages served by Getwebup
| Code | Meaning | What to do |
|---|---|---|
| GW-404 | Unknown host. | Check the address for typos; random addresses change when a tunnel is restarted after a while. |
| GW-OFFLINE | No tunnel is online on this address. | Start the CLI again. Reserved subdomains and custom domains come back on the same address. |
| GW-502 | The CLI could not reach your local app. | Make sure the app is running and listening on the port you gave the CLI, for example open http://localhost:3000 on your machine. For HTTPS apps include the scheme: getwebup http https://localhost:8443. |
| GW-CONNS | Too many simultaneous connections for your plan. | Wait for open connections to finish or upgrade your plan. |
| GW-RATE | Too many requests per minute for your plan. | Requests are accepted again within a minute. |
| GW-QUOTA | The monthly bandwidth quota is used up. | Wait for the reset on the first of the month or upgrade your plan. |
The CLI cannot connect
- Authentication failed: the authtoken was revoked or mistyped. Create a new one on the Authtokens page and run getwebup config add-authtoken again.
- Tunnel limit reached: your plan allows a fixed number of online tunnels across all your machines. Stop one on the Tunnels page or with Ctrl+C.
- Subdomain or domain errors: --subdomain only accepts names reserved by your account and --domain only verified domains. Check the Domains page.
- Firewalls and proxies: the CLI only needs outgoing HTTPS (port 443) to https://connect.getwebup.in. It honours the HTTPS_PROXY environment variable.
- Network drops: the CLI reconnects automatically with back-off and keeps your random address when it can. Run with --log stdout --log-level debug to see what happens.
REST API
Automate your account with the JSON API at https://connect.getwebup.in/api/v1. Authenticate every request with an authtoken in the Authorization header; we recommend a dedicated token per integration.
$ export GETWEBUP_AUTHTOKEN=<YOUR_AUTHTOKEN>
# your account, plan and usage
$ curl -H "Authorization: Bearer $GETWEBUP_AUTHTOKEN" https://connect.getwebup.in/api/v1/me
# tunnels online right now
$ curl -H "Authorization: Bearer $GETWEBUP_AUTHTOKEN" https://connect.getwebup.in/api/v1/tunnels
# reserve a subdomain
$ curl -X POST -H "Authorization: Bearer $GETWEBUP_AUTHTOKEN" \
-H "Content-Type: application/json" -d '{"subdomain":"my-app"}' \
https://connect.getwebup.in/api/v1/domains
# stop a tunnel
$ curl -X DELETE -H "Authorization: Bearer $GETWEBUP_AUTHTOKEN" https://connect.getwebup.in/api/v1/tunnels/<TUNNEL_ID>| Endpoint | Description |
|---|---|
| GET /me | Account, plan limits and this month's usage. |
| GET /tunnels | Your online tunnels. |
| DELETE /tunnels/{id} | Stop one of your tunnels. |
| GET /domains | Reserved subdomains and custom domains, with DNS records. |
| POST /domains | Reserve {"subdomain":"my-app"} or add {"hostname":"dev.example.com"}. |
| POST /domains/{id}/verify | Check the DNS records of a custom domain. |
| DELETE /domains/{id} | Release a subdomain or remove a custom domain. |
| GET /tcp-addresses | Your reserved TCP addresses. |
| POST /tcp-addresses | Reserve a TCP address: {"port":0} picks a free port. |
| DELETE /tcp-addresses/{id} | Release a TCP address. |
| GET /usage | Bandwidth this month, per day. |
| GET /authtokens | Your authtokens (never the secret value). |
| POST /authtokens | Create a token: {"name":"ci"}. The response contains the token once. |
| DELETE /authtokens/{id} | Revoke a token. |
Requests and responses use JSON; send Content-Type: application/json with a body. Times are RFC 3339 in UTC. Errors use the HTTP status code and a body such as {"error":{"code":"limit_reached","message":"..."}}, where message is safe to show to people.