bestruirui/octopus: a self-hosted LLM API gateway for one person's model stack
One Hub All LLMs For You | 为个人打造的 LLM API 聚合网关
At a glance
- What is it?
- Octopus is a Go and TypeScript gateway that aggregates multiple LLM provider channels behind one endpoint, converts between OpenAI and Anthropic request formats, and ships as a single binary. It is a personal tool, not a multi-tenant platform, and the README does not document rollback or a migration path between database engines.
- Who is it for?
- Adopt Octopus if you are one person or a small team routing several provider accounts through one endpoint and you want the routing logic on your own disk instead of a hosted proxy. Do not adopt it if you need per-tenant isolation, an audit trail you can hand to a compliance officer, or a documented rollback path between database engines, because the README describes none of those.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Octopus solves: many provider accounts, one endpoint
If you pay for more than one LLM provider, you eventually own a small routing problem. Each provider has its own base URL, its own authentication header, its own request and response shape, and its own way of failing. The README frames Octopus as "A Simple, Beautiful, and Elegant LLM API Aggregation Service for Individuals", and that last word is the honest scope. This is a gateway for one operator, not a multi-tenant proxy you hand to a company.
The concrete job it does is to sit between your clients and your upstream channels. A client speaks one protocol, Octopus translates it, picks a channel, forwards the request, and records what happened. The README lists the pieces of that job as multi-channel aggregation, protocol conversion between OpenAI Chat, OpenAI Responses and Anthropic API formats, automatic failover, upstream error shielding, and analytics for requests, token consumption and cost. If you have ever kept a spreadsheet of which key is still funded, or written a shell script that retries a different provider after a 429, this is the category of tool that replaces it.
The audience is narrow on purpose. The topics list includes claude-code, codex-cli and opencode, which tells you the intended user runs coding agents against several backends and wants to switch between them without editing each agent's config. That is a personal-infrastructure problem, and Octopus is sized for it.
How the gateway routes and converts requests
The repository layout tells you most of the architecture before you read a line of code. There is a cmd/ directory, an internal/ directory, a main.go, and a web/ directory holding the frontend. The build note in the README explains the coupling: "the frontend build artifacts are embedded into the Go binary, so you must build the frontend before starting the backend." The management panel is not a separate service. It is compiled into the same executable that proxies your API traffic.
go.mod confirms the shape. gin-gonic/gin is the HTTP router, gin-contrib/sse handles server-sent events, which is what streaming chat completions are, and github.com/looplj/axonhub/llm is the library the project depends on for the model-facing layer. Persistence is gorm with three drivers: glebarez/sqlite, gorm.io/driver/mysql and gorm.io/driver/postgres. Configuration comes from spf13/viper, which is why the same options can be set in a JSON file or through environment variables. Authentication for the panel uses golang-jwt/jwt.
The routing model is channel plus group. A channel is one upstream provider connection, and the README is explicit that you supply only the service root URL because "the program automatically appends the API version and endpoint path based on the channel type." A group is the layer your client actually points at, and failover happens inside it: the README says Octopus "automatically switches to an available channel when an upstream channel fails." Two more features matter for agent workloads. Upstream error shielding intercepts upstream errors so agent tasks keep running, and the request visualization view shows the full path from the moment the client sends a request. The first is a design decision with a cost, which I take up below.
Installing Octopus with Docker and reaching the admin panel
The fastest path in the README is a single container. It mounts a data directory for the SQLite file and the generated config, and publishes port 8080.
docker run -d --name octopus -v /path/to/data:/app/data -p 8080:8080 bestrui/octopusAfter the container starts, open http://localhost:8080. The README gives the first-login credentials as username `admin` and password `admin`, with a security notice telling you to change the password immediately. The panel is where you add channels, group them, and read the request logs.
If you prefer compose, the repository ships a docker-compose.yml. It uses the same image, the same port mapping, and `restart: unless-stopped`.
wget https://raw.githubusercontent.com/bestruirui/octopus/refs/heads/master/docker-compose.yml
docker compose up -dThere is also a release binary. The README says to download the build for your platform from Releases and then run `./octopus start`. Building from source needs Go 1.24.4, Node.js 18+ and pnpm, and the frontend must be built first because its output is embedded in the binary.
cd web && pnpm install && pnpm run build
go run main.go startConfiguration lives in `data/config.json` and is generated on first startup. The README's complete example sets `server.host` to `0.0.0.0`, `server.port` to 8080, `database.type` to `sqlite`, `database.path` to `data/data.db` and `log.level` to `info`. Every one of those can be overridden by an environment variable named `OCTOPUS_` plus the path joined with underscores, so `OCTOPUS_SERVER_PORT` replaces `server.port`. That is the mechanism to use if you would rather not bake a port into an image.
Switching Octopus to MySQL or PostgreSQL
SQLite is the default and needs no setup beyond a writable directory. The README supports two server databases as well, and the connection string format differs enough between them to be worth copying exactly. For MySQL, the example is a Go-style DSN.
{
"database": {
"type": "mysql",
"path": "root:password@tcp(127.0.0.1:3306)/octopus"
}
}For PostgreSQL, the example uses a URL with an explicit sslmode parameter.
{
"database": {
"type": "postgres",
"path": "postgresql://user:password@localhost:5432/octopus?sslmode=disable"
}
}The README notes that MySQL and PostgreSQL require you to create the database yourself, and that the application creates the table structure automatically. What it does not document is anything about moving data between engines, or about rolling back to SQLite once you have switched. If you start on SQLite and later decide you want PostgreSQL, you are on your own for the migration. That is a real gap for a tool that stores your request history and cost analytics, and it argues for choosing the engine you actually intend to keep before you accumulate data.
Error shielding is the feature with the sharpest edge
Upstream error shielding is listed as a feature, and the README's description is that it intercepts all upstream errors to keep agent tasks running without interruption. Read that against failover and you can see the intended behaviour: the client sees a working response even when a channel is unhealthy, because Octopus has already retried elsewhere.
That is exactly what you want when a coding agent is mid-task and a provider returns a transient error. It is also the behaviour that makes debugging harder. If the gateway normalizes upstream failures into successful-looking responses, your client-side error handling stops being a signal about upstream health. The request visualization view exists for this reason: it is where you go to see what actually happened, because the response your agent received may not tell you. The README does not describe how errors are classified, how many retries a request gets, or what happens when every channel in a group fails. Those are the questions I would want answered before putting this in front of an agent that runs unattended.
The second limitation is the default credential. Shipping `admin`/`admin` and asking the user to change it after login is a common pattern for self-hosted tools, and it is fine on a laptop behind a firewall. It is not fine on a host reachable from the internet, and nothing in the README suggests the application forces a change at first boot.
How Octopus differs from LiteLLM and one-api
The closest category neighbours are LiteLLM and one-api, and the difference is where the routing logic lives and what you are expected to operate. LiteLLM's proxy is a Python service; you deploy a Python runtime and its dependency tree alongside it. Octopus compiles the frontend into a Go binary and the README advertises "Lightweight Single-Binary Deployment" with no external runtime dependencies. If your constraint is a small VPS or a home server where you do not want to maintain a Python environment, that is the deciding difference. If your constraint is a provider or model that only LiteLLM supports, the single binary does not help you.
Against one-api, the distinction is scope rather than language. Octopus is framed for individuals, and the README's feature list is oriented around one operator's workflow: channel management, groups, price sync, model sync, logs. It does not present itself as a billing or reseller platform with user accounts and quotas. The protocol conversion is also a specific claim worth noting: the README says Octopus converts between OpenAI Chat, OpenAI Responses and Anthropic API formats. That matters if you run Claude Code against a non-Anthropic backend, or Codex against something that speaks the Responses API, because the translation happens in the gateway rather than in each client.
None of these three is strictly better. They differ in runtime, in how much multi-user machinery they carry, and in which protocols they translate.
Licence and the cost of staying current
Octopus is AGPL-3.0. For a self-hosted personal gateway this changes nothing about how you run it. It matters if you intend to modify Octopus and expose the modified version to other users over a network, because that is the scenario the AGPL's network clause addresses. If you are evaluating this for a company that wants to embed it in a product, the licence is a conversation to have with someone qualified to have it, not something to settle from a README. I am not giving legal advice here, only pointing at the clause that tends to matter.
On maintenance: the last push to the default branch was on 2026-09-10, and v0.13.4 was released the same day, with v0.13.3 hours earlier and v0.13.2 on 2026-09-02. The release cadence in that window is tight. The upgrade cost itself is low on the Docker path, where you pull a new image and the data directory persists. The environment variable scheme, `OCTOPUS_` plus the config path joined with underscores, means you can pin behaviour in your compose file rather than editing `data/config.json` by hand on each upgrade. The README does not describe a migration step between versions, so the practical assumption is that the schema is handled on startup. That assumption is worth testing on a copy of your data directory before you upgrade the instance you rely on.
Editorial conclusion
Adopt Octopus if you are one person or a small team routing several provider accounts through one endpoint and you want the routing logic on your own disk instead of a hosted proxy. Do not adopt it if you need per-tenant isolation, an audit trail you can hand to a compliance officer, or a documented rollback path between database engines, because the README describes none of those. Before you commit, verify two things yourself: that your provider's base URL works under the channel type you pick, since Octopus appends the API version and endpoint path for you, and that the default admin/admin credentials have been changed, since the README only asks you to change them after first login rather than forcing it at setup.
Frequently asked questions
How do I install Octopus?
The README's quickest route is the published container image, run with a mounted data directory and port 8080 published; a docker-compose.yml is also in the repository. Alternatively, download a platform binary from Releases and run ./octopus start, or build from source with Go 1.24.4, Node.js 18+ and pnpm, building the web frontend before the backend.
What is the default password for the Octopus admin panel?
The README states that first login uses the username admin and the password admin, and it includes a security notice asking you to change the default password immediately after first login.
Which databases can Octopus use?
SQLite, MySQL and PostgreSQL are supported, selected through the database.type key in data/config.json. SQLite is the default at data/data.db; the README notes that MySQL and PostgreSQL require you to create the database manually, after which the application creates the table structure.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bestruirui-octopus)