Don’t want to read all this?
Just drop a link to https://xedant.com/agents/proxy/install.md or to https://xedant.com/llms.txt into any AI chat (Claude, ChatGPT, etc.) and ask it to generate the config files and commands. It will read the docs, ask you a few questions about your setup, and hand you a ready-to-use configuration. Save time — let the model do the reading for you.
You can also reach me on Telegram — I’m always glad to help. And that’s not just politeness — I genuinely enjoy talking to like-minded people, especially if you love coding as much as I do.
Proxy Agent is a single entry point to all the models your team uses. The program lives on your server and deploys as one Docker container, with a PostgreSQL database required next to it — that is the only mandatory setting. After installation, all your programs talk not to a dozen vendors one by one, but to your server’s address: vendor keys, spending limits and the request log stay with you instead of spreading across employee computers.
What you will need
- A server or computer with Docker — Windows, Linux or macOS all work, and an inexpensive server is enough for permanent use.
- A PostgreSQL database — separate and mandatory. There is no database inside the container: without a connection string the app will not start. The easiest way is to run the database next to the app in the same startup file, as shown below.
- One free port for the interface and requests (5000 in the examples). If you need a proxy for ordinary traffic, add a separate port for every channel you allow one: as many ports as channels.
- A license key — without it the interface opens, but no traffic flows through the server. The key is passed in the
AGENT_LICENSEvariable. - Optionally, the address and key of your Xedant Agent: without them everything works except the chat with the AI agent inside the product.
Installing with Docker Compose
Create a compose.yml file with this content. There are two services here: the database and the app itself.
services:
postgres:
image: postgres:17
container_name: proxyagent-postgres
environment:
- POSTGRES_DB=proxyagent
- POSTGRES_USER=proxyagent
- POSTGRES_PASSWORD=change-this-password
volumes:
- proxyagent-db:/var/lib/postgresql/data
restart: unless-stopped
proxyagent:
image: xedant/proxy-agent:main-latest
container_name: proxyagent
ports:
- "5000:80"
# The proxy service port is published on its own line — one per each
# channel that has a listener port set on the "HTTP Proxies" page.
# - "5010:5010"
volumes:
# Working state: data protection keys, the session signing key,
# "reasoning", the secret vault, VPN configurations.
- proxyagent-data:/apps/proxy
# Configuration: settings, models, channels, keys and rules files.
- proxyagent-config:/project/apps/proxy
environment:
- ASPNETCORE_ENVIRONMENT=Production
- PROXYAGENT_DATABASE=Host=postgres;Port=5432;User Id=proxyagent;Password=change-this-password;Database=proxyagent;
- PROXYAGENT_DATA=/apps/proxy
- PROXYAGENT_CONFIG_FOLDER=/project/apps/proxy
- PROXYAGENT_ADMIN_LOGIN=admin
- PROXYAGENT_ADMIN_PASSWORD=<SHA-256 hash of the password, lowercase>
- JWT_SECRET_KEY=<a random string of at least 32 characters>
# License key: without it the interface opens, but no traffic flows.
# - AGENT_LICENSE=${AGENT_LICENSE}
restart: unless-stopped
volumes:
proxyagent-db:
proxyagent-data:
proxyagent-config:
The xedant/proxy-agent:main-latest image is the English build with an English interface. Now start it:
docker compose up -d
The interface appears on port 5000: http://<server-address>:5000. Replace the database password with your own and put the same value into the PROXYAGENT_DATABASE string — it is the same pair of values. The license key is set with the AGENT_LICENSE variable: without a valid key the interface and settings stay open, but no traffic flows through the server.
Running without Compose
You can get by with a single docker run command — in that case run the database separately:
docker run -d \
--name proxyagent \
-p 5000:80 \
-v proxyagent-data:/apps/proxy \
-v proxyagent-config:/project/apps/proxy \
-e PROXYAGENT_DATABASE="Host=db-address;Port=5432;User Id=proxyagent;Password=your-password;Database=proxyagent;" \
-e PROXYAGENT_DATA=/apps/proxy \
-e PROXYAGENT_CONFIG_FOLDER=/project/apps/proxy \
-e PROXYAGENT_ADMIN_LOGIN=admin \
-e PROXYAGENT_ADMIN_PASSWORD=your-sha256-hash \
-e JWT_SECRET_KEY=your-random-string-of-at-least-32-characters \
-e AGENT_LICENSE=your-license-key \
--restart unless-stopped \
xedant/proxy-agent:main-latest
The remaining variables are convenient to keep in a .env file next to the project (by default /project/.env; the path is changed with the PROXYAGENT_ENV_FILE variable). The app reads it itself at startup and re-reads it on the fly, so no separate --env-file flag is needed in the command — this makes it easier to change variables without rewriting the long startup line. Real environment variables always take priority over the file, and the file itself belongs in .gitignore: it holds secrets.
Main environment variables
Settings are passed through environment variables — you write them once into compose.yml and change them without touching the code. Almost all names start with PROXYAGENT_.
| Variable | What it sets | Default |
PROXYAGENT_ENV_FILE | path to the environment file that is mixed in at startup and re-read on change | /project/.env |
PROXYAGENT_DATABASE | PostgreSQL connection string — the only mandatory setting | none; the app will not start without it |
PROXYAGENT_ADMIN_LOGIN, PROXYAGENT_ADMIN_PASSWORD | administrator sign-in; the password is a lowercase SHA-256 hash (the login form has a built-in generator) | not set — the app shows “initial setup” |
JWT_SECRET_KEY, DEV_FALLBACK_JWT_KEY | signs login sessions (at least 32 characters); the second is a last-resort fallback when the key file is unavailable. With a set key, sessions survive container recreation | generated and stored in a file |
AGENT_LICENSE | license key or path to a file with the key; read once at startup — a restart is needed after changing it | not set — no traffic flows |
PROXYAGENT_API_KEY | lowercase SHA-256 hash of the management API key; protects the /api/agent/* addresses with the X-API-Key header | not set — management over the API is off |
PROXYAGENT_AGENT_API_URL, PROXYAGENT_AGENT_API_KEY | chat with the AI agent inside the product (an Xedant Agent connection); read once at startup | not set — the chat is hidden |
PROXYAGENT_BASE_PATH | hosting in a first-level subfolder (for example, /proxy) | not set — runs at the domain root |
PROXYAGENT_CONFIG_FOLDER | configuration folder with the settings, models, channels, keys and secret-hiding rule files; read once at startup | /project/apps/proxy |
PROXYAGENT_DATA | working-state root (data protection keys, the session signing key, “reasoning”, the secret vault, VPN configurations); read once at startup | /apps/proxy |
PROXYAGENT_ANONYMIZER_DB | secret-hiding vault folder: rules, mappings and leak events | /apps/proxy/anonymizer |
PROXYAGENT_CLICKHOUSE_URL | sending statistics to ClickHouse; when set, analytics gets a button that backfills missed days | not set — off |
PROXYAGENT_BRAND | build brand; pastukhov is the Russian build, where the interface opens in Russian by default (until the language is chosen manually) | xedant |
ASPNETCORE_URLS | listen address inside the container | http://+:80 |
ASPNETCORE_ENVIRONMENT | Production enables protection and a strict error page | Production |
Where the data lives
The data is spread over three places, and they should not be confused.
- Configuration — the files
settings.yml,models.yml,http-providers.yml,keys.ymlandanonymization.ymlin the/project/apps/proxyfolder. Models, channels, access keys, secret-hiding rules and settings live here. The folder can be put under version control and moved together with the project, and manual edits are picked up in about 300 ms. Secret fields can be written as an environment-variable reference like$VARIABLE_NAME. - Working state — the
/apps/proxyvolume:auth/(data protection keys),appdata/.jwt-secret(the login session signing key),reasoning_cache.sqlite3(saved DeepSeek “reasoning”),anonymizer/(the secret-hiding vault),vpn/(VPN configurations) andhapp/(working files of Happ subscription channels — currentlyhapp/{id}/). The contents ofhapp/restore themselves: on the next use the subscription is fetched again. - Logs and spending — PostgreSQL: the request log, the proxy service log and daily spending totals per key.
That is why the example above mounts two volumes. Without the working-state volume, recreating the container loses the saved “reasoning” and the secret mappings (placeholders already sent to the model stop coming back), and without a persistent JWT_SECRET_KEY every issued login session stops working.
First sign-in
Open the interface in a browser. The administrator login and password are set with the PROXYAGENT_ADMIN_LOGIN and PROXYAGENT_ADMIN_PASSWORD variables; if they are not set, the product honestly reports “initial setup” and refuses to work. The variable stores not the password itself but its irreversible SHA-256 hash — at sign-in you type the password, the app hashes what you typed and compares it with the configured value. A ready hash is easy to produce with the built-in generator right in the login form. A login session lives 90 days, and the variables are read on every request, so the password can be changed without restarting the container.
What to do after startup
Once the interface is open, a few steps remain before the first request:
- Create the first model in the “Models” section: a public name, the vendor address and key, prices per million “portions of text” (tokens). Details are in the Models & Prices section.
- Press “Check” on the model — the product walks the model’s real route and tells you whether the connection answers.
- Create an access key for the first program. The key is shown exactly once — save it right away.
- Connect the program: put your server’s address in place of the vendor address, and your access key in place of the vendor key. Exactly how — in the Connecting Applications section.
- Send the first request and make sure it appears in the request log: the model, the key, tokens and the cost are visible there.
A proxy for ordinary traffic
Besides working with models, the product can act as an ordinary proxy server for browsers and programs unrelated to AI. By default this capability is off: until some HTTP proxy gets a listener port, nothing listens.
- Every channel gets its own listener port: on the “HTTP Proxies” page set the port and enable accepting connections. The port is published with its own line in the startup file — only then is it reachable from outside.
- Sign-in with an access key is on by default: without a key, nobody gets out to the internet. Turning the check off makes sense only inside a closed network.
- If you need a channel through a VPN, the container needs
NET_ADMINrights and WireGuard installed inside the image: the stock image does not include them. - If you need a Happ subscription channel, nothing extra to install: the Xray core is already in the image. In your own build without the core, the product will say so itself — such a channel is unavailable.
Such traffic is counted in volume, but not in money, and it does not consume key limits. Details are in the Tunnel Service section.
Installing through Xedant MultiAgent
If you have several servers, it is more convenient to install the product from Xedant MultiAgent: it raises the container itself, provides a permanent address and HTTPS, and connects the database. Proxy Agent is in the product catalogue (port 6040), the database is set with the same PROXYAGENT_DATABASE variable, and a linked Xedant Agent connects to the chat. More about MultiAgent itself is on the MultiAgent page.
License and updates
The product checks the license: a valid key is needed for traffic to flow through the server, while the interface, settings, logs and management over the API stay open even without one. The key is set with the AGENT_LICENSE variable, and its state is visible in a line in the interface. The license is the right to use the product, 12 months of free updates and support. Prices are the same as the neighboring products: personal
Next, take a look at Getting Started — a short tour of how the product works inside.