Server#

gptme provides multiple web-based interfaces for browser-based interactions, from lightweight options to sophisticated desktop-integrated experiences.

Installation#

To use gptme’s server capabilities, install with server extras:

pipx install 'gptme[server]'

Start the server, then open http://localhost:5700:

gptme-server

The server and modern web UI share one origin by default, so no separate frontend process or CORS configuration is required.

For more CLI options, see the CLI reference.

gptme-webui: Modern Web Interface#

The primary web interface is gptme-webui: a modern, feature-rich application that provides a complete gptme experience in your browser. (Originally a standalone repo, now merged into the main gptme repository.)

Try it now:

  • chat.gptme.org (latest version of gptme-webui, bring your own gptme-server)

  • gptme.ai (upcoming hosted gptme service)

Key Features:

  • Modern interface

  • Streaming responses

  • Mobile-friendly responsive design

  • Dark mode support

  • Conversation export and offline capabilities

  • Integrated computer use interface

  • Create your own persistent agents

Local use:

The modern UI is bundled in gptme release packages. Run gptme-server and open http://localhost:5700.

For frontend development, see the gptme-webui README. When Vite runs separately on port 5701, allow that development origin:

gptme-server --cors-origin 'http://localhost:5701'

Note

Connecting the hosted web UI to a local server (Chrome 142+). When you use the hosted web UI at chat.gptme.org with a gptme-server running on localhost, recent Chromium browsers (Chrome 142+) gate the connection behind a Local Network Access permission prompt. This check runs before CORS headers are evaluated, so the --cors-origin flag is necessary but no longer sufficient — you must also click Allow on the permission prompt for the page to reach your local server. Serving the web UI from a local origin (for example http://localhost:5701) avoids the prompt entirely, since that is a local-to-local request.

Note

Host-header validation. Bearer authentication is enabled for loopback and network binds alike. If an operator explicitly disables authentication with GPTME_DISABLE_AUTH, they can still opt into Host-header validation with gptme-server serve --allowed-hosts gptme.local (comma-separated, or via GPTME_SERVER_ALLOWED_HOSTS).

Self-Hosting with Docker Compose#

For a self-contained deployment, a docker-compose.yml is included at the repository root. It builds a lean image (scripts/Dockerfile.selfhost, gptme + the server extra only — no Node/agent tooling) and runs gptme-server with persistent volumes for config and conversation logs.

# Clone the repository
git clone https://github.com/gptme/gptme.git
cd gptme

# Configure: at least one provider key is required
cp .env.example .env
$EDITOR .env

# Build and start the server
docker compose up --build

The server listens on http://localhost:5700.

The modern web UI is bundled at the same origin — just open http://localhost:5700 in a browser. Being same-origin, it needs no CORS setup (you will still need the server token; see below).

To use the hosted web UI instead, open chat.gptme.org and point it at your server. That is a cross-origin setup, so uncomment the Compose command and set CORS_ORIGIN to the hosted UI (or your separately hosted UI).

Key .env settings:

  • OPENAI_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY — at least one is required.

  • GPTME_SERVER_TOKEN — auth token. The server enables auth by default when bound to 0.0.0.0 (as in the container), so set this and configure the web UI with the same value. If left blank, a token is auto-generated at startup — find it with docker compose logs.

  • CORS_ORIGIN — only needed for a separately hosted web UI; uncomment the Compose command and set this to that UI’s origin.

  • GPTME_SERVER_PORT — host port to publish (the container always listens on 5700).

Production Deployment: nginx Reverse Proxy#

The docker-compose setup above publishes the server on a plain HTTP port (5700 by default). For a public-facing deployment you should put it behind a reverse proxy that terminates TLS and forwards requests to the container. The example below uses nginx with a Let’s Encrypt certificate.

Warning

Do not expose the raw 5700 port to the internet. Bind the published port to loopback so only the proxy can reach it. In .env (or docker-compose.yml) set the publish address to 127.0.0.1:

ports:
  - "127.0.0.1:5700:5700"

Also set GPTME_SERVER_TOKEN to a strong value — the proxy handles TLS, but the token is what authenticates each request.

1. Obtain a TLS certificate with certbot (one-time, then auto-renewed):

sudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d gptme.example.com

Note

The --nginx plugin handles the ACME HTTP challenge through nginx itself, so you do not need to stop nginx first (unlike --standalone, which binds its own listener to port 80 and fails when nginx is already running).

2. nginx site config (/etc/nginx/sites-available/gptme):

server {
    listen 80;
    server_name gptme.example.com;
    # Redirect all HTTP to HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name gptme.example.com;

    ssl_certificate     /etc/letsencrypt/live/gptme.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gptme.example.com/privkey.pem;

    # Restrict to TLS 1.2/1.3 with strong ciphers (Mozilla "intermediate" profile)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    location / {
        proxy_pass http://127.0.0.1:5700;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # gptme-server streams responses over Server-Sent Events
        # (text/event-stream). Disable proxy buffering and use long
        # read timeouts so streamed tokens are flushed to the client
        # immediately rather than buffered until the response completes.
        proxy_buffering    off;
        proxy_cache        off;
        proxy_read_timeout 3600s;
        proxy_set_header   Connection "";
        proxy_http_version 1.1;
    }
}

