Portkey is an open-source AI gateway that unifies access to 250+ Large Language Models (LLMs) across dozens of providers behind a single, OpenAI-compatible API. Instead of integrating with each provider's SDK, applications send requests through Portkey, which handles routing, load balancing, and automatic fallback to keep AI-powered systems reliable. This guide deploys Portkey on a Linux server using Docker Compose and secures it with Traefik as a reverse proxy for TLS termination, protecting access with Basic Authentication for the web console and an IP allowlist for the API endpoint. By the end, you'll have a working AI gateway routing requests to your LLM provider over HTTPS.
Set Up the Directory Structure and Environment Variables
Portkey's gateway container is stateless and does not require persistent storage of its own. The project directory contains the Docker Compose configuration and environment variables used to configure and run the gateway.
1. Create the project directory:
$ mkdir ~/portkey
2. Navigate to the project directory:
$ cd ~/portkey
3. Find your server's public IP address, which is used later to restrict API access:
$ curl -4 ifconfig.me
Copy this value for use when configuring the .env file.
4. Create an environment file to store configuration variables:
$ nano .env
5. Add the following configuration:
DOMAIN=portkey.example.com
LETSENCRYPT_EMAIL=admin@example.com
SERVER_IP=YOUR_SERVER_IP/32
- Replace
portkey.example.comwith your domain name. - Replace
admin@example.comwith your email address. - Replace
YOUR_SERVER_IPwith your server's public IP address obtained in the earlier step.
Save and close the file.
6. Install the htpasswd utility, which is used to generate credentials for the web console:
$ sudo apt install -y apache2-utils
7. Generate a username and password for accessing the Portkey console. Replace portkeyadmin with your preferred username:
$ htpasswd -c ~/portkey/.htpasswd portkeyadmin
Enter and confirm a password when prompted. This creates a .htpasswd file containing the hashed credentials.
Deploy Portkey with Docker Compose
This section deploys Portkey and Traefik together, with Traefik handling HTTPS certificate issuance through Let's Encrypt. The self-hosted Portkey gateway has no built-in authentication of its own, so this guide adds Basic Authentication and an IP allowlist at the Traefik level to restrict access to the console and the API.
1. Create the Docker Compose manifest file:
$ nano docker-compose.yml
2. Add the following configuration:
services:
traefik:
image: traefik:v3.7.11
container_name: traefik
restart: unless-stopped
environment:
DOCKER_API_VERSION: "1.44"
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--certificatesresolvers.le.acme.httpchallenge=true"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.le.acme.email=${LETSENCRYPT_EMAIL}"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./.htpasswd:/.htpasswd:ro
portkey:
image: portkeyai/gateway:1.15.2
container_name: portkey
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.services.portkey.loadbalancer.server.port=8787"
- "traefik.http.middlewares.portkey-auth.basicauth.usersfile=/.htpasswd"
- "traefik.http.middlewares.portkey-ipallow.ipallowlist.sourcerange=${SERVER_IP}"
- "traefik.http.routers.portkey-console.rule=Host(`${DOMAIN}`) && PathPrefix(`/public`)"
- "traefik.http.routers.portkey-console.entrypoints=websecure"
- "traefik.http.routers.portkey-console.tls=true"
- "traefik.http.routers.portkey-console.tls.certresolver=le"
- "traefik.http.routers.portkey-console.middlewares=portkey-auth"
- "traefik.http.routers.portkey-console.service=portkey"
- "traefik.http.routers.portkey-console.priority=10"
- "traefik.http.routers.portkey-api.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.portkey-api.entrypoints=websecure"
- "traefik.http.routers.portkey-api.tls=true"
- "traefik.http.routers.portkey-api.tls.certresolver=le"
- "traefik.http.routers.portkey-api.middlewares=portkey-ipallow"
- "traefik.http.routers.portkey-api.service=portkey"
- "traefik.http.routers.portkey-api.priority=1"
- "traefik.http.routers.portkey-logs.rule=Host(`${DOMAIN}`) && Path(`/log/stream`)"
- "traefik.http.routers.portkey-logs.entrypoints=websecure"
- "traefik.http.routers.portkey-logs.tls=true"
- "traefik.http.routers.portkey-logs.tls.certresolver=le"
- "traefik.http.routers.portkey-logs.middlewares=portkey-auth"
- "traefik.http.routers.portkey-logs.service=portkey"
- "traefik.http.routers.portkey-logs.priority=10"
Save and close the file.
In the above manifest:
-
traefik: Serves as the reverse proxy and TLS termination point. It listens on ports 80 and 443, automatically redirects HTTP to HTTPS, and provisions Let's Encrypt certificates. -
portkey: Runs the officialportkeyai/gatewayimage on internal port 8787. Separate Traefik routers apply Basic Authentication to the/publicconsole and an IP allowlist to the API, avoiding conflicts with providerAuthorizationheaders. The stateless gateway requires no environment variables, volumes, or database.
3. Start the services in detached mode:
$ docker compose up -d
4. Verify that all containers are running:
$ docker compose ps
The output displays two running containers with Traefik listening on ports 80 and 443.
Access the Portkey Gateway Console
Traefik routes all HTTPS traffic on the configured domain to the Portkey container, applying Basic Authentication to the console and an IP allowlist to the API.
1. Confirm that the API responds from your server. Replace portkey.example.com with your configured domain:
$ curl -I https://portkey.example.com/v1/chat/completions
A response other than 403 confirms that the request reached the gateway and was not blocked by the IP allowlist. A 403 response means the server's IP does not match the value configured in SERVER_IP in the .env file.
2. Open a web browser and navigate to https://portkey.example.com/public/, replacing portkey.example.com with your configured domain.
3. A browser prompt requests a username and password. Enter the credentials created earlier with htpasswd.
The Portkey Console displays a test request panel and options to configure routing rules such as load balancing, fallbacks, and retries.
Test the Portkey Gateway Console
Validate the deployment by sending a live chat completion request through the gateway using an LLM provider API key.
1. Send a test chat completion request through the gateway. Replace portkey.example.com with your configured domain, your_provider with your LLM provider, and your_api_key and your_model with your provider's key and model name:
$ curl https://portkey.example.com/v1/chat/completions -H "x-portkey-provider: your_provider" -H "Authorization: Bearer your_api_key" -H "Content-Type: application/json" -d '{"messages": [{"role": "user", "content": "Say this is a test."}], "model": "your_model"}'
A successful response returns a chat.completion object containing the model's reply, confirming that the gateway routed the request to the provider and back.
2. Open the Portkey Console at https://portkey.example.com/public/, replacing portkey.example.com with your configured domain and review the request under the Logs section, confirming the gateway recorded the completed request.
Next Steps
Portkey is running behind Traefik, routing requests to your language model provider through a single, OpenAI-compatible endpoint. From here you can:
- Configure routing rules such as load balancing, fallbacks, and automatic retries across multiple LLM providers
- Add more LLM providers to the gateway and compare latency, cost, and reliability across them
- Review the request logs in the console regularly to monitor usage and catch failed requests
For the full guide with additional tips, visit the original article on Vultr Docs.
Top comments (0)