Umami + Portainer + Traefik = ❤️‍🔥

Hosting Umami with Portainer and Exposing with Traefik

Published on: 15-03-2024

Hit some hurdles with self-hosting Umami with Portainer and exposing it properly with Traefik... so just sharing the recipe and some tips!

This will assume you have a working Traefik + Portainer setup. You will find several tutorials on how to make that work 😅.

Tips

Make sure you properly configure CORS middleware - besides the origin, everything else should do fine.

For me, existing_network is a bridge network where traefik is configured and from where it receives all the trafik. Considering we are connecting to the Postgre instance through a different network (umami), traefik.docker.network is very important for traefik to know from which network to listen for requests.

In case you are trying to collect analytics from a Nuxt site using nuxt-umami make sure you configure it with version: 2.

docker-compose.yml

version: "3.7"
services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    environment:
      - TRACKER_SCRIPT_NAME=getinfo
      - APP_SECRET=random_string
      - DATABASE_URL=${DATABASE_URL}
      - DATABASE_TYPE=${DATABASE_TYPE}
      - HASH_SALT=${HASH_SALT}
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    ports:
      - 33000:3000
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=existing_network"
      - "traefik.constraint-label=existing_network"
      - "traefik.http.routers.umami.rule=Host(`<your domain>`)"
      - "traefik.http.routers.umami.priority=3"
      - "traefik.http.services.umami.loadbalancer.server.port=3000"
      - "traefik.http.routers.umami.middlewares=traefik-https-redirect,umami_cors"
      - "traefik.http.routers.umami.tls=true"
      - "traefik.http.routers.umami.tls.certresolver=<your-resolver>"
      - "traefik.http.middlewares.umami_cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
      - "traefik.http.middlewares.umami_cors.headers.accesscontrolallowheaders=*"
      - "traefik.http.middlewares.umami_cors.headers.accesscontrolalloworiginlist=https://tere.ro"
      - "traefik.http.middlewares.umami_cors.headers.accesscontrolmaxage=100"
      - "traefik.http.middlewares.umami_cors.headers.addvaryheader=true"
    networks:
      - umami
      - existing_network
    depends_on:
      - db
    restart: always
  db:
    image: postgres:15-alpine
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - DATABASE_TYPE=${DATABASE_TYPE}
      - HASH_SALT=${HASH_SALT}
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    networks:
      - umami
    volumes:
      - db:/var/lib/postgresql/data
    restart: always
volumes:
  db:
networks:
  existing_network:
    external: true
  umami:
    external: false

🙏🏻

Andrei Terecoasa ©