3. Enable the site and reload nginx:

sudo ln -s /etc/nginx/sites-available/gptme /etc/nginx/sites-enabled/
sudo nginx -t        # validate config
sudo systemctl reload nginx

The server and bundled UI are now reachable together at https://gptme.example.com. If you instead use a separately hosted UI such as chat.gptme.org, set CORS_ORIGIN in .env to that UI’s origin and enable the Compose --cors-origin command.

Note

The proxy_buffering off and long proxy_read_timeout settings are the important part: without them nginx buffers the SSE stream and the chat appears to hang until each full response is ready, instead of streaming token by token.

Local-only access. If you only want the server reachable from the host itself (for example, behind a VPN or an SSH tunnel), skip the proxy entirely and keep the default loopback bind — open an SSH tunnel from your client with ssh -L 5700:127.0.0.1:5700 user@host and use http://localhost:5700.

Running as a systemd Service (pipx)#

If you installed gptme directly with pipx rather than Docker, you can run the server as a systemd service so it starts on boot and restarts on failure. A ready-to-edit unit template ships at scripts/gptme-server.service.

The template runs the server as a dedicated gptme user, reads secrets from /etc/gptme/server.env, binds loopback, and applies systemd hardening (ProtectSystem=strict, NoNewPrivileges, etc.). Install it with:

# Dedicated service user + pipx install of the entrypoint
sudo useradd --system --create-home --shell /usr/sbin/nologin gptme
sudo -u gptme pipx install 'gptme[server]'

# Pre-create config/data dirs (required: ProtectHome=read-only only bind-mounts
# paths that already exist; gptme initialises them at import time, which fails
# under the sandbox on a fresh install before any request is served)
sudo -u gptme mkdir -p /home/gptme/.config/gptme \
                       /home/gptme/.local/share/gptme \
                       /home/gptme/.local/state/gptme

# Secrets file (provider keys + GPTME_SERVER_TOKEN), not world-readable
sudo install -d -m 750 -o gptme -g gptme /etc/gptme
sudo install -m 640 -o gptme -g gptme /dev/null /etc/gptme/server.env
sudoedit /etc/gptme/server.env   # add ANTHROPIC_API_KEY=... etc.

# Download and install the unit (adjust User= and the ExecStart path)
sudo curl -fsSL https://raw.githubusercontent.com/gptme/gptme/master/scripts/gptme-server.service \
    -o /etc/systemd/system/gptme-server.service
sudo systemctl daemon-reload
sudo systemctl enable --now gptme-server

Tail logs with journalctl -u gptme-server -f. Because the unit binds 127.0.0.1, pair it with the nginx reverse proxy above to expose it over TLS. Set GPTME_SERVER_TOKEN in the env file to a stable secret so clients have a persistent credential across restarts. This is required for persistent deployments: if omitted the server generates a new random token at each startup, invalidating any client already configured with the previous token.

Basic Web UI#

A lightweight chat interface with minimal dependencies is bundled with the gptme server for simple deployments.

Access at http://localhost:5700 after starting gptme-server.

This interface provides basic chat functionality and is useful for:

  • Quick testing and development

  • Minimal server deployments

  • Environments with limited resources

Computer Use Interface#

The computer use interface provides an innovative split-view experience with chat on the left and a live desktop environment on the right, enabling AI agents to interact directly with desktop applications.

Warning

The computer use interface is experimental and has serious security implications. Please use with caution and see Anthropic’s documentation on computer use for additional guidance.

Docker Setup (Recommended):

# Clone the repository
git clone https://github.com/gptme/gptme.git
cd gptme

# Build and run the computer use container
make build-docker-computer
docker run -v ~/.config/gptme:/home/computeruse/.config/gptme -p 6080:6080 -p 8080:8080 gptme-computer:latest

Access Points:

