Connect your AI tools to free models through a gateway you control.
Switch providers, choose how requests leave your network, and see every request from one dashboard.
Install · Connect a client · Screenshots · Downloads
Your tools keep one base URL and one key. Polygate picks the model, moves to another when one is busy, and sends each request out through the exit you chose.
| What you get | |
|---|---|
| Free providers, built in | OpenCode Free and Kilo Free, with their current catalogs. Add a Z.ai (ZCode) account or any OpenAI-compatible API beside them. |
| One address for your tools | OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages endpoints. |
| Automatic model selection | Use auto, auto:smart, or auto:fast; Polygate can try another model when one is busy or rate-limited. Or name your own chain (my-coding: try model A, then B, then C). |
| Control your connection | Direct access, HTTP/SOCKS proxies, a verified proxy pool (from public lists or your own list links), WARP, Psiphon, and deployable relays. |
| One MCP address for your tools | Add MCP servers once; every AI client gets all their tools from /mcp with its Polygate key, reached through your own routes. |
| A coding agent in the app | The Windows app has an Agent workspace: sessions per folder, permission modes, each turn's changed files with Undo. It runs on the models your gateway already serves. |
| Limits that hold | Client keys can carry a token budget, a per-minute limit, an expiry and a model list. A request that cannot fit is refused, not cut short. |
| See what is happening | Model availability, request timing, a searchable log of everything the gateway does, usage by day, and a Playground for real requests: conversations, side-by-side model comparison, tool and reasoning output, speed and token figures. |
| Run it your way | Portable Windows app, Linux service with a manager, or Docker. Built-in HTTPS is available on servers. |
Note
Free models have provider limits and changing availability. Polygate helps you manage access; it cannot guarantee capacity or remove provider limits. Follow each provider’s terms.
The pictures follow your GitHub theme: the dashboard has a light and a dark side too. They show a demo setup with invented traffic and example model names; your own catalog comes from your providers.
![]() Overview. The address and key to paste into your tool, the last 24 hours, each provider's health, and what failed and why. |
![]() Routing map. Drag a line from a provider to an exit. Thicker lines carry more traffic; a paused line keeps its place. |
![]() Models. Check one model or a whole provider. A model that did not answer shows the reason and when it last worked. |
![]() Playground. Send a real request through your gateway and see which model answered, how fast, and through which exit. |

