Dealownia
Menu
sprawdzono – jak sprawdzamy oferty

Umami zamiast Google Analytics: instalacja na własnym VPS

Umami w Docker Compose z Postgresem, nginx jako reverse proxy, HTTPS, kod śledzący, codzienna kopia bazy i realny koszt utrzymania analityki na własnym VPS.

Aplikacje na własnym serwerzezaktualizowano 6 min czytania

Redakcja serwisu Dealownia · ceny i fakty ze stron dostawców, jak sprawdzamy

Umami pod https://stats.example.pl, z Postgresem w Dockerze, dostępne tylko przez nginx i z nocną kopią bazy – w pięciu krokach. Umami nie używa ciasteczek, więc do samej analityki nie potrzebujesz banera zgody (opis w polityce prywatności nadal jest potrzebny). Oprogramowanie jest darmowe; miesięczny koszt to cena VPS-a albo jego część, jeśli Umami działa obok strony i innych narzędzi. Jedna instancja obsłuży wiele stron – każdą dodajesz w panelu osobno.

Czego potrzebujesz

  • VPS z Ubuntu 24.04 LTS przygotowany jak w poradniku od zera: użytkownik z sudo, ufw, nginx, Docker z wtyczką Compose.
  • Minimum: 1 vCPU, 1 GB RAM (z plikiem swap), 10 GB dysku. Dokumentacja Umami nie podaje wymagań pamięci; orientacyjnie kontener Umami zajmuje ok. 180 MiB RAM po starcie, a Postgres ok. 65 MiB – sprawdź u siebie docker stats. Jeśli na tym samym serwerze ma działać więcej narzędzi, weź 2 GB.
  • Subdomenę, np. stats.example.pl, z rekordem A wskazującym serwer.

Na Umami z Postgresem wystarczy plan z 1–2 GB RAM.

Krok 1. Katalog i sekrety

bash
sudo mkdir -p /opt/apps/umami && sudo chown deploy:deploy /opt/apps/umami
cd /opt/apps/umami
cat > .env <<EOF
UMAMI_DB_PASSWORD=$(openssl rand -hex 24)
UMAMI_APP_SECRET=$(openssl rand -hex 32)
EOF
chmod 600 .env

Hasła w postaci szesnastkowej nie zawierają znaków @, / ani :, które psują adres DATABASE_URL. Docker Compose sam wczytuje plik .env z katalogu projektu i podstawia zmienne ${...}.

Krok 2. Plik compose.yaml

yaml
services:
  umami:
    image: ghcr.io/umami-software/umami:latest
    restart: unless-stopped
    environment:
      DATABASE_URL: postgresql://umami:${UMAMI_DB_PASSWORD}@db:5432/umami
      APP_SECRET: ${UMAMI_APP_SECRET}
      DISABLE_TELEMETRY: "1"
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:3000:3000"
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 5

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

Co tu jest ważne:

  • Obraz i zmienne pochodzą z oficjalnego pliku compose Umami. Jedyna wymagana zmienna to DATABASE_URL; APP_SECRET zabezpiecza tokeny logowania. Według aktualnej dokumentacji Umami działa tylko z PostgreSQL (od wersji 12.14). Przy obrazie Umami zostajemy przy latest, bo dokumentacja instalacji podaje tylko ten tag – przed każdym docker compose pull zrób kopię bazy (krok 5) i przeczytaj notatki do wydania. Postgres przypinamy do wersji głównej (17-alpine), bo jej zmiana wymaga migracji danych.
  • Port jest opublikowany tylko na 127.0.0.1. Docker omija reguły ufw, więc "3000:3000" wystawiłoby panel na świat bez HTTPS.
  • Postgres 17 trzyma dane w /var/lib/postgresql/data. Jeśli wybierzesz obraz postgres:18, montuj /var/lib/postgresql – od wersji 18 zmieniła się ścieżka i stary punkt montowania nie zachowa danych.

Uruchom i sprawdź:

bash
docker compose up -d
docker compose ps
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/api/heartbeat

Oczekujesz dwóch kontenerów w stanie healthy i kodu 200. Pierwszy start trwa dłużej, bo Umami tworzy tabele w bazie.

Krok 3. nginx i HTTPS

Plik /etc/nginx/sites-available/stats.example.pl:

