Umami is an open-source, privacy-focused web analytics platform designed as a self-hosted alternative to Google Analytics. It avoids cookies and personally identifiable information, removes the need for cookie banners, and captures real-time metrics including visitor devices, geographic data, referrers, and custom events through a lightweight tracking script. This guide deploys Umami on a Linux server using Docker Compose with PostgreSQL as the database, Redis for session caching, and Traefik for automatic HTTPS through Let's Encrypt, then walks through directory setup, environment configuration, and integrating the tracking script into a sample website. By the end, you'll have a self-hosted Umami instance tracking real traffic on your own domain.
Set Up the Directory Structure, Configuration, and Environment Variables
Umami requires a project directory with persistent storage for the PostgreSQL database, Redis cache, and Let's Encrypt certificates. Environment variables control the domain, database credentials, application secret, and tracking customizations.
1. Create the project directory and move into it:
$ mkdir -p ~/umami/{pgdata,redis,letsencrypt}
$ cd ~/umami
-
pgdata/: Persists PostgreSQL database files. -
redis/: Stores Redis data for caching and session management. -
letsencrypt/: Stores Traefik ACME certificates for HTTPS renewal.
2. Generate a strong random secret for the application:
$ openssl rand -hex 32
Save the output for use in the environment file.
3. Create the environment file:
$ nano .env
Add the following configuration. Replace umami.example.com with your domain name, admin@example.com with your email address, GENERATED_SECRET with the generated random string, and STRONG_DATABASE_PASSWORD with a secure database password.
# Domain Configuration
DOMAIN=umami.example.com
LETSENCRYPT_EMAIL=admin@example.com
# Application Secret
APP_SECRET=GENERATED_SECRET
# PostgreSQL Configuration
POSTGRES_DB=umami
POSTGRES_USER=umami
POSTGRES_PASSWORD=STRONG_DATABASE_PASSWORD
DATABASE_URL=postgresql://umami:${POSTGRES_PASSWORD}@postgres:5432/umami
# Redis Configuration
REDIS_URL=redis://redis:6379
# Tracker Customization
TRACKER_SCRIPT_NAME=custom-stats
COLLECT_API_ENDPOINT=/custom-api/send
DISABLE_TELEMETRY=1
Save and close the file.
Note: The
TRACKER_SCRIPT_NAMEandCOLLECT_API_ENDPOINTvariables add an alternate path for the tracking script and collection endpoint, alongside the defaults, to help bypass ad blockers that specifically target/script.js. The default paths remain active.DISABLE_TELEMETRY=1prevents Umami from sending anonymous usage statistics.
Deploy with Docker Compose
The deployment stack runs four services: Traefik as the reverse proxy with automatic TLS, PostgreSQL for analytics data persistence, Redis for session caching, and the Umami web application. This configuration is based on the official Umami Docker Compose example, adapted to use Traefik and persistent storage.
1. Create the Docker Compose manifest:
$ nano docker-compose.yml
services:
traefik:
image: traefik:v3.7.0
container_name: umami-traefik
restart: unless-stopped
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
postgres:
image: postgres:17-alpine
container_name: umami-postgres
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ./pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB} -U ${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:8-alpine
container_name: umami-redis
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
volumes:
- ./redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
umami:
image: ghcr.io/umami-software/umami:3.1.0
container_name: umami
restart: unless-stopped
env_file: .env
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
labels:
- "traefik.enable=true"
- "traefik.http.routers.umami.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.umami.entrypoints=websecure"
- "traefik.http.routers.umami.tls=true"
- "traefik.http.routers.umami.tls.certresolver=letsencrypt"
- "traefik.http.services.umami.loadbalancer.server.port=3000"
Save and close the file. traefik handles reverse proxy and TLS termination, redirecting HTTP to HTTPS and provisioning Let's Encrypt certificates using the TLS-ALPN-01 challenge. postgres runs PostgreSQL 17 as the primary database for analytics data, website configurations, and user accounts. redis runs Redis 8 as the caching layer for server-side authentication sessions, reducing database load. umami runs the official Umami application pinned to version 3.1.0 and registers with Traefik for HTTPS routing on the configured domain.
2. Start the services:
$ docker compose up -d
3. Verify that all containers are running:
$ docker compose ps -a
The output displays four containers. postgres and redis show a healthy status; traefik and umami show as running, since those two have no configured health check.
4. View the service logs to confirm Umami connected to the database:
$ docker compose logs umami
The output displays Umami completing database migrations and reporting the application as ready.
Access and Configure Umami
After deployment, access the Umami dashboard using your configured domain, log in with the default administrator credentials, and rotate the password to secure the instance.
1. Open the login page:
Replace umami.example.com with your configured domain and open https://umami.example.com/login in a web browser.
2. Log in using the default administrator credentials. The username is admin and the password is umami.
Note: Change the default credentials immediately after the first login to secure your analytics instance.
3. Change the password:
At the bottom of the left sidebar, click admin and select Settings. Navigate to the Profile tab, click Change password, enter the current password (umami), enter your new secure password, and click Save.
Track a Sample Website
Umami tracks visitors through a lightweight JavaScript snippet embedded in your target website. The following steps add a website, retrieve the tracking code, embed it in a sample page, and verify that metrics appear in the dashboard.
Add a Website
Umami tracks each site separately, so a website entry must exist before its tracking code can be generated.
- In the Umami dashboard, click Websites in the left navigation pane.
- Click Add website.
- Enter a name such as
My Test Siteand a domain such astest.example.com. - Click Save.
Retrieve the Tracking Code
Each website gets a unique tracking snippet tied to its website ID.
- Find the new website in the list and click Edit.
- Navigate to the Tracking code tab.
- Copy the generated
<script>tag.
Note: Because
TRACKER_SCRIPT_NAME=custom-statswas set in the environment file, the generated tag uses/custom-statsas an additional path alongside the default/script.js. Using the custom path helps bypass ad blockers that specifically target the default filename.
Embed the Tracking Code
The script must load on every page you want Umami to track.
- Open the main HTML document or the global layout component of your sample web application.
- Paste the tracking code into the
<head>section. ReplaceYOUR_WEBSITE_IDwith the ID from your Umami dashboard andumami.example.comwith your domain:
<head>
<meta charset="UTF-8">
<title>Sample Web Application</title>
<script defer src="https://umami.example.com/custom-stats" data-website-id="YOUR_WEBSITE_ID"></script>
</head>
- Save the file and open the sample web application in a browser.
- Refresh the page a few times to simulate visitor traffic.
Verify Analytics Collection
Confirming that traffic appears in the dashboard validates that the tracking script is reaching the server.
- Return to the Umami dashboard and select your website.
- Review the main dashboard to verify captured page views, referrers, device types, and visitor data.
- Click the Realtime tab to monitor active visitors navigating the sample site.
Next Steps
Umami is running with a privacy-first, self-hosted analytics dashboard tracking live traffic. From here you can:
- Add more websites and compare traffic across properties from a single dashboard
- Configure custom events to track conversions, signups, or other in-app actions
- Enable email reports or connect the Umami API to pull metrics into external tooling
For the full guide with additional tips, visit the original article on Vultr Docs.
Top comments (0)