# Docker

> Deploy Helicone using Docker. Quick setup guide for running a containerized instance of the LLM observability platform on your local machine or server.

To run all services in a single Docker container, you can use the `helicone-all-in-one` image.

## Quick Start (Local)

Get [Docker](https://docs.docker.com/get-docker/) and run the container:

```bash
docker pull helicone/helicone-all-in-one:latest
docker run -d \
  --name helicone \
  -p 3000:3000 \
  -p 8585:8585 \
  -p 9080:9080 \
  helicone/helicone-all-in-one:latest
```

Access the dashboard at `http://localhost:3000`.

## Example to test the Jawn service

```bash
curl http://localhost:8585/healthcheck
```

<Note>
  Jawn no longer proxies LLM traffic: the `/v1/gateway/*` routes have been
  removed. To proxy requests through a self-hosted deployment, run the
  [AI Gateway](/gateway/overview) alongside Jawn.
</Note>

## Production Setup (Remote Server)

When deploying to a remote server (EC2, VPS, etc.), configure your server's public IP or domain:

```bash
# Replace YOUR_IP with your server's public IP or domain
export PUBLIC_URL="http://YOUR_IP:3000"
export JAWN_URL="http://YOUR_IP:8585"
export S3_URL="http://YOUR_IP:9080"

docker run -d \
  --name helicone \
  -p 3000:3000 \
  -p 8585:8585 \
  -p 9080:9080 \
  -e SITE_URL="$PUBLIC_URL" \
  -e BETTER_AUTH_URL="$PUBLIC_URL" \
  -e BETTER_AUTH_SECRET="$(openssl rand -base64 32)" \
  -e NEXT_PUBLIC_APP_URL="$PUBLIC_URL" \
  -e NEXT_PUBLIC_HELICONE_JAWN_SERVICE="$JAWN_URL" \
  -e NEXT_PUBLIC_IS_ON_PREM=true \
  -e S3_ENDPOINT="$S3_URL" \
  helicone/helicone-all-in-one:latest
```

## Environment Variables

The container uses these environment variables (with defaults for local development):

| Variable | Default | Description |
|----------|---------|-------------|
| `NEXT_PUBLIC_HELICONE_JAWN_SERVICE` | `http://localhost:8585` | URL browsers use to reach the API. **Must be public URL for remote deployments.** |
| `S3_ENDPOINT` | `http://localhost:9080` | URL browsers use for presigned URLs. **Must be public URL for remote deployments.** |
| `S3_ACCESS_KEY` | `minioadmin` | MinIO access key |
| `S3_SECRET_KEY` | `minioadmin` | MinIO secret key |
| `S3_BUCKET_NAME` | `request-response-storage` | S3 bucket for request/response bodies |
| `BETTER_AUTH_SECRET` | `change-me-in-production` | Auth secret. **Generate a secure value for production.** |
| `SITE_URL` | - | Public URL of the web dashboard |
| `BETTER_AUTH_URL` | - | Same as SITE_URL |
| `NEXT_PUBLIC_APP_URL` | - | Same as SITE_URL |
| `NEXT_PUBLIC_IS_ON_PREM` | - | Set to `true` for non-localhost deployments |

## Port Requirements

| Port | Service | Required For |
|------|---------|--------------|
| 3000 | Web Dashboard | Browser access |
| 8585 | Jawn API + LLM Proxy | Browser API calls, LLM proxying |
| 9080 | MinIO S3 | Request/response body storage |
| 5432 | PostgreSQL | Internal (can be restricted) |
| 8123 | ClickHouse | Internal (can be restricted) |

**Important:** Ports 3000, 8585, and 9080 must be accessible from browsers accessing the dashboard.

## User Account Setup

### Create Account

Navigate to `http://YOUR_IP:3000/signup` and create your account.

### Email Verification

The container doesn't include email services. Manually verify users:

```bash
docker exec -u postgres helicone psql -d helicone_test -c \
  "UPDATE \"user\" SET \"emailVerified\" = true WHERE email = 'your@email.com';"
```

### Organization Setup

Users need an organization. If you see "No organization ID found" errors:

```bash
# Get your user ID
docker exec -u postgres helicone psql -d helicone_test -c \
  "SELECT id, email FROM \"user\" WHERE email = 'your@email.com';"

# Create organization (save the returned ID)
docker exec -u postgres helicone psql -d helicone_test -c \
  "INSERT INTO organization (name, is_personal) VALUES ('My Org', true) RETURNING id;"

# Add user to organization (replace USER_ID and ORG_ID)
docker exec -u postgres helicone psql -d helicone_test -c \
  "INSERT INTO organization_member (\"user\", organization, org_role) \
   VALUES ('USER_ID', 'ORG_ID', 'admin');"
```

## LLM Proxying

The all-in-one image runs the dashboard and the Jawn API only. Jawn's
`/v1/gateway/*` proxy routes have been removed, so LLM requests must go through
the [AI Gateway](/gateway/overview), which you can deploy next to this image.

## Important Notes

### Data Persistence

Container restarts will wipe all data. For production, mount Docker volumes:

```bash
-v helicone-postgres:/var/lib/postgresql/data \
-v helicone-clickhouse:/var/lib/clickhouse \
-v helicone-minio:/data
```

### Security

Port 8585 does not require authentication for proxying requests. Anyone with access can proxy LLM requests through your endpoint. Restrict access via firewall rules.

### HTTPS

For HTTPS support, use a reverse proxy (Caddy, nginx, Traefik) in front of the container. See the [Cloud Deployment guide](/getting-started/self-host/cloud) for a Caddy example.

## Troubleshooting

### API calls fail with connection refused

The web app tries to connect to `localhost:8585` instead of your public IP. Verify the environment variable was set:

```bash
curl http://YOUR_IP:3000/__ENV.js | grep JAWN
# Should show your public IP, not localhost
```

### Infinite redirect loop

Missing `NEXT_PUBLIC_IS_ON_PREM=true` environment variable.

### "Invalid origin" error on sign-in

All URL environment variables must use the same origin (public IP or domain). Don't mix `localhost` with public IPs.

### "No organization ID found" error

User needs to be added to an organization. See the Organization Setup section above.
