AILLMSelf-HostingAI Coding Agents

Jan in 2026: Private Offline ChatGPT With a Local API (Linux, Windows, Mac)

Before you start

  • 16 min read

Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#

Jan is a free, open-source desktop app that runs AI models on your own computer, so your chats stay private and work without internet. It also starts a local OpenAI-compatible API on your machine.

Jan official logo

Logo: the official Jan project (github.com/janhq/jan)

Think of it as ChatGPT in a window on your own PC. You download a model once, then chat, attach files and connect tools without sending anything out. Other programs can use the same model through the local API, with the same code you would write for OpenAI.

One thing first, said plainly: Jan is a desktop app. It has no official Docker image and no official server mode. We looked in the README, the docs and the release files, and found installers only (.exe, .dmg, .deb, AppImage and Flatpak). So this guide installs it like any app, per system. Docker only appears as an optional extra later.

At a glance#

  • What you get: a private chat app, a model library (Hub) and a local API at http://127.0.0.1:1337/v1.
  • Time needed: about 20 minutes, most of it downloading.
  • Difficulty: easy. You run an installer, click a few buttons and copy one test command.
  • You need: a 64-bit PC or an Apple Silicon Mac, 8 GB RAM or more, 10 GB free disk space.
  • Offline? Yes, with local models. Anything you send to a cloud provider you add leaves your machine.
WhatValue
Current versionv0.8.7, released 20 Oct 2026 (GitHub releases)
Download sizeabout 560 MB (Windows), 1 GB (Linux .deb), 105 MB (Mac) before models
LicenceApache 2.0
Local APIhttp://127.0.0.1:1337/v1 (OpenAI-compatible)
Docker imagenone (desktop app)
Official docsjan.ai/docs/desktop

Why this version? We checked the issue tracker for v0.8.7. We found a few single bug reports and no pattern of install failures or data loss. The release notes say your data and settings carry over. So this guide uses the latest release. Two cautions: do not use 0.8.5 (its Linux AppImage crashed on every model load and some older NVIDIA cards failed; 0.8.6 fixed both), and Intel Macs cannot run local models from 0.8.5 on.

How it fits together#

You and your own scripts both talk to the Jan app. Jan runs the model with its built-in llama.cpp engine and keeps models and chats in its data folder.

How Jan works: you chat in the Jan window and your scripts call the local API on port 1337; Jan runs the model with its built-in llama.cpp engine, loads models and chats from the data folder on your disk, and only sends data to a cloud provider or through a Caddy HTTPS proxy if you add them

Two simple rules:

  1. The local API is off until you start it, and it listens on 127.0.0.1 (this computer only) by default.
  2. A cloud provider is optional. If you add one, that chat is no longer offline.

Before you start#

Any recent 64-bit system works, as long as it has enough memory for the model you choose.

SystemNeeds (from the Jan docs)
LinuxDebian/Ubuntu, Fedora/RHEL, Arch or openSUSE. CPU with AVX2 (Intel Haswell 2013+, AMD Excavator 2015+). 8 GB RAM minimum, 16 GB recommended. 10 GB free disk
WindowsWindows 10 or higher, x64 with AVX2 (or ARM64). 8 GB RAM minimum, 16 GB recommended. 10 GB free disk. NVIDIA, AMD or Intel Arc GPUs are supported
MacmacOS 13.6 or higher on Apple Silicon (M1 or newer). 10 GB+ free disk. Intel Macs cannot run local models since 0.8.5

You do not need the CUDA Toolkit: Jan bundles CUDA 13. GPUs or drivers that cannot use it fall back to Vulkan, so keep a current graphics driver installed. Docker and WSL2 are not needed.

Checklist:

  • [ ] You have 10 GB free (models add more)
  • [ ] Your graphics driver is up to date
  • [ ] Port 1337 is free (Jan does not pick another port by itself)
  • [ ] You know where your important files are (nothing here touches them)

Tested on 2026-10-26: not run. Commands and settings checked against the official Jan docs and the v0.8.7 release files.

Step 1: Install Jan#

Download the installer for your system and run it. Check the file against the hash GitHub shows next to the download on the release page if you like.

Linux#

Flatpak is the way the Jan docs recommend. It works on any distribution and updates with your system:

Run in terminalbash
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install flathub ai.jan.Jan
flatpak run ai.jan.Jan

Prefer a .deb (Ubuntu or Debian)?

Run in terminalbash
cd /tmp
curl -LO https://github.com/janhq/jan/releases/download/v0.8.7/Jan_0.8.7_amd64.deb
sudo apt-get install ./Jan_0.8.7_amd64.deb

The AppImage also works: download Jan_0.8.7_amd64.AppImage from the release page, run chmod +x on it and start it. The .deb does not auto-update, and the in-app updater is switched off for Flatpak.

Windows (PowerShell)#

Run in terminalpowershell
curl.exe -L -o "$env:TEMP\Jan-setup.exe" https://github.com/janhq/jan/releases/download/v0.8.7/Jan_0.8.7_x64-setup.exe
Start-Process "$env:TEMP\Jan-setup.exe"

On a Windows on ARM PC, use Jan_0.8.7_arm64-setup.exe instead. Use curl.exe, not curl: in Windows PowerShell 5 plain curl is an alias for another command.

Mac (Terminal)#

Run in terminalbash
cd ~/Downloads
curl -LO https://github.com/janhq/jan/releases/download/v0.8.7/Jan_0.8.7_universal.dmg
open Jan_0.8.7_universal.dmg

Drag Jan to Applications and open it.

Check it worked#

Jan opens a guided first-run wizard (welcome, engine setup, a first model, then a consent page). If you see it, the install is fine. Potential issue: a blank window or a crash on launch is covered in Troubleshooting.

Step 2: Download a model that fits your memory#

Open the Hub in Jan, search for a model and download it. Pick one that is smaller than about 80% of your RAM.

The Jan troubleshooting page gives the rule: keep the model under roughly 80% of your memory. That is about 6 GB on an 8 GB machine and 13 GB on a 16 GB machine. The sizes below are our rough guide for 4-bit models, not official numbers. Check each model's page.

Your memoryTry a model of about
8 GB RAM, 4-6 GB VRAM3-4 billion parameters, Q4
16 GB RAM, 8-12 GB VRAM7-9 billion parameters, Q4 or Q5
32 GB RAM or more, 16-24 GB VRAM14-32 billion parameters, Q4

On a Mac the docs say 8 GB suits up to about 3B models, 16 GB about 7B and 32 GB about 13B.

Open Jan first. The model steps are the same in the Jan window on every system:

Linux#

Start Jan from your app menu (Flatpak: flatpak run ai.jan.Jan).

Windows (PowerShell)#

Start Jan from the Start menu.

Mac (Terminal)#

Run in terminalbash
open -a Jan

Then in the Jan window:

  1. Click Hub, search, and download a model from HuggingFace.
  2. Or import your own .gguf file. For a model split into several files, point Jan at shard 1.
  3. The default context size is 8192 and can go up to 131072. A bigger context needs more memory, so lower it if you run out.

Check it worked#

Start a new chat, choose the model, and say hello. A reply means the engine loaded it. Open Settings > Hardware > GPUs to see whether your GPU is switched on.

Step 3: Start the local API and call it#

In Settings, pick a default model and start the server. Then one curl command proves it works.

  1. Open Settings > Local API Server.
  2. Under Default Model choose your local model.
  3. Set an API Key (any string you invent, such as a long random password). If you leave it empty, no key is needed, so always set one.
  4. Click Start Server.

The base URL is http://127.0.0.1:1337/v1. Find your model ID with /v1/models (or copy it in Jan).

Linux#

Run in terminalbash
curl http://127.0.0.1:1337/v1/models -H "Authorization: Bearer <YOUR_API_KEY>"

curl http://127.0.0.1:1337/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -d '{"model":"<YOUR_MODEL_ID>","messages":[{"role":"user","content":"Tell me a joke."}]}'

Windows (PowerShell)#

Codepowershell
$h = @{ Authorization = "Bearer <YOUR_API_KEY>" }
$b = '{"model":"<YOUR_MODEL_ID>","messages":[{"role":"user","content":"Tell me a joke."}]}'
Invoke-RestMethod http://127.0.0.1:1337/v1/chat/completions -Method Post -Headers $h -ContentType "application/json" -Body $b

Mac (Terminal)#

Same commands as Linux.

Check it worked#

