Independent testing Updated August 2026 387 self-hosting guides 5 VPS providers tested

guide

How to Self-Host Jan Server on a VPS (Complete Guide)

Deploy Jan Server on a VPS with Docker Compose: run the setup wizard, pick remote or local inference, and lock down Keycloak and the Kong gateway first.

Jan Server is the self-hostable half of the Jan project: a set of Go microservices that expose an OpenAI-compatible API, with MCP tool integration, Keycloak authentication and a Kong gateway in front. It is not a single container, and the deployment reflects that.

The good news is that the project ships a setup wizard that writes the configuration for you. The main decision you make during it is where inference runs.

Before you start

Most cheap VPS plans are 4 GB and will not do. These clear the floor:

ProviderPlanvCPU / RAM / DiskPriceLink
ContaboCloud VPS 44 / 8 GB / 100 GB5.50 EUR/mo excl. VATContabo
Hetzner CloudCX334 / 8 GB / 80 GB NVMe8.49 EUR/mo excl. VATHetzner Cloud
DigitalOcean8 GB droplet tier8 GBcheck current rateDigitalOcean
Vultr8 GB instance tier8 GBcheck current rateVultr
Linode8 GB shared tier8 GBcheck current rateLinode

For a fuller breakdown of these plans, see our VPS comparison.

Step 1: Connect and install dependencies

ssh user@your-vps-ip
sudo apt update && sudo apt upgrade -y
sudo apt install -y docker.io docker-compose-v2 make git
sudo systemctl enable --now docker

Confirm Compose v2 is what you got, since Jan Serverโ€™s compose file uses the include: key that v1 does not understand:

docker compose version

Step 2: Clone the repository

Unlike most self-hosted apps, you do not write your own docker-compose.yml here. The repositoryโ€™s compose file pulls in fragments for infrastructure, the API services, MCP tools, the web app and inference.

git clone https://github.com/janhq/server.git
cd server

Step 3: Run the setup wizard

make quickstart

The wizard writes a single root .env and then starts Compose. It asks three things:

If you cannot run the wizard interactively, copy the template and populate it instead:

cp .env.template .env
nano .env
make setup

make setup checks dependencies, creates directories and pulls the base images without starting anything.

Step 4: Start the stack

make up-full

Once the containers settle you have:

ServicePortPurpose
API Gateway (Kong)8000The entry point for everything
LLM API8080OpenAI-compatible chat completions
Response API8082Multi-step tool orchestration
Media API8285Uploads and media IDs
MCP Tools8091Search, scraping, code execution
Web chat UI3001The browser client
Keycloak8085Authentication console

API documentation is served at http://your-vps-ip:8000/api/swagger/index.html.

Step 5: Secure it before you expose it

This is the step to not skip. Two defaults are unsafe on a public server:

  1. The Keycloak console ships with admin / admin. Change it immediately at port 8085. Keycloak issues the tokens that Kong validates, so this one credential protects the whole API surface.
  2. Only port 8000 should be reachable from outside. Kong enforces the JWT and API key checks; the service ports behind it do not. Bind the rest to localhost or block them at the firewall.
sudo ufw allow OpenSSH
sudo ufw allow 443/tcp
sudo ufw enable

Then terminate TLS with Caddy, Traefik or Nginx and proxy to port 8000. Leaving an unauthenticated LLM endpoint on the public internet gets it found and used by someone else, usually within days.

Running inference locally

If you did choose local vLLM, the inference fragment defines two profiles. The GPU profile runs vllm/vllm-openai:v0.11.2 with janhq/Jan-v1-4B as the default model and reserves an NVIDIA device, so it will not start on a typical VPS. The CPU profile runs without a GPU and is genuinely usable for testing, but token generation on shared vCPUs is slow enough that you will not want it in front of users.

Renting GPU capacity and pointing Jan Server at it as a remote endpoint is usually cheaper than a GPU server sitting idle between prompts.

Day-to-day operation

Update to a newer release:

git pull
docker compose pull
make up-full

Back up the Postgres volume and your root .env. The .env holds the secrets the wizard generated, and restoring a database without it leaves you with sessions you cannot decrypt.

Check what a service is doing with docker compose logs -f llm-api, substituting the service you care about.

Common problems

SymptomCause
include is not a valid compose keyDocker Compose v1 is installed; you need v2
Containers are killed during startupUnder 8 GB RAM, the stack gets OOM-killed
Every API call returns 401Requests are hitting a service port directly rather than Kong on 8000
vLLM container never becomes healthyThe GPU profile is active on a host with no NVIDIA device

Jan Server asks more of a VPS than a typical self-hosted app, mostly because it brings its own gateway, identity provider and database rather than assuming you have them. Size for 8 GB, put Kong behind TLS, and change the Keycloak password before anything else.

Frequently asked questions

Do I need a GPU to self-host Jan Server on a VPS?

Not if you choose a remote OpenAI-compatible endpoint when the setup wizard asks about your LLM provider. The VPS then runs only the API, orchestration and auth services. The local vLLM option has a GPU profile that expects an NVIDIA card and a CPU profile that works without one at much lower speed.

Why does the Keycloak console accept admin as both username and password?

That is the default credential the compose setup ships with, and it is fine on a laptop but not on a public server. Change it before you open any port to the internet, because the Keycloak realm is what protects every API route behind the Kong gateway.

Which port should I put behind my reverse proxy?

Port 8000, the Kong API gateway. It is the documented entry point and it enforces the JWT and API key checks in front of the individual services. Publishing the service ports directly would let callers bypass the gateway and its authentication entirely.