Features:

  • Split-view interface with real-time desktop interaction

  • Toggle between view-only and interactive desktop modes

  • Automatic screen scaling optimized for LLM vision models

  • Secure containerized environment

Requirements:

  • Docker with X11 support

  • Available ports: 6080 (VNC) and 8080 (web interface)

Local Computer Use (Advanced)#

You can enable the computer tool locally on Linux systems, though this is not recommended for security reasons.

Requirements:

  • X11 server

  • xdotool package installed

Usage:

# Enable computer tool in addition to default tools
gptme --tools +computer

Set an appropriate screen resolution for your vision model before use.

For long-running visual workflows, prefer a specialized subagent profile to keep parent context smaller:

# Desktop interaction (mouse, keyboard, screenshots)
subagent(
    "computer-use",
    "Click the Submit button, wait for the modal, and screenshot the result",
)

# Web browsing and testing
subagent(
    "browser-use",
    "Open localhost:5173, capture a screenshot, and report UI issues",
)

Security#

This section describes the security model of gptme-server and the threat vectors it is designed (and not designed) to address.

Authentication Model#

gptme-server requires bearer authentication for capability-bearing API routes regardless of bind address. Loopback is a transport boundary, not an identity boundary: another local process must not gain shell and config access merely by reaching 127.0.0.1. A small set of public routes remain unauthenticated: the API root (/api/v2), version info (/api/v2/version), config metadata (/api/v2/config), Prometheus metrics (/api/v0/metrics), and the API documentation at /api/docs/. Set GPTME_SERVER_TOKEN to a fixed value; if unset the server generates one and prints it at startup.

  • GPTME_DISABLE_AUTH disables bearer checks entirely regardless of bind address. Use only behind an authenticated ingress.

Warning

An authorized API client (anyone who can reach the server with a valid token) can execute arbitrary shell commands through the agent. There is no additional sandboxing at the API layer. The security boundary is access to the server, not any individual endpoint.

Threat Model#

The server is hardened against browser-originating attacks that apply to local server access:

1. Cross-Site Request Forgery (CSRF)

A malicious web page cannot send credentialed cross-origin JSON requests to the local server because the browser’s CORS preflight blocks them: the server does not return Access-Control-Allow-Origin headers for arbitrary origins (only for the configured --cors-origin). Plain forms can POST without CORS, but cannot set Content-Type: application/json, so the server rejects them as malformed.

2. DNS Rebinding

A malicious site can re-resolve its hostname to 127.0.0.1 after the page loads and thereby bypass CORS. Bearer authentication still blocks access to capability-bearing routes because the page does not possess the token. If an operator explicitly disables bearer auth, --allowed-hosts can add Host-header validation as defense in depth.

What is NOT in scope:

  • An authorized client redirecting the agent to sensitive files: An authorized API client can already run cat /etc/passwd through the agent. Restricting which directories the agent starts in adds no security boundary — the agent can navigate anywhere from there.

  • Protecting one user from another on a shared server: gptme-server is single-user by design. Multi-user setups must gate access at the network or OS level.

Workspace PATCH Semantics#

Conversations have a workspace — the directory the agent treats as its working directory. The API exposes two operations that touch workspace:

  • PUT /api/v2/conversations/<id> (create): accepts any workspace the client supplies, including paths outside the conversation’s log directory. Rationale: an authorized client can already run arbitrary shell commands; workspace containment at creation adds no security boundary. Cloud pods and the workspace picker both rely on this to set a custom workspace on create.

  • PATCH /api/v2/conversations/<id>/config (update): accepts the round-trip of the already-persisted workspace (the webui settings dialog sends the full config including workspace on every save), but rejects any change that redirects the workspace outside the conversation’s log directory. Rationale: silently redirecting an existing agent’s workspace mid-conversation to an arbitrary path is plausibly a confused-deputy attack vector and is never needed for legitimate updates. If the workspace must change, delete and recreate the conversation.

    Warning

    Deleting a conversation is destructive: its persisted message history is permanently removed. Export or back up conversation logs before deleting if you need to preserve them.

This creates an intentional asymmetry — create-any, re-target-never — to minimize confused-deputy risk without breaking legitimate workflows.

REST API#

gptme-server provides a REST API for programmatic access to gptme functionality. This enables integration with custom applications and automation workflows.

The API endpoints support the core gptme operations including chat interactions, tool execution, and conversation management.

Note

API documentation is available when running the server. Visit the server endpoint /api/docs/ for interactive API documentation based on the OpenAPI spec (served at /api/docs/openapi.json).