You get a JSON answer with a choices list holding the model's reply. Expected shape (from the OpenAI format Jan follows, not a real capture):

File contenttext
{"object":"chat.completion","choices":[{"message":{"role":"assistant","content":"..."}}], ...}

The server settings, all from the official API docs:

SettingDefaultWhat it does
Server host127.0.0.1Only this computer. 0.0.0.0 opens it to your whole network
Server port1337Change it if the port is taken
API prefix/v1OpenAI-style path
API keyempty (off)Needed in Authorization: Bearer when set
Trusted hostsemptyHost names allowed to call the server
CORSonSwitch off if only scripts (not web pages) use the API
Execute tools on serveroffRuns MCP tool calls on the server side

The API server needs a local model to start. On Windows and Linux, closing the window keeps the server running if the "Run in background" option is on.

Optional: cloud providers, MCP and the tools#

Jan can also talk to cloud models and use tools, but both are optional.

  • Cloud providers: add one under Settings > Model Providers with its key and base URL (usually ending in /v1). Requests to it leave your machine, so that chat is not offline.
  • MCP (connectors): Jan supports MCP servers, so a model can call tools such as search. Only add servers you trust.
  • Shell tool: chat has a sandboxed shell tool. Since 0.8.7 you can switch it off from the tool menu in the message box.
  • Provider keys are kept in your operating system's keyring since 0.8.4, not in plain browser storage.

How Jan compares#

Pick Jan if you want a friendly desktop app. Pick Ollama with Open WebUI if you want a server with several users.

JanOllama + Open WebUILM Studio
FormDesktop appDaemon plus web pageDesktop app
LicenceApache 2.0Open sourceClosed-source app
OpenAI-style APIYes, port 1337Yes, port 11434Yes, port 1234
Official Docker or server modeNoYesNot checked
Several usersNoYes (Open WebUI)No
Cloud models in the same appYesLimitedLimited

The Jan column comes from the official docs. The other two are our general summary, not official claims. We have an Ollama guide too.

Optional: put a web page in front with Docker#

This is an extra, not part of Jan. If you want a browser chat page for other people, you can run Open WebUI in Docker and point it at Jan's API. We have a full Open WebUI and Ollama guide for the container side. The two Jan-specific settings are the API address and your key, for example:

File contentyaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:<pinned-tag>
    container_name: open-webui
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:8080"
    environment:
      OPENAI_API_BASE_URL: http://host.docker.internal:1337/v1
      OPENAI_API_KEY: ${JAN_API_KEY}
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - ~/docker_volumes/open-webui/data:/app/backend/data

Jan must listen on 0.0.0.0 for a container to reach it, so set an API key and the trusted hosts first. Take the pinned tag from the Open WebUI releases page. We did not test this file.

Put it behind HTTPS (with or without Traefik)#

Most people never need this. Jan's API listens on this computer only, and that is the safest setting. Read on only if other devices must use your API. Then you put a reverse proxy in front, so the key is not sent in plain text.

Rules for both routes:

  • Keep Jan on 127.0.0.1 when the proxy runs on the same computer.
  • Add the public host name to Trusted Hosts in Jan. If other devices get 403, this is why.
  • Never forward port 1337 to the internet.

With Traefik#

Choose this if Traefik already runs on this computer in Docker. Jan is not a container, so Traefik needs a file-provider route to the host. This is our example, not from the official docs (VERIFY against your Traefik setup). Jan must listen on 0.0.0.0 for a container to reach it.

File contentyaml
# dynamic config file, e.g. ~/docker_volumes/traefik/config/jan.yml
http:
  routers:
    jan:
      rule: "Host(`jan.<your-domain>`)"
      entryPoints: [https]
      tls: {}
      service: jan
  services:
    jan:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:1337"

Add extra_hosts: ["host.docker.internal:host-gateway"] to the Traefik service, and your domain, DNS and ports 80 and 443 must already work.

Without Traefik: Caddy#

Choose Caddy if you have no Traefik yet. It runs next to Jan, so Jan can stay on 127.0.0.1.

