How to install Umami on a VPS
Umami is a lightweight analytics platform designed to provide useful website metrics without the tracking profile of many hosted tools. This guide deploys Umami with PostgreSQL and Docker Compose, adds HTTPS and explains how to connect the first website.
Prerequisites
Use Ubuntu 22.04 or 24.04 with SSH, a public IP and at least 1 GB of RAM for a small analytics instance. Create an A record such as analytics.example.com and allow ports 80 and 443. You also need a backup destination and a long random application secret.
Umami stores event data in PostgreSQL, so disk usage depends on traffic and retention. Do not expose PostgreSQL to the internet. Only the reverse proxy should be public.
Step 1, Connecting to your server
Connect and prepare a dedicated directory:
ssh root@SERVER_IP
apt update && apt upgrade -y
apt install -y ca-certificates curl
mkdir -p /opt/umami
cd /opt/umami
chmod 750 /opt/umamiCheck that ports 80, 443 and the internal application port are not occupied. Keep the Compose file and .env readable only by administrators.
Step 2, Installing Docker and Docker Compose
Install Docker Engine and the Compose plugin using Docker's current Ubuntu instructions. Confirm the installation:
docker --version
docker compose version
systemctl enable --now dockerUse the current Compose syntax and a supported package source. Keep the host patched before exposing the analytics endpoint.
Step 3, Running Umami with Docker Compose
Create .env with values that do not appear anywhere else:
POSTGRES_DB=umami
POSTGRES_USER=umami
POSTGRES_PASSWORD=REPLACE_WITH_A_RANDOM_VALUE
APP_SECRET=$(openssl rand -hex 32)
DATABASE_URL=postgresql://umami:REPLACE_WITH_A_RANDOM_VALUE@db:5432/umamiThis is critical โ without APP_SECRET, authentication tokens are not properly secured. Generate it with openssl rand -hex 32 and never share it. The password in DATABASE_URL must match POSTGRES_PASSWORD, with URL encoding if your generated value contains reserved characters. Create compose.yaml:
services:
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db_data:/var/lib/postgresql/data
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
restart: unless-stopped
depends_on:
- db
environment:
DATABASE_URL: ${DATABASE_URL}
APP_SECRET: ${APP_SECRET}
ports:
- "127.0.0.1:3000:3000"
volumes:
db_data:Set PostgreSQL timezone to UTC. Umami expects UTC for correct analytics aggregation.
Start and inspect the stack:
docker compose up -d
docker compose ps
docker compose logs --tail 100 umamiPin tested image tags before using the deployment for important reporting.
Step 4, Configuring the reverse proxy
Forward analytics.example.com from Caddy, Nginx or another supported proxy to 127.0.0.1:3000. Terminate TLS at the proxy, preserve the original host and protocol headers and keep port 3000 private. The analytics script must load over HTTPS when the website uses HTTPS, otherwise browsers can block it as mixed content.
If you use a host firewall, allow SSH, 80 and 443 only. Test certificate renewal and check that the proxy sends the correct Host header to Umami. Behind a CDN or proxy, set CLIENT_IP_HEADER and FORCE_SSL environment variables in the Umami service for correct IP geolocation.
Step 5, First access and initial setup
Open https://analytics.example.com and complete the first login. Change the default admin credentials (admin / umami) immediately. Create a website entry, copy the generated tracking snippet and add it to the site you want to measure.
Load the site in a private browser window and confirm that a page view appears. Check the hostname and timezone before inviting other users. Avoid collecting data you do not need, and document any consent requirements that apply to your audience.
Maintenance
Back up PostgreSQL and APP_SECRET together. Keep retention under control and monitor the database volume with df -h and PostgreSQL metrics. Update Umami after reviewing release notes, run the migration in the supported way and verify that reports still load.
If events stop arriving, inspect the browser network request, proxy logs and Umami logs in that order. Do not delete the database volume to fix a tracking problem.
Tools mentioned
Umami
โClean, privacy-minded website analytics with straightforward reports.
Free cloud plan: up to 3 websites, 100k events/month and 6-month retention; self-hosting is unlimited.