# Self-host Umami on a VPS

> Run Umami, simple cookie-free website analytics, on your own VPS with PostgreSQL in Docker and HTTPS on your own domain.

Source: https://vpsnine.com/help/self-host-umami · Updated: 2026-10-21

To self-host Umami on a VPS, run its Docker Compose setup (Umami and PostgreSQL) with the app on localhost, change the default `admin` / `umami` login before anyone can reach it, and serve it over HTTPS on a domain such as `stats.example.com`. On VPSNine the [Umami one-click app](https://vpsnine.com/apps/umami) does all of that except naming the domain, which takes one command.

Umami counts page views, referrers, devices and custom events without cookies. It suits a few sites that want light statistics without a heavy database to look after.

## What you need

- The Budget plan (2 GB) is enough for Umami and PostgreSQL with modest traffic. Umami publishes no minimum; a busy site grows the database, so watch disk and memory and move up when PostgreSQL wants more. The [plans page](https://vpsnine.com/plans) has the specs.
- A domain or subdomain for it, like `stats.example.com`. The tracking script has to load over HTTPS from your sites, so this isn't optional.

## Install it with the one-click app

Order a server with the [Umami app](https://vpsnine.com/apps/umami). It installs Docker and runs the compose setup from Umami's repository (Umami's image and `postgres:15-alpine`) in `/opt/umami`, with generated secrets in `/opt/umami/.env`. Umami listens only on `127.0.0.1:3000`. Umami ships with the login `admin` / `umami`; the installer changes that password through Umami's API before anything can reach it, and Umami has no public sign-up.

1. From your computer, open a tunnel to it:

   ```bash
   ssh -L 3000:127.0.0.1:3000 root@203.0.113.10
   ```

   In that session, run `cat /root/umami-admin.txt` for the password, then open `http://localhost:3000` and log in as `admin`.

2. Set up HTTPS (next section).

3. Add your website in Umami's settings and paste its tracking script into your pages. Each website gets its own script and dashboard.

On the server, `curl http://127.0.0.1:3000/api/heartbeat` answers when Umami is up.

## Put it on your domain with HTTPS

Point an `A` record for `stats.example.com` at the server, allow ports 80 and 443 in [the panel firewall](https://vpsnine.com/help/server-firewall), then run:

```bash
vps9-https stats.example.com
```

It installs Caddy from Caddy's own packages, writes a Caddyfile that proxies the domain to Umami on `127.0.0.1:3000`, and reloads Caddy, which gets and renews the certificate. Umami needs no settings changed for this, so there's no app step. From then on, log in at `https://stats.example.com`, and the tracking script loads from that domain:

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

Copy the exact snippet from Umami's website settings, which fills in the ID for you.

## Doing it by hand on another server

[Umami's install guide](https://docs.umami.is/docs/install) uses the compose file in its repository:

```bash
git clone https://github.com/umami-software/umami.git
cd umami
docker compose up -d
```

Before starting it, edit the compose file: set your own database password, set `APP_SECRET` to a random string (`openssl rand -hex 32`), and bind the port to `127.0.0.1:3000:3000` so Docker doesn't publish it to the internet. Then open it through an SSH tunnel and change the `admin` / `umami` password straight away. Put Caddy or nginx in front for HTTPS, as in [Serve a site with nginx and HTTPS](https://vpsnine.com/help/nginx-and-https).

## Updates and backups

Read the release notes, then:

```bash
cd /opt/umami
docker compose pull
docker compose up -d
```

The one-click app turns on the operating system's automatic security updates; Umami's images are yours to update.

Back up the database with `pg_dump`, and keep `/opt/umami/.env` with it, since it holds the database password and app secret:

```bash
cd /opt/umami
docker compose exec -T db pg_dump -U umami umami > /root/umami-$(date +%F).sql
cp .env /root/umami-env-$(date +%F)
```

Copy both off the server. [Backups you should run](https://vpsnine.com/help/backups-you-should-run) shows how to schedule it.

## When it goes wrong

- **Visits from some people never show up**: some ad blockers block Umami's default script name. Umami can serve the script and its collection endpoint under other names with `TRACKER_SCRIPT_NAME` and `COLLECT_API_ENDPOINT`. Add them to the `umami` service's `environment` in `/opt/umami/compose.yaml`, for example `TRACKER_SCRIPT_NAME: stats.js` and `COLLECT_API_ENDPOINT: /api/hit`, run `docker compose up -d`, and change the `src` in your pages to match.
- **No visits at all**: the script isn't loading. Open your site with the browser's developer tools on the Network tab and check the request to `stats.example.com` succeeds, and that `data-website-id` matches the website in Umami.
- **`https://stats.example.com` doesn't load**: DNS doesn't point at the server yet, or ports 80 and 443 are closed in the panel firewall. Check with `getent hosts stats.example.com` on the server and run `vps9-https stats.example.com` again once it resolves.