Usage. Requests, tokens and failures per day for up to a year, by model, route or key.
Copy these two commands into your server’s terminal:
curl -fsSL https://raw.githubusercontent.com/B3hnamR/Polygate/main/install.sh -o install.sh
sudo bash install.sh- Press Enter to start. The installer checks the machine and installs missing dependencies.
- Choose how to open the dashboard: a domain, the server’s IP with HTTPS, your existing web server, your own certificate, or a local SSH tunnel.
- Review the plan and confirm. Open the Dashboard address shown at the end and sign in with the supplied password.
Run polygate any time to open the server manager.
Tip
The curl command is silent when it succeeds: it saves install.sh. The second command starts the installer.
To check the machine first, run sudo bash install.sh --check.
Requirements: Linux with systemd and glibc, on x86-64 or ARM64. Ubuntu, Debian, Fedora/RHEL, Arch, and openSUSE families are supported. Alpine and environments without systemd should use Docker. ARM64 packages are built with each release; running them on ARM64 hardware has not yet been verified.
Advanced install options, HTTPS choices, and server changes
The installer opens with the Polygate banner and waits for you to press Enter. Then it checks the machine and installs what is missing in one quiet step (details go to /var/log/polygate-install.log; only problems are shown), asks how you want to open the dashboard, shows a short summary and asks once more before it installs. It needs systemd and glibc (Alpine and containers without systemd should use Docker). When it finishes, run polygate any time to open the manager.
What it checks: your Linux version and CPU, free disk space and memory, the clock, internet access, which tools are missing (it installs only those, and nothing is upgraded), whether ports 80 and 443 are already used and by which program, and whether anything on the machine would clash with the names it uses.
It does not disturb your other services. It never stops, restarts or edits another service, and it never changes your firewall. It only creates /opt/polygate, /etc/polygate, /var/lib/polygate, a polygate system user, polygate.service and the polygate command. If any of those names already belong to something else, it stops and changes nothing.
It asks how you want to open the dashboard:
| Choice | What you get | Needs |
|---|---|---|
| A domain name, with automatic HTTPS | https://your.domain/polygate/ with a free Let's Encrypt certificate that renews itself |
the domain points at the server; ports 80 and 443 free |
| The server's IP address, with automatic HTTPS | https://1.2.3.4/polygate/ with a free short-lived certificate that renews itself |
a public IPv4 address; ports 80 and 443 free |
| Behind the web server I already run | Polygate listens on 127.0.0.1 only; a ready-made nginx and Caddy snippet is shown |
your own web server |
| My own certificate files | HTTPS with your certificate, on port 443 or another port you choose | certificate and key (PEM) |
| No HTTPS | listens on 127.0.0.1 only; open it through an SSH tunnel |
nothing |
Automatic HTTPS needs ports 80 and 443 for good (80 for renewals and the redirect, 443 for the dashboard). If another program already holds them, the installer says which one and shows the command to stop it permanently, or you pick behind the web server I already run and nothing is stopped. If a firewall is active it only prints the commands you may want to run; open the same ports in your hosting provider's panel if it has its own firewall.
Without questions (for scripts), anything you do not give takes the safe default (local only):
sudo bash install.sh --yes --https domain --domain panel.example.com --email you@example.com
sudo bash install.sh --yes --https ip
sudo bash install.sh --yes --https proxy --domain panel.example.com
sudo bash install.sh --yes --https custom --cert fullchain.pem --key privkey.pem --https-port 8443
sudo bash install.sh --update # newer release, keeps your data, settings and certificatesbash install.sh --help lists every option. The dashboard is served at /polygate/ (set POLYGATE_DASHBOARD_PATH to another path, or to an empty value for the root), so on a shared domain only that one path belongs to Polygate. The password is shown once at the end and kept in /var/lib/polygate/admin-password.txt.
- Download the Windows app — choose
Polygate-<version>-Windows-x64.exe. - Run it. It is portable: no installer or administrator access is needed.
- The dashboard opens inside the app. Copy your connection details into an AI tool, or try the Playground.
The API stays at http://127.0.0.1:4317/v1 from one launch to the next (if another program holds that port, the app picks a free one once and keeps it). Closing the window keeps Polygate running in the tray so your tools keep working; right-click the tray icon and choose Exit to stop it, or turn this off in Settings → Desktop app.
Compact view. Press Compact view in the header (or Ctrl+Shift+M, or the tray menu) to shrink the app into a small portrait window you can keep beside your work. It shows whether the gateway is online, the route, the success rate and speed, and your latest requests, with buttons to pause it and copy the base URL or API key. It stays on top of other windows (turn that off with the pin), and the app remembers where each view was.
The app is currently unsigned, so Windows may show SmartScreen. Download from this repository’s release page and verify the executable against the supplied .sha256 file. App data is kept in %LOCALAPPDATA%\Polygate.
From a machine with Docker Compose and Git:
git clone https://github.com/B3hnamR/Polygate.git
cd Polygate
docker compose up -d --buildOpen http://127.0.0.1:4317. Retrieve the generated dashboard password with:
docker compose exec polygate cat /data/admin-password.txtTo choose your own password before the first start, set POLYGATE_ADMIN_PASSWORD in your shell or a local .env file. Docker publishes port 4317 on loopback only and keeps data in a named volume.
Docker with built-in HTTPS
docker compose -f docker-compose.yml -f docker-compose.https.yml up -d --buildThis also publishes ports 80 and 443. Enable HTTPS in Settings; both ports must be free and reachable. For an existing reverse proxy, keep the default Compose file and forward requests to Polygate.
Client setup · Guide in the app · Providers · Agent · MCP hub · Network routes and relays · HTTPS · Server manager · Privacy · Troubleshooting · Development
Open Overview → Connect your client. Copy the base URL and client API key into your tool, then set the model to auto. The API key starts with pg_; it is different from your dashboard password.
Tip
The Windows app and Linux installer can choose a free port. Copy the address from your own dashboard instead of assuming port 4317.
| Base URL | http://127.0.0.1:<port>/v1 on your computer, or https://your.domain/polygate/v1 on a server (/v1 also works at the root) |
| API key | one of the keys on the Overview page (they start with pg_) |
| OpenAI Chat | POST /v1/chat/completions |
| OpenAI Responses | POST /v1/responses |
| Anthropic Messages | POST /v1/messages (send the key as x-api-key or as a Bearer token) |
| Model list | GET /v1/models |
curl http://127.0.0.1:4317/v1/chat/completions \
-H "Authorization: Bearer pg_your_key" -H "Content-Type: application/json" \
-d '{"model":"auto","messages":[{"role":"user","content":"Say hello"}],"stream":true}'from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:4317/v1", api_key="pg_your_key")
print(client.chat.completions.create(model="auto", messages=[{"role": "user", "content": "Hi"}]).choices[0].message.content)Choosing a model
model |
Meaning |
|---|---|
auto |
highest-ranked usable model, with fallback attempts for supported failure types |
auto:smart |
prefers reasoning and larger models |
auto:fast |
prefers the models that answered fastest |
my-coding (a chain you create) |
your own list, tried in your order: see below |
kilo/kilo-auto/free, opencode/<name> |
an exact model: the provider, then its model id (see /v1/models) |
Chains. Open Chains and press New chain: name it (for example my-coding) and list up to 8 models in the order you want them tried. A step can also be auto, auto:smart or auto:fast. Clients then use that name as the model. Polygate asks the first model that is ready; if it is resting, refuses the request (401, 403, 404, 429, 5xx) or is full, it moves to the next. A request the client got wrong (such as a 400) is not retried on other models. The reply names the model that answered in x-polygate-model, the chain in x-polygate-chain and anything it passed over in x-polygate-skipped; the Logs page shows the same. A key limited to some models reaches only those models inside a chain.
auto looks at the request. When a request uses tools, has an image, or is longer than a model's context, auto (and the auto steps of a chain) pass over models whose listing says they cannot handle that, and the answer names them: the x-polygate-skipped header and the Logs page say, for example, opencode/a (no tool support). A model is skipped only when its listing says so; an unknown ability never excludes it, and if no model is listed as able, the best ones are tried anyway, because provider metadata is not always right. A model you name yourself, or put in a chain on purpose, is never swapped out.
Preview routing. On Chains and in the Playground, Preview routing shows which models a request would try, in order, and why each other one is skipped (route resting, key not allowed, no tool support, resting until a time). Nothing is sent to a model, so no allowance is used. It reads the current settings and known health; it cannot promise that a provider will accept the next real request.
Ready, and the recovery checklist. The header says Ready only when a request could succeed right now: a usable model, a client key that can be used, and a route that would really be chosen. Otherwise it says Needs attention and the Overview page lists what is wrong, what it means and a button for the fixes that are safe (refresh the catalog, try a resting route again, reconnect WARP). A problem stays on the list until its cause is gone; one that is fixed while the page is open shows as resolved until you dismiss it. The list never switches anything on for you, so a route you turned off, such as Direct, stays off.
Your client’s key is never sent to a provider. Streaming and tool support depend on the selected provider and model. Manage client key limits, expiry, and model allowlists in Settings. A key with a token budget or a per-minute limit is held to it strictly, which rules out a few request types for that key; docs/API.md lists them.
Responses continuation through previous_response_id is not implemented; send conversation input explicitly. The real OpenCode server adapter supports text conversations rather than native tool execution.
| Provider | What it is | Good to know |
|---|---|---|
| OpenCode Free | built in | OpenCode has a daily allowance per network address. When an address is used up, Polygate moves to another exit if you have one, and says when the limit resets. |
| Kilo Free | built in; every model Kilo marks free, no account needed | Kilo limits anonymous use per network address. When that happens all Kilo models rest for 30 minutes (the answer says so and carries Retry-After). A single busy model rests for 2 minutes while the others keep working. You can save a Kilo API key on its row. Kilo models rank behind OpenCode's in auto and take over when OpenCode's are resting. |
| OpenAI-compatible | add any endpoint that has /v1/chat/completions |
needs a base URL and, usually, a key |
| Z.ai (ZCode) | built in, off until you add an account | Import an account under Providers → Z.ai (ZCode) and choose the active one. Each model has its own quota and reset time, shown on the page. When a model's quota runs out it rests until the reset and the other models keep working. Polygate never switches accounts by itself. |
| OpenCode server | an OpenCode you run yourself (opencode serve), reached over its own REST API |
uses the providers and logins configured in that OpenCode; model ids are provider/model as that server lists them; text conversation only (no tool calls) |
Built-in providers can be switched off but not deleted. Refresh catalog on the Models page loads each provider's current list and removes models it retired or made paid; if the list cannot be read, the previous one is kept. A model's priority and score can be changed on the Models page, which can also show one provider's models at a time. Models are not probed in the background by default (a probe is a real request that uses up allowance); press Check on a model to test it, or Check all for every model of one provider. A run stops as soon as the provider asks to slow down; a model that is only out of its own allowance is passed over and the rest are still checked. A model whose check got a temporary refusal stays in use, and its row shows the reason and when it last answered. Each provider can also be checked automatically every hour, 6 hours or day: one model at a time, waiting 15 minutes after a slow-down, and including unavailable models so one that comes back is found.
The Windows app has an Agent workspace at the top of the side menu: a coding agent (the OpenCode 2.3.0 engine, which Polygate downloads from npm, verifies against its published hash and runs for you) working in folders you allow, on the models your gateway serves.
- Sessions by folder. Each session keeps its own folder, model and mode. A message sent while the agent works steers it; Ctrl+Enter queues it for the end of the turn.
- Permission modes. The agent asks before it writes or runs commands, or works without asking in Full access, which you switch on with a confirmation. Polygate's own folders stay closed to it in every mode.
- Undo. Each turn lists the files it changed. Undo puts them back and keeps edits you made yourself in the meantime. Folder backups for Undo are off until you turn them on in the Agent settings.
- OpenCode Free models can be used only while the engine and the gateway present the same OpenCode version; a model that cannot be used says why in the list.
Add your MCP servers once on the MCP page; every AI client then connects to one address and gets all their tools, named server__tool, plus a few of Polygate's own (polygate__gateway_status, list_models, list_routes, test_route, recent_errors, read_logs, list_mcp_servers).
claude mcp add --transport http polygate http://127.0.0.1:4317/mcp --header "Authorization: Bearer pg_your_key"The page has ready-to-paste settings for Claude Code, Cursor, Codex, OpenCode, VS Code and Claude Desktop, and can import the mcpServers block other tools use. /mcp/<name> offers one server alone, with its tools' own names.
- Remote servers (Streamable HTTP, or HTTP + SSE for older ones) are reached through the route you choose: direct, a proxy, the proxy pool or WARP. Their headers and keys are stored encrypted and never shown again.
- Local programs (
npx …,uvx …) can be added in the Windows app. On a server they are added only from the server itself,sudo polygate mcp add-local NAME COMMAND ARGS, never from the web dashboard, so the dashboard password alone cannot run commands on your server. - Each server can be limited to some client keys, single tools can be hidden, and every tool call is on the Logs page (tool names, timing and errors; not what was sent).
A route is the path a request takes to the provider. Pick one on the Routing page, and give a provider its own route if it needs one.
In the side menu, Routing opens a sub-menu: Proxies, Relays, WARP and Psiphon, each with its own settings. The Routing page itself lists every exit, the one in use, and the policy for exits that are used up or cannot connect.
The Routing page has two views of the same settings. List shows the exits and switches one under another. Map shows providers and exits as nodes joined by lines: drag from a provider to an exit (or back) to join them, drag the dot near a line's end to move it to another exit, click a line to pause or remove it, and pause any node from its own button. A paused line keeps its place and is not used. Z.ai keeps one steady address: Direct, or one proxy of your own. Relays, the proxy pool, WARP and Psiphon change address between requests, so they are not offered for it. The map works from the keyboard through its side panel.
- Direct: your own connection.
- HTTP / SOCKS proxy: your own proxy, or the verified proxy pool: Polygate downloads public lists, tests them with real model requests, and keeps the ones that work. Under My proxies and lists you can paste proxies and links to lists (plain
ip:port,socks5://…,user:pass@ip:port,ip:port:user:pass, web-page tables, JSON), or save list links that every search downloads before (or instead of) the public lists. - Cloudflare WARP: a built-in MASQUE tunnel over HTTP/2, using a bundled helper built from usque (MIT). It changes nothing on the machine: no network interface, route, DNS or firewall rule, only a local SOCKS port on
127.0.0.1that Polygate's own requests use. If another program already uses that port (Cloudflare's ownwarp-cliand some xray setups use 40000), Polygate picks the next free one and never touches the other program. It needs outbound TCP 443 and normal DNS access, and splits the first part of the TLS handshake on networks that reset it (names inside the tunnel are looked up through8.8.8.8and9.9.9.9, not Cloudflare's own resolver; the helper program can be changed only in the Windows app, or on a server with the admin token), so it works where WireGuard/UDP is blocked. Cloudflare's WARP exit addresses are shared, so a service can still rate-limit an exit while the tunnel itself is healthy. - Psiphon: tick the regions you want under Routing → Psiphon and press Connect. Polygate runs Psiphon's own client (bundled, GPL-3.0, from Psiphon Inc.'s official builds) once per region, each on its own local SOCKS port, and together they are one route named Psiphon. Choose Take turns (each request uses the next connected region) or Stay on one region. When OpenCode Free or Kilo says a region's exit is used up, the request goes on through the next region, and the region reconnects for a new address that is checked with that same provider before it carries that provider's requests again (at most three new addresses an hour per region). Other providers keep using the region meanwhile. Test checks every connected region through its own exit. Update servers connects once to fetch Psiphon's current servers and regions. Each request line in Logs names the region it went through (
via Psiphon NL), and a line under Logs → Psiphon says when a request moved from one region to another and why. Like WARP it changes nothing on the machine. It runs on Windows and Linux x86-64; Psiphon publishes no Linux arm64 client. - Relays: one click on the Relays page deploys a small forwarding function to your own Vercel, Netlify or Cloudflare account. The platform token is used for the deploy and is kept only if you tick Remember this token (encrypted with your other settings, never shown again; the dialog can forget it). On Vercel you can tick several regions and deploy them one after another. A relay Polygate deployed can be updated to the current relay code from its row, and deleting it can remove its project, site or Worker from the platform as well. A table on the Relays page shows how each relay has done (worked, refused, redirected, failed), so a region that never works can be replaced.
Press Test on a route to send one small request through it with the provider you pick. The result names the model that was asked and passes only when the answer finished; another model can still be refused.
When OpenCode answers a request with its limit, Polygate checks the same exit with one small request (DeepSeek 4.1 Flash first, then GLM 5.3 Flash, MiniMax M3.1 Flash, then any other model). Refused there too: the exit is used up, it is set aside until the reset and the request moves to the next exit. Accepted: only this request was refused, so it is asked again with fewer tools and then through other exits, and the exit stays in use for everything else.
| Relay | OpenCode Free | Kilo |
|---|---|---|
| Vercel (Bun runtime) | yes, streams | yes |
| Netlify | yes, answers arrive in one piece (30 s limit) | yes |
| Cloudflare Worker | no (OpenCode refuses its TLS handshake) | yes, streams |
Every relay has its own access token and forwards to any public HTTPS host, so it carries OpenCode, Kilo and the providers you add yourself (the Cloudflare one carries Kilo and your providers, not OpenCode, which refuses it). Set POLYGATE_ALLOWED_HOSTS on a relay to narrow the hosts. An older relay only knows the OpenCode and Kilo hosts: press Update on the Relays page.
When a route's exit is used up, Polygate moves to another healthy exit if you allow it. Rotation is off by default. A relay that is used up is not written off for the day: relays can come back on a fresh address, so Polygate asks it again once or twice a few seconds apart (recycling it first when it runs the Polygate template), and then leaves it until the next check, which runs every 10 minutes. Requests keep using other exits meanwhile. Switch this off with Ask a used-up relay again for a fresh address under Routing policy.
Which relay? For OpenCode, Vercel is the best choice: it streams answers, runs on Bun (the handshake OpenCode checks), and Polygate can switch it to a fresh outbound address when one is used up. Deploy one in a region near you and a second elsewhere as a backup. Netlify is for light, short requests only: its answers are buffered (nothing arrives until the whole answer is ready), a function is stopped after 30 seconds, and some networks block netlify.app. Cloudflare carries Kilo only.
Switching Direct off. Press Disable on the Direct connection row to make sure requests never leave from your own network address (useful when that address must stay clean). Polygate then sends everything through your other routes, and Direct cannot be selected, used as a fallback or used by MCP. It needs at least one other route to be on, and it cannot be switched off while it is the selected route or a provider is pinned to it. Polygate's own update checks and the WARP registration still connect directly.
On a server Polygate can serve HTTPS itself. The Linux installer sets it up, or later run:
sudo polygate https domain panel.example.com you@example.com # certificate for a domain
sudo polygate https ip # short-lived certificate for the server's IP
sudo polygate https custom fullchain.pem privkey.pem # your own certificate
sudo polygate https statusCertificates come from Let's Encrypt, renew by themselves, and need the validation request to reach port 80. Polygate keeps ports 80 and 443 while this is on,
so use behind my web server (POLYGATE_TRUST_PROXY=1, POLYGATE_COOKIE_SECURE=1, POLYGATE_ALLOWED_HOSTS=your.domain) if something else needs them.
The installer writes a ready nginx and Caddy snippet to /etc/polygate/proxy-example.conf.
The Guide page (bottom of the side menu) explains every part of Polygate in plain words: connecting clients, models and chains, each provider, every exit and the routing policy, MCP, the Agent, the Playground, Requests, Usage and Logs, each setting, and what common errors mean. Type in its search box to find a topic, and use Open to go to the page where that part lives.
Settings → Alerts sends notices (an exit used up or switched, a model resting, WARP or Psiphon down, no route left) to a Discord, Slack or any JSON webhook, from the level you choose. Save & send test sends one test notice and says whether the webhook accepted it. Every notice also appears under the bell.
Settings → Backup and restore saves your providers and keys, routes and relay tokens, client keys, chains, MCP servers, Psiphon settings and preferences in one passphrase-protected file that restores on another computer. The dashboard password, HTTPS certificates, WARP registration and request history are not included, and a restore keeps the current dashboard password and a copy of the previous settings.
The Usage page shows requests, tokens and failures per day for 7 days up to a year, and the busiest models and routes. The request log keeps a week; a daily summary keeps 400 days.
The dashboard checks for a newer published stable release when you open it, then every 6 hours while open. A small banner announces a new version, and Settings → Updates shows the installed version, latest version, release notes, and a manual check button. Drafts and prereleases are ignored.
| Where you run Polygate | How to update |
|---|---|
| Windows portable app | Click Update & restart. The app downloads the official Windows executable, verifies its SHA-256, closes, replaces its portable executable, and reopens. Settings and keys are kept. Finish active requests first. |
| Linux service | Connect to your VPS over SSH and run sudo polygate update, or open sudo polygate and choose 8 · Update Polygate. The dashboard shows the command; it does not run server commands for you. |
| Docker | In your checkout, run git pull --ff-only, then docker compose up -d --build. Keep your existing volume and Compose options. |
| Source / standalone package | Update using your original deployment method, then restart the gateway. |
Note
Update notices and Windows one-click updates are included from v0.2.1. If you use the v0.2.0 Windows app, download and open v0.2.1 once; future updates can then be installed from the app. Linux users can run sudo polygate update to get the new dashboard notices.
Checks contact GitHub directly and are cached. Downloads only begin when you click the Windows update button. A failed download or checksum check leaves the current app running.
Run polygate for the manager: the banner, whether the service is running, the dashboard address, and a menu.
1 Dashboard address and password 6 HTTPS and certificate (domain, IP address, your own files, renew, off)
2 Health check 7 Change the dashboard password
3 Live logs 8 Update Polygate
4 Restart (or Start) 9 Uninstall (keep my data, or remove everything; you type "delete")
5 Stop 0 Exit
Every menu action is also a command:
| Task | Command |
|---|---|
| Dashboard address and password | sudo polygate info |
| Service state / health report / version | sudo polygate status / sudo polygate doctor / sudo polygate version |
| Start / stop / restart | sudo polygate start / sudo polygate stop / sudo polygate restart |
| Live logs | sudo polygate logs |
| New dashboard password | sudo polygate password |
| MCP servers: list / add a local program / remove / switch | sudo polygate mcp list / sudo polygate mcp add-local files npx -y @modelcontextprotocol/server-filesystem /srv/share / sudo polygate mcp remove files / sudo polygate mcp on files |
| Update, keeping data | sudo polygate update |
| Uninstall, keeping data | sudo polygate uninstall --yes |
| Uninstall and delete data | sudo polygate uninstall --yes --purge |
polygate doctor explains in plain words whether the service, HTTPS and the catalog are healthy. Files: program in /opt/polygate, settings in
/etc/polygate/polygate.env, data in /var/lib/polygate, installer log in /var/log/polygate-install.log.
Advanced environment settings
Most things are changed in the dashboard. A server reads these environment variables (the installer writes them to /etc/polygate/polygate.env):
| Variable | Meaning | Default |
|---|---|---|
POLYGATE_PORT |
dashboard and API port | 4317 (the installer picks a free random one) |
POLYGATE_HOST |
address to listen on | 127.0.0.1 |
POLYGATE_DASHBOARD_PATH |
serve the dashboard and the API under this path, e.g. /polygate, so a reverse proxy can forward just that path (the root only redirects to it) |
empty (the root); the Linux installer sets /polygate |
POLYGATE_STATE |
where data is kept | per user (%LOCALAPPDATA%\Polygate\state, ~/.local/state/polygate) |
POLYGATE_ADMIN_PASSWORD |
dashboard password, 12 or more characters (when set, controls the password instead of the dashboard) | a random one is generated |
POLYGATE_ALLOWED_HOSTS |
names the dashboard answers to, comma separated (* for any) |
loopback names and the certificate’s name; public listeners accept any hostname |
POLYGATE_TRUST_PROXY |
how many reverse proxies sit in front (reads the client address from X-Forwarded-For) |
0 |
POLYGATE_COOKIE_SECURE |
1, 0 or auto |
auto |
POLYGATE_HTTP_PORT, POLYGATE_HTTPS_PORT |
ports for built-in HTTPS | 80, 443 |
POLYGATE_HTTPS_STAGING |
1 uses Let's Encrypt's test servers while you experiment |
off |
- Settings, provider keys and relay tokens are stored encrypted on disk; the key file is private to the service user. Client API keys are never forwarded to a provider.
- The request log records sizes, status and timing, not what you typed or what came back. The Logs page (kept for 7 days) removes keys and tokens before anything is saved; MCP tool calls are logged by name and timing, without their arguments' values.
- The dashboard needs a password and locks out guessing; API keys can be limited per key and expire.
- The Linux service runs as an unprivileged user with systemd hardening (no new privileges, read-only system, private temp folder) and is a polite neighbour (low priority, task limit).
- Releases are verified with SHA-256 before they are unpacked, and the installer refuses archives with unsafe paths or links.
- Report security problems privately to the repository owner rather than in a public issue.
| You see | What it means and what to do |
|---|---|
| The download command prints nothing | Normal: curl -fsSL saved install.sh. Run sudo bash install.sh next. |
| The installer says The download failed | Check outbound GitHub access and that the selected published release has a package for your architecture. Latest release. |
Unrecognized Host header |
the dashboard was opened with a name it does not know. Set POLYGATE_ALLOWED_HOSTS to that name, or use the HTTPS name. |
| A model says paused or answers 429 | the provider limited it. The message says when it comes back. Use auto, or add another route. |
| OpenCode: daily allowance used up | that network address has used OpenCode's daily allowance. Add Psiphon, WARP, a proxy or a relay under Routing. A very large conversation (hundreds of messages, a megabyte or more per request) can be refused on an address that still accepts small requests, so a route test can pass while the chat is refused; the message says when this is the case. Start a new chat or compact the old one. |
| OpenCode: refused this request, though a small test through the same exit passed | OpenCode Free sometimes refuses a request only because of the list of tools your coding tool sends, and words it like a usage limit (for example, Kilo's 27 tools are refused while the same request without one of two particular tools is answered). Polygate notices that the exit itself is fine and asks once more with the standard tools only (bash, read, edit and similar), then remembers it; the response header x-polygate-tools-trimmed says how many were left out, and the Logs page explains it. If it is still refused, the request is tried through your other exits before the error goes back. Turn the tool retry off with Retry with fewer tools on the Models page. |
| Your request resulted in more tokens than this model's maximum context length | the conversation is longer than the model can take. Run compaction in your client, or start a new session. Polygate passes the provider's answer through unchanged. |
| Expected 'id' to be a string or Model generated invalid tool call | a tool call arrived out of order or with misnamed arguments. Polygate repairs both on the way; if it still happens, open Logs → Requests for the model and the route. |
| Agent: OpenCode Free is blocked by Polygate's Agent compatibility check | OpenCode released a new version before Polygate's Agent engine moved to it. Update Polygate, or use another provider's model in the Agent until then. |
| A relay shows Connection reset | the network, or the relay's host, closed the connection before it answered. Test the relay's address with curl.exe -v https://your-relay-address: if the reset happens during the handshake, your network blocks that site (common for netlify.app) and another relay is the fix. For OpenCode, Vercel relays are the most reliable. |
| Kilo: stopped answering from this network address | Kilo's anonymous limit for the address. All Kilo models rest for 30 minutes and then try again. You can save an optional Kilo key on its provider row; whether it lifts this limit has not been verified here. |
| WARP: Could not start a WARP tunnel | the message says what was tried and what most likely happened. Your network reset the connection means the network blocks Cloudflare's MASQUE servers; did not answer in time means the traffic is dropped or very slow. If a VPN or proxy program is running on this computer, turn it off first (WARP runs its own tunnel, and a VPN in between often breaks it). WARP tries a plain handshake first and splits it only if the network resets that (Handshake splitting in the WARP settings forces either way). You can also set a different MASQUE endpoint (the default tries 162.159.198.183, then 162.159.198.2), try another network, or use a proxy or relay route instead. |
| WARP is connected but a service still refuses the exit | WARP exit addresses are shared and can be rate-limited. Ask for a New identity, or use a proxy or relay route for that service. |
| HTTPS fails at the certificate step | check that the domain points at the server, that ports 80 and 443 reach it (also in your hosting provider's firewall), and that nothing else uses them. Run sudo polygate https status for the exact reason. |
| The Linux installer stops with problems to fix | it lists them and changed nothing. Fix them and run it again, or use --check to look first. |
| Nothing works after an update | polygate doctor, then polygate logs. A failed update puts the previous release back by itself. |
With Node.js, npm, and Bun installed (release builds use Bun 1.4.4):
git clone https://github.com/B3hnamR/Polygate.git
cd Polygate
npm install
bun run check # type check
bun test tests # the test suite
bun run dev # dashboard + gateway with live reloadbackend/ is the gateway (Bun, no framework), src/ the dashboard (React), desktop/ the Windows app (Electron), relays/ the relay templates,
install.sh and install/ the Linux installer and the polygate command, vendor/ code reused from other open projects (see below).
Releases are built on the maintainer's machine with the commands below and published with their .sha256 files; the workflows in .github/ describe the same steps but are not run for releases.
To build the portable Windows app in PowerShell, with Python available:
python scripts/fetch-bun.py 1.4.4 windows-x64
$env:POLYGATE_BUN_RUNTIME = "$PWD\build\runtime\1.4.4\windows-x64\bun.exe"
bun run distThe executable is written to release/. For Linux packages, run bash scripts/build-linux.sh amd64 (or arm64).
Made by B3hnamR. Released under the MIT license. Third-party components keep their own licenses; see THIRD_PARTY_NOTICES.md.