CaseResultYou do
Public domainAutomatic Let's EncryptDNS A record to this computer, ports 80 and 443 open
Home onlytls internal (Caddy's local certificate)Trust Caddy's root certificate on each device

Caddyfile for a public domain:

File contenttext
jan.example.com {
    reverse_proxy 127.0.0.1:1337
}

Caddyfile for home only (point the name at the Caddy computer):

File contenttext
jan.home.arpa {
    tls internal
    reverse_proxy 127.0.0.1:1337
}

Trust the root certificate (pki/authorities/local/root.crt in Caddy's data folder):

Run in terminalbash
# Linux: on the Caddy machine
sudo caddy trust
# other Linux devices, with root.crt copied over
sudo cp root.crt /usr/local/share/ca-certificates/caddy-root.crt && sudo update-ca-certificates
# Mac
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain root.crt
Run in terminalpowershell
# Windows (PowerShell as administrator)
certutil -addstore -f ROOT root.crt

Run Caddy:

Run in terminalbash
# Linux: install from the official apt repository (caddyserver.com/docs/install), then
sudo systemctl reload caddy
# Mac
brew install caddy && caddy run --config Caddyfile
Run in terminalpowershell
# Windows (PowerShell)
winget install CaddyServer.Caddy
caddy run --config Caddyfile

Or use the official image caddy:2.11.7 (Jan must then listen on 0.0.0.0, and the Caddyfile uses reverse_proxy host.docker.internal:1337). Save the Caddyfile as ~/docker_volumes/caddy/conf/Caddyfile. Create the folder first: mkdir -p ~/docker_volumes/caddy/conf (Windows PowerShell: New-Item -ItemType Directory -Force "$HOME\docker_volumes\caddy\conf"). Caddy gets the whole conf folder, not one file, because Caddy's Docker docs warn that editors can break a single-file mount.

File contentyaml
services:
  caddy:
    image: caddy:2.11.7
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - ~/docker_volumes/caddy/conf:/etc/caddy:ro
      - ~/docker_volumes/caddy/data:/data
      - ~/docker_volumes/caddy/config:/config

Check it worked:

Run in terminalbash
curl -I https://jan.example.com/v1/models -H "Authorization: Bearer <YOUR_API_KEY>"

Expected: HTTP/2 200. A 401 means the key is missing, a 403 means the host is not in Trusted Hosts.

Security and testing#

Keep the API on this computer, always use a key and keep secrets out of scripts.

  • Default is safest: host 127.0.0.1. Use 0.0.0.0 only on a trusted home network, with an API key and Trusted Hosts. Version 0.8.5 fixed a flaw so Trusted Hosts is enforced on 0.0.0.0, so stay on 0.8.5 or newer (GitHub advisory GHSA-x6p8-7cp8-c3p6, as reported by Perplexity; VERIFY).
  • Never port-forward 1337 to the internet.
  • Key in a file, not in the script. Save it in an environment variable or a .env file and lock it:
Run in terminalbash
echo 'JAN_API_KEY=<YOUR_API_KEY>' > ~/.jan-env && chmod 600 ~/.jan-env
  • Switch CORS off if only scripts call the API.
  • Download from the official release page only, and compare the hash.

Tests:

Run in terminalbash
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:1337/v1/models
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:1337/v1/models -H "Authorization: Bearer <YOUR_API_KEY>"

Expected: the first prints 401 (a key is set and you sent none), the second prints 200.

Troubleshooting#

ProblemSolution
401 UnauthorizedSend Authorization: Bearer <YOUR_API_KEY>
404 Not FoundCheck the model ID and the /v1 prefix
403 from another deviceAdd the host name to Trusted Hosts in Local API Server settings
Address already in use on 127.0.0.1:1337Quit the old Jan process, or change the port. Jan does not pick another port
Blank window or crash on launchFully quit Jan, rename store.json in the data folder, start again
The provided PTX was compiled with an unsupported toolchainOld NVIDIA GPU on v0.8.5: update to v0.8.6 or newer
unknown model architectureThe engine is too old for that model: update Jan
failed to allocate ... buffer, out of memory, cudaMallocSmaller model, lower context, fewer GPU layers
request (N tokens) exceeds the available context sizeRaise the context size
jan-llama-worker did not report a port within ...Slow load (timeout 600 s): wait, or use a smaller model or a faster disk

Where the logs live (logs/app.log inside the data folder):

SystemPath
Linux (.deb / AppImage)~/.local/share/Jan/data/logs/app.log
Linux (Flatpak)~/.var/app/ai.jan.Jan/data/Jan/data/logs/app.log
Windows%APPDATA%\Jan\data\logs\app.log
Mac~/Library/Application Support/Jan/data/logs/app.log

Since 0.8.5 the engine runs in its own process called jan-llama-worker, so look for that name in the log when a model fails to load. Redact private details before you share a log.

Known bugs#

Open on GitHub when we read it (2026-10-26):

  • #9435: on Windows the jan-llama-worker process can hang on "Working" after MCP tool calls. If you hit it, switch off your MCP servers.
  • #9407: the bundled engine cannot be updated separately. You wait for an app update to support brand-new models.
  • #9317: long chats with remote models can fail with "prompt is too long" because auto-compact does not run for them.
  • Intel Macs: no local models since 0.8.5 (official docs).

Updates and backups#

Update from the app (or Flatpak), and back up the data folder.

  • Windows, Mac and AppImage: Jan updates itself. Check the release notes first, especially the Migration part when you jump several versions.
  • Linux Flatpak: flatpak update ai.jan.Jan.
  • Linux .deb: no auto-update. Download the new .deb and install it the same way as before.

Your data and settings are kept across reinstalls. Back up anyway. Models make the archive huge, so skip them and download them again if needed (they live in llamacpp/models in the data folder).

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/jan-backup
tar czf ~/docker_volumes/jan-backup/jan-$(date +%F).tgz \
  --exclude='Jan/data/llamacpp/models' -C ~/.local/share Jan

Windows (PowerShell)#

Codepowershell
New-Item -ItemType Directory -Force "$HOME\docker_volumes\jan-backup" | Out-Null
$files = Get-ChildItem "$env:APPDATA\Jan\data" | Where-Object Name -ne 'llamacpp'
Compress-Archive -Path $files.FullName -DestinationPath "$HOME\docker_volumes\jan-backup\jan-$(Get-Date -Format yyyy-MM-dd).zip" -Force

Mac (Terminal)#

Run in terminalbash
mkdir -p ~/docker_volumes/jan-backup
tar czf ~/docker_volumes/jan-backup/jan-$(date +%F).tgz \
  --exclude='Jan/data/llamacpp/models' -C ~/Library/"Application Support" Jan

Schedule it: Linux and Mac with cron at 03:00 (0 3 * * * <path-to-script>), Windows with Task Scheduler. Quit Jan before backing up so files are not half-written.

Restore test#

Do this once, before you need it:

Run in terminalbash
mkdir /tmp/jan-test && tar xzf ~/docker_volumes/jan-backup/jan-*.tgz -C /tmp/jan-test
ls /tmp/jan-test/Jan/data

You should see your threads folder and logs. On a spare computer, quit Jan, move its Jan folder aside, copy the backup in, start Jan and check that your chats appear. If not, put the old folder back.

Performance and resources#

The biggest speed-up is a model that fits fully in GPU memory. We did not measure speed ourselves, because it depends on your hardware and model.

  • Check Settings > Hardware > GPUs and make sure your GPU is on.
  • Keep model plus context under about 80% of memory. Lower the context size if you run out.
  • Since 0.8.5 each chat's prompt cache is kept on disk (default cap 8192 MiB). You can turn this off under Settings > Model Providers > Llama.cpp.
  • The engine runs in its own worker process, so an engine crash does not close the app.
  • Watch memory while a model runs with Task Manager (Windows), Activity Monitor (Mac) or htop (Linux).

FAQ#

Is Jan really offline? Yes, with local models. Anything routed to a cloud provider you added leaves your machine.

Can I run Jan in Docker or headless? Not officially. Jan is a desktop app. For a headless server, run llama-server yourself or use Ollama.

Will my chats survive an update? The release notes say data and settings carry over. Back up first anyway.

Why do I get 403 from another computer? Its host name is not in Trusted Hosts. Add it in Local API Server settings.

Why can't my Intel Mac run local models? The bundled engine needs Apple Silicon since 0.8.5. Use a cloud provider there, or a newer Mac.

Can Claude Code or other tools use Jan? Any tool that accepts an OpenAI-style base URL can: give it http://127.0.0.1:1337/v1 and your key.

Sources#

Checked against the official docs on 2026-10-26. Not run by DIY Lab Hub. Items marked VERIFY are not confirmed in the official docs.