nginx
server {
    listen 80;
    listen [::]:80;
    server_name stats.example.pl;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
bash
sudo ln -s /etc/nginx/sites-available/stats.example.pl /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d stats.example.pl

Nagłówek X-Forwarded-For jest potrzebny, żeby Umami widział adres odwiedzającego, a nie adres nginx – inaczej każdy gość wyglądałby jak ten sam komputer.

Krok 4. Pierwsze logowanie i strona

Wejdź na https://stats.example.pl. Domyślne konto to admin z hasłem umami – zmień hasło od razu (ustawienia profilu), bo panel jest publicznie dostępny. Potem dodaj stronę w ustawieniach (Websites → Add website) i skopiuj kod śledzący. Wstaw go w <head> każdej strony:

html
<script
  defer
  src="https://stats.example.pl/script.js"
  data-website-id="WKLEJ-ID-STRONY"
  data-domains="example.pl,www.example.pl"
  data-do-not-track="true"
></script>

data-domains sprawia, że skrypt liczy tylko ruch z podanych hostów – wersja testowa i localhost nie zaśmiecą statystyk. data-do-not-track respektuje ustawienie DNT przeglądarki; dokumentacja Umami zaznacza, że nie zastępuje to rozwiązania zgód.

Krok 5. Kopia bazy co noc

Skrypt /opt/apps/umami/backup.sh:

bash
#!/usr/bin/env bash
set -euo pipefail
umask 077
cd /opt/apps/umami
install -d -m 700 backup
docker compose exec -T db pg_dump -U umami -Fc umami > "backup/umami-$(date +%F).dump"
find backup -name 'umami-*.dump' -mtime +7 -delete
bash
chmod +x /opt/apps/umami/backup.sh
sudo /opt/apps/umami/backup.sh && sudo ls -lh /opt/apps/umami/backup
echo "30 3 * * * root /opt/apps/umami/backup.sh >>/var/log/umami-kopia.log 2>&1" | sudo tee /etc/cron.d/umami-kopia

Format -Fc jest skompresowany i odtwarza się przez pg_restore:

bash
docker compose exec -T db pg_restore -U umami -d umami --clean --if-exists < backup/umami-2026-11-11.dump

Kopie leżą w /opt/apps/umami/backup (prawa 700, pliki czyta tylko root) – tak samo jak w pozostałych poradnikach o narzędziach w Dockerze. Kopia na tym samym dysku chroni przed pomyłką, ale nie przed awarią serwera, więc wysyłaj ją też w zaszyfrowanej postaci (np. rclone crypt, opisany w poradniku o kopiach poza serwerem) do innej firmy niż dostawca VPS-a. Na początku takie archiwum ma kilkaset kilobajtów, więc darmowe miejsce w chmurze w zupełności wystarcza.

Ile to kosztuje miesięcznie

  • Umami, Postgres, nginx, certyfikat: 0 zł.
  • VPS: jeśli stawiasz go tylko pod Umami, płacisz pełną cenę najmniejszego planu z 1–2 GB RAM. Jeśli Umami działa obok strony i innych narzędzi, to ułamek tej kwoty. Aktualne ceny planów porównujesz w rankingu VPS.
  • Domena: Umami nie potrzebuje osobnej, wystarczy subdomena.
  • Twój czas: aktualizacja raz na kilka tygodni (docker compose pull && docker compose up -d) i rzut oka na kopie.

Najczęstsze problemy

  • Kontener umami restartuje się w pętli. Zwykle zła wartość DATABASE_URL: literówka, hasło ze znakami specjalnymi albo baza jeszcze nie wstała. Sprawdź docker compose logs umami. Hasła szesnastkowe i condition: service_healthy rozwiązują dwa ostatnie przypadki.
  • Panel pokazuje zero odwiedzin. Host strony nie pasuje do data-domains (częsty brak wersji z www) albo skrypt blokuje polityka CSP – wtedy script-src i connect-src muszą zawierać adres Umami. Sprawdź kartę „Sieć” w narzędziach przeglądarki.
  • Część ruchu ginie przez blokery reklam. Blokery znają ścieżkę script.js. Umami pozwala zmienić nazwę skryptu (TRACKER_SCRIPT_NAME) i adres wysyłania danych (COLLECT_API_ENDPOINT).
  • Wszyscy odwiedzający z jednego kraju albo z adresu serwera. Brak nagłówków X-Forwarded-For w nginx. Jeśli masz przed serwerem CDN z innym nagłówkiem, ustaw CLIENT_IP_HEADER.
  • Dane zniknęły po przebudowie kontenera. Wolumen Postgresa był zamontowany pod złą ścieżką (patrz uwaga o wersji 18). Zawsze sprawdzaj kopię przed zmianą głównej wersji obrazu bazy – przejście między głównymi wersjami Postgresa wymaga zrzutu i odtworzenia.

Co dalej

Dołóż monitoring dostępności – Uptime Kuma postawisz na tym samym serwerze w kilka minut. Jeśli chcesz mieć analitykę, monitoring i stronę w jednym pliku, zobacz gotowy stack Docker Compose.

Powiązane poradniki