# How to self-host Umami with Docker Compose

> Deploy Umami web analytics with Docker Compose and Postgres in 10 minutes: APP_SECRET, default login, HTTPS reverse proxy, tracking code, backups and upgrades.

## Key facts

| Fact | Value |
|---|---|
| App | Umami (https://appsgit.com/apps/umami) |
| Difficulty | beginner |
| Time | about 10 minutes |
| Requirements | 1 vCPU / 1 GB RAM; Docker + Docker Compose v2; A domain name for the tracking script |
| Last updated | 2026-10-06 |

## What is Umami?

Umami is a simple, fast and privacy-focused web analytics platform, often used as a Google Analytics alternative. It is open source under the MIT license, collects no personal data, sets no cookies and has a clean dashboard for pageviews, referrers, devices, locations and custom events. One instance can track any number of websites.

## Requirements

- A Linux server with 1 vCPU and 1 GB of RAM.
- Docker Engine and Docker Compose v2.
- A domain name such as `stats.example.com`, so the tracking script loads over HTTPS.

## Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed. If you need Docker, follow the [official install guide](https://docs.docker.com/engine/install/ubuntu/). Create a project folder:

```bash
mkdir -p ~/umami && cd ~/umami
```

## Step 2: Create the Docker Compose file

This follows the official Compose file, which runs Umami with Postgres. Save as `docker-compose.yml`:

```yaml
services:
  umami:
    image: ghcr.io/umami-software/umami:latest
    restart: always
    init: true
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      DATABASE_URL: postgresql://umami:${POSTGRES_PASSWORD}@db:5432/umami
      APP_SECRET: ${APP_SECRET}
      TWO_FACTOR_ENCRYPTION_KEY: ${TWO_FACTOR_ENCRYPTION_KEY}
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat"]
      interval: 10s
      timeout: 5s
      retries: 5

  db:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - umami-db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami -d umami"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  umami-db-data:
```

Create `.env` in the same folder:

```bash
POSTGRES_PASSWORD=CHANGE_ME
APP_SECRET=CHANGE_ME
TWO_FACTOR_ENCRYPTION_KEY=CHANGE_ME
```

Generate each value with `openssl rand -hex 32`. Use hex for the database password so it is safe inside the `DATABASE_URL`. `APP_SECRET` signs login tokens, and `TWO_FACTOR_ENCRYPTION_KEY` (a 64-character hex string) encrypts two-factor secrets. The port is bound to `127.0.0.1` so the dashboard is only reachable through your HTTPS proxy. To pin a version instead of `latest`, pick a tag from the [releases page](https://github.com/umami-software/umami/releases).

## Step 3: Start and open the app

```bash
docker compose up -d
docker compose logs -f umami
```

On first start Umami creates its database tables. Finish Step 4, then open `https://stats.example.com`, or test via an SSH tunnel with `ssh -L 3000:127.0.0.1:3000 user@server`. Sign in with the default credentials, username `admin` and password `umami`, then change the password straight away under Settings, Profile.

Add a website under Settings, Websites, then open its "Tracking code" tab. Paste the snippet into the `<head>` of your site:

```html
<script defer src="https://stats.example.com/script.js" data-website-id="YOUR-WEBSITE-ID"></script>
```

## Step 4: Put it behind HTTPS

With [Caddy](https://caddyserver.com/docs/) on the host:

```caddyfile
stats.example.com {
    encode zstd gzip
    reverse_proxy 127.0.0.1:3000
}
```

Caddy issues the certificate automatically and forwards the client IP, which Umami needs for location data. With Nginx Proxy Manager, create a proxy host for port 3000 and request a Let's Encrypt certificate. Ad blockers often block `script.js` on known analytics hosts; setting the `TRACKER_SCRIPT_NAME` environment variable to a custom name such as `stats.js` reduces that.

## Backups and upgrades

Everything lives in Postgres. Dump it regularly:

```bash
docker compose exec -T db pg_dump -U umami umami | gzip > umami-$(date +%F).sql.gz
```

Store the dump off-site, along with your `.env`. Restore by piping the dump into `psql` on a fresh database.

Upgrade with:

```bash
docker compose pull && docker compose up -d
```

Umami applies database migrations automatically on start. For major versions, read the release notes first, because some major upgrades require a migration step.

## Troubleshooting

- **No data appears:** the website ID in the snippet is wrong, or an ad blocker in your test browser blocks the script. Test in a private window without extensions.
- **All visitors show the same location:** the reverse proxy is not forwarding the client IP in `X-Forwarded-For`.
- **Container restarts with a database error:** `DATABASE_URL` does not match the Postgres credentials, often because the password contains special characters. Use a hex password.
- **Cannot log in with admin/umami:** the database was created by an earlier install with a different password. Reset it in the database or restore your backup.

## Next steps

Track custom events with `data-umami-event` attributes, create teams to share dashboards, set up public share links for open stats, and add more websites to the same instance.

## FAQ

### What port does Umami use?

Umami listens on port 3000. You reach the dashboard at http://SERVER_IP:3000, or on your own domain behind a reverse proxy.

### What is the default Umami login?

A new Umami install creates the user admin with the password umami. Sign in and change that password immediately.

### Is Umami free?

Yes. Umami is free and open source under the MIT license. Umami Cloud is an optional hosted service with a free tier and paid plans.

### Does Umami use cookies?

No. Umami does not set cookies and does not collect personal data. It anonymises visitors with a salted hash that rotates, which is why many sites use it without a consent banner.

### Umami vs Plausible?

Both are lightweight, privacy-friendly Google Analytics alternatives. Umami runs on a single Postgres database and is easier to host on a small server, while Plausible uses ClickHouse and handles very high traffic volumes.

Prefer not to do it yourself? [appsgit installation help](https://appsgit.com/services/install) installs it on your server for a fixed quote.

---

Canonical page: https://appsgit.com/guides/umami
Source: appsgit (https://appsgit.com), the app store for github. Data from the GitHub API, refreshed nightly.
Machine access: JSON API https://appsgit.com/api/v1/apps (OpenAPI: https://appsgit.com/openapi.json), MCP server https://mcp.appsgit.com/mcp, full index https://appsgit.com/llms-full.txt.
