GuiderFöretag och övervakningDashboards med Metabase

Kör Metabase-dashboards på dina egna data med Podman utan root

Metabase på Debian 13, verktyget med öppen källkod för frågor, diagram och dashboards på dina egna data, i rootless Podman med PostgreSQL under en egen användare bakom Caddy, där din databas läses via en inloggning som inte kan ändra något.

Testad på Metabase 0.64.2.2 på Debian 13 (trixie) på en server hos Melonslab Uppdaterad 14 oktober 2026

Rekommenderad server för guiden

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy · 2 vCPU · 8 GB Minne · 60 GB Lagring

Månadsvis, ingen bindningstid 7 dagars öppet köp

100 kr/mån

Beställ nu
På den här sidan

Det här sätter du upp

Metabase gör om data i din databas till svar, diagram och dashboards. Du bygger en fråga genom att välja en tabell, en summa och en gruppering, utan att skriva SQL, och Metabase ritar diagrammet. Den som kan SQL skriver det direkt. Frågorna samlas på dashboards som hela teamet kan öppna.

Metabase utvecklas av Metabase, Inc., ett företag i San Francisco, öppet på GitHub. Utgåvan här, utgåvan med öppen källkod, är gratis under licensen AGPL 3.0. Metabase säljer också utgåvorna Pro och Enterprise, med till exempel enkel inloggning via SAML och finare behörigheter, och Metabase Cloud, sin molntjänst. Som standard skickar Metabase anonyma användningsdata till Metabase, letar efter nya versioner hos Metabase och slår upp var varje inloggning kommer ifrån hos GeoJS, en tjänst för IP-uppslag, genom att skicka besökarens IP-adress. Steg 4 stänger av alla tre; en sida använder fortfarande GeoJS, som steg 10 förklarar.

Metabase sparar sina egna data, som användare, frågor och dashboards, i en egen databas. Utan inställningar blir det en fil i H2-format, som Metabase avråder från för riktig användning, så här får den PostgreSQL. Dina affärsdata läser den från din egen databas, via en inloggning som bara kan läsa.

Här körs Metabase som en pod under en egen användare som heter metabase, bakom Caddy från Podman-guiden, och läser en databas i PostgreSQL från PostgreSQL-guiden på samma server.

Varje steg nedan har körts på en nyinstallerad Melonslab VC-P Alloy (2 vCPU, 8 GB) med Debian 13:

  • Metabase 0.64.2.1 startade med sina egna data i PostgreSQL 18, och administratörskontot skapades via en SSH-tunnel innan Caddy sattes upp.
  • Metabase anslöt till en butiksdatabas i serverns PostgreSQL 18 via inloggningen som bara kan läsa. En fråga byggd utan SQL visade intäkter per månad, en SQL-fråga räknade betalda ordrar per stad, och båda lades på en dashboard.
  • En DELETE i en SQL-fråga misslyckades med cannot execute DELETE in a read-only transaction. När transaktionen ställdes om till skrivbar fick inloggningen ändå permission denied for table orders, och en fråga som tog längre än 60 sekunder stoppades.
  • En andra användare, utan rätt att skriva SQL, kunde öppna frågorna och fick ett fel när den försökte köra SQL mot databasen.
  • Utan e-post gav en ny användare ett tillfälligt lösenord i stället för en inbjudan. Med e-post uppsatt kom inbjudningar och återställning av lösenord fram, till en testbrevlåda på servern.
  • Gränssnittet visades på svenska.
  • Inloggningar sparades med besökarens riktiga IPv4-adress, och en förfalskad X-Forwarded-For-header struntades i.
  • En avlyssning av serverns trafik visade inga anslutningar till Metabase eller någon annan medan Metabase startade, startades om och användes, med ett undantag som steg 10 beskriver.
  • En uppdatering från Metabase 0.63 till 0.64 behöll frågorna och dashboardsen, och podman auto-update flyttade Metabase från 0.64.1 till 0.64.2.1. Metabase 0.64.2.2 startade senare med samma inställningar och läste butiksdatabasen. Metabase återställdes från en säkerhetskopia till en tom volym, och allt startade igen av sig självt efter en omstart av servern.

Metabase använde omkring 1,7 GB minne efter omstarten, nästan allt för Java, och dess egen PostgreSQL omkring 30 MB. Java låter Metabase använda upp till en fjärdedel av serverns minne, 2 GB på den här servern, så 4 GB är det minsta vi skulle köra den på tillsammans med PostgreSQL.

Innan du börjar

Du behöver:

  • en server uppsatt som i Podman-guiden, med Caddy igång;
  • PostgreSQL på samma server, som i PostgreSQL-guiden, med databasen du vill titta på;
  • en A-post och en AAAA-post för metabase.example.com som pekar på din server;
  • SSH-åtkomst till servern från din egen dator.

Exemplen använder metabase.example.com för Metabase, 203.0.113.10 för serverns IPv4-adress, och appdb och appuser för databasen och appens inloggning från PostgreSQL-guiden. Byt ut dem genomgående.

1. Skapa en inloggning som bara kan läsa

Metabase behöver bara läsa dina data. Ge den en egen inloggning som inte kan ändra något, så att ett misstag i en SQL-fråga, eller någon som tar sig in i Metabase, inte kan radera eller ändra dina data. Som root skapar du inloggningen med ett långt lösenord, som createuser frågar efter två gånger:

openssl rand -base64 24
sudo -u postgres createuser --pwprompt metabase_ro

Låt den sedan läsa tabellerna i appdb:

sudo -u postgres psql -d appdb <<'EOF'
ALTER ROLE metabase_ro SET default_transaction_read_only = on;
ALTER ROLE metabase_ro SET statement_timeout = '60s';
GRANT CONNECT ON DATABASE appdb TO metabase_ro;
GRANT USAGE ON SCHEMA public TO metabase_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase_ro;
ALTER DEFAULT PRIVILEGES FOR ROLE appuser IN SCHEMA public GRANT SELECT ON TABLES TO metabase_ro;
EOF

Vad raderna gör:

  • GRANT SELECT låter inloggningen läsa tabellerna som finns nu, och inget annat. Den kan inte lägga till, ändra eller radera rader, eller skapa tabeller.
  • ALTER DEFAULT PRIVILEGES ger den samma rätt till tabeller som appuser, appens egen inloggning, skapar senare, till exempel vid en uppdatering av appen.
  • default_transaction_read_only gör dessutom varje transaktion skrivskyddad, ett andra lås utöver rättigheterna.
  • statement_timeout stoppar varje fråga från Metabase efter 60 sekunder, så att en tung fråga inte kan hålla appens databas sysselsatt.

Spara lösenordet till steg 7. Ligger dina tabeller i ett annat schema än public upprepar du de tre sista raderna för det.

2. Skapa användaren

Som root:

useradd -m -s /bin/bash metabase
loginctl enable-linger metabase
machinectl shell metabase@

Allt fram till steg 6 körs som metabase.

3. Skapa hemligheterna

openssl rand -hex 24 | tr -d '\n' | podman secret create metabase-db-password -
openssl rand -hex 32 | tr -d '\n' | podman secret create metabase-encryption-key -

Den första är lösenordet till Metabases egen databas. Den andra är nyckeln som Metabase krypterar anslutningsuppgifterna till dina databaser med, som lösenordet för metabase_ro, innan de sparas. Utan nyckeln går uppgifterna i en säkerhetskopia inte att läsa, och du får ange dem igen, så steg 12 sparar en kopia.

4. Definiera podden

mkdir -p ~/.config/containers/systemd
cd ~/.config/containers/systemd

Skapa metabase.pod:

[Pod]
PodName=metabase
# Only Caddy, on this server, can reach Metabase: the port is not open to the internet.
PublishPort=127.0.0.1:8131:3000
# Lets Metabase reach PostgreSQL on this server, which listens on 127.0.0.1, at 169.254.1.3.
Network=pasta:--map-host-loopback,169.254.1.3

[Install]
WantedBy=default.target

Skapa metabase-db.container:

[Container]
ContainerName=metabase-db
Image=docker.io/library/postgres:18-alpine
Pod=metabase.pod
Volume=metabase-db:/var/lib/postgresql
Environment=POSTGRES_USER=metabase POSTGRES_DB=metabase
Secret=metabase-db-password,type=env,target=POSTGRES_PASSWORD
HealthCmd=pg_isready -U metabase -d metabase
HealthInterval=10s
Notify=healthy
AutoUpdate=registry

[Service]
Restart=always

Och metabase-app.container:

[Unit]
Requires=metabase-db.service
After=metabase-db.service

[Container]
ContainerName=metabase-app
Image=docker.io/metabase/metabase:v0.64.x
Pod=metabase.pod
Environment=MB_SITE_URL=https://metabase.example.com
Environment=MB_DB_TYPE=postgres MB_DB_HOST=127.0.0.1 MB_DB_PORT=5432 MB_DB_DBNAME=metabase MB_DB_USER=metabase
Environment=MB_ANON_TRACKING_ENABLED=false MB_CHECK_FOR_UPDATES=false MB_SEND_EMAIL_ON_FIRST_LOGIN_FROM_NEW_DEVICE=false
Environment=JAVA_TIMEZONE=Europe/Stockholm
Secret=metabase-db-password,type=env,target=MB_DB_PASS
Secret=metabase-encryption-key,type=env,target=MB_ENCRYPTION_SECRET_KEY
AutoUpdate=registry

[Service]
Restart=always

Vad inställningarna gör:

  • Network=pasta:--map-host-loopback,169.254.1.3 ger podden en adress, 169.254.1.3, som leder till 127.0.0.1 på servern. PostgreSQL från PostgreSQL-guiden lyssnar bara där, och poddens egen 127.0.0.1 är podden själv. Inne i podden svarar Metabases egen databas på 127.0.0.1:5432 och din på 169.254.1.3:5432. Alla andra program på servern som lyssnar på 127.0.0.1 nås också på den adressen, som de andra apparnas portar för Caddy, så den som kan lägga till databaser i Metabase, alltså dess administratörer, kan prova dem.
  • MB_SITE_URL är den publika adressen som Metabase sätter i länkar och e-post.
  • MB_DB_* och de två hemligheterna pekar Metabase mot sin egen PostgreSQL i podden, i stället för en H2-fil.
  • MB_ANON_TRACKING_ENABLED=false stoppar de anonyma användningsdata och MB_CHECK_FOR_UPDATES=false versionskontrollen. Steg 13 tar hand om uppdateringarna i stället.
  • MB_SEND_EMAIL_ON_FIRST_LOGIN_FROM_NEW_DEVICE=false stoppar platsuppslagen hos GeoJS vid inloggning. Samma inställning stoppar också e-postmeddelandet som Metabase annars skickar till en användare som loggar in från en ny enhet; Metabase har inget sätt att behålla det ena utan det andra.
  • JAVA_TIMEZONE gör att Metabase visar datum och tider i svensk tid.
  • v0.64.x följer varje buggfix och säkerhetsfix av Metabase 0.64, via podman-auto-update.timer. En ny version, som 0.65, ändrar Metabases databas, så den byter du till för hand (steg 13). PostgreSQL följer version 18 på samma sätt.

Starta den:

systemctl --user daemon-reload
systemctl --user start metabase-pod
systemctl --user enable --now podman-auto-update.timer

Vid första starten laddas omkring 1,4 GB avbilder ner, och Metabase behöver en minut eller två för att sätta upp sin databas. Räkna med omkring 2,1 GB diskutrymme totalt: vid varje start skriver Metabases container också en kopia på 0,7 GB av sin programfil. Den är klar när det här skriver ut {"status":"ok"}:

curl -s http://127.0.0.1:8131/api/health

5. Skapa administratörskontot via en SSH-tunnel

Tills det finns ett administratörskonto kan den som först öppnar Metabase skapa det och se alla dina data. Caddy visar inte Metabase för någon än, så skapa kontot via en SSH-tunnel, som bara du har.

Öppna en tunnel till Metabases port på servern från din egen dator, och låt den vara öppen:

ssh -L 8131:127.0.0.1:8131 root@203.0.113.10

Öppna http://localhost:8131 i webbläsaren. Den visar Welcome to Metabase. Välj Let's get started och fyll i First name, Last name, Email, Company or team name och ett lösenord under Create a password och Confirm your password. Next skapar kontot direkt, så resten av frågorna avgör du själv:

  • Under What will you use Metabase for? väljer du Self-service analytics for my own company och Next.
  • Under Add your data väljer du Continue with sample data. Din egen databas lägger du till i steg 7, när Metabase har fått sin adress.
  • Under Usage data preferences stänger du av Allow Metabase to anonymously collect usage events och väljer Finish. Reglaget är påslaget från början, men MB_ANON_TRACKING_ENABLED=false från steg 4 håller insamlingen avstängd ändå.

Stäng tunneln när du är klar.

6. Sätt Caddy framför

Gå tillbaka till root med exit, byt till Caddys användare med machinectl shell caddy@ och lägg till det här blocket sist i ~/Caddyfile:

metabase.example.com {
    reverse_proxy 127.0.0.1:8131
}

Starta om Caddy med systemctl --user restart caddy och logga in på https://metabase.example.com.

7. Anslut din databas

Öppna menyn uppe till höger, rutan med prickar, och välj Admin, sedan Databases > Add database. Database type är redan PostgreSQL. Fyll i:

  • Display name: namnet som teamet ser, till exempel Butik;
  • Host: 169.254.1.3, serverns egen 127.0.0.1 sett från podden (steg 4);
  • Port: 5432;
  • Database name: appdb;
  • Username: metabase_ro, och dess Password från steg 1.

Välj Save. Metabase ansluter, läser in vilka tabeller och kolumner som finns och visar Syncing completed. Som standard läser den in dem igen varje timme, så nya tabeller dyker upp av sig själva. Metabase sparar lösenordet krypterat med nyckeln från steg 3.

Låt Model actions vara avstängt. Med actions kan användare ändra data via Metabase, och det kräver en inloggning som kan skriva.

Bestäm vem som får skriva SQL. Som standard får alla i Metabase skriva SQL mot varje databas du lägger till. De läser fortfarande bara det som metabase_ro får läsa, men en SQL-fråga kan läsa varje kolumn i varje tabell, även sådana du skulle hålla utanför en dashboard, som e-postadresser. För att bara låta administratörer skriva SQL öppnar du Permissions, väljer databasen, sätter All Users till Query builder only under Create queries, väljer Save changes och bekräftar med Yes. Andra kan då bygga frågor med frågebyggaren och öppna sparade frågor. I vårt test nekades en SQL-fråga från en sådan användare.

8. Frågor och dashboards

En fråga är en sökning i databasen med tillhörande diagram. För att bygga en utan SQL väljer du New uppe till höger, sedan Question, din databas och en tabell, till exempel Orders:

  1. Under Summarize väljer du Pick a function or metric, sedan Sum of ... och en kolumn, till exempel Total.
  2. Bredvid by väljer du Pick a column to group by och ett datum, till exempel Created At. Metabase grupperar per vecka; välj by week bredvid kolumnen och sedan Month för att ändra det.
  3. Välj Visualize. Metabase visar ett linjediagram, och du kan byta till ett annat diagram under Visualization.

Välj Save, ge frågan ett namn, till exempel Intäkter per månad, och välj Save igen.

För SQL väljer du New > SQL query, väljer databasen högst upp, skriver frågan och kör den med Ctrl+Enter:

SELECT c.city, count(*) AS orders
FROM orders o JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'paid'
GROUP BY c.city ORDER BY orders DESC

Spara den på samma sätt. En fråga som försöker ändra data får ett fel från PostgreSQL, till exempel ERROR: cannot execute DELETE in a read-only transaction.

För att samla frågor på ett ställe väljer du New > Dashboard, ger den ett namn och väljer Create. Välj Add a chart, sedan varje sparad fråga, ordna korten och välj Save. En dashboard kör sina frågor varje gång någon öppnar den.

På startsidan erbjuder Metabase också färdiga översikter av en tabell, som den kallar X-rays. Dess AI-funktioner, som AI exploration och Metabot, kräver ett konto hos en AI-leverantör som du ansluter under Admin > AI; tills du gör det händer ingenting. Vi har inte testat dem.

9. Använd Metabase på svenska

Metabase är översatt till svenska. För att göra svenska till standard för alla väljer du Admin > Settings > Localization och sedan Swedish under Instance language. Det gäller direkt. Varje användare kan välja sitt eget språk under Language i sina kontoinställningar, som öppnas från sitt namn i samma meny uppe till höger.

Namnen på dina tabeller, kolumner och frågor översätts inte. Datum följer språket, medan tal behåller kommatecken som tusentalsavgränsare tills du ändrar Separator style under Localization.

10. Användare

Välj Admin > People > Invite someone, fyll i First name, Last name och Email och välj Create. Utan e-post (steg 11) visar Metabase "We couldn’t send them an email invitation" med ett tillfälligt lösenord. Ge det till personen, som bör byta det efter första inloggningen.

Nya användare hamnar i gruppen All Users, som får se allt i Our analytics och använda databaserna så som det är inställt under Permissions (steg 7). Gör någon till administratör genom att lägga till den i Administrators.

Metabase sparar varje inloggning med besökarens adress, som varje användare ser under Login History i sina kontoinställningar. När den sidan öppnas skickas adresserna i listan till GeoJS för att slå upp en plats för var och en: det var den enda externa anslutningen i vår avlyssning. Enkel inloggning med Google eller LDAP finns under Admin > Settings > Authentication; SAML och JWT kräver en betald utgåva. Vi har inte testat dem.

11. E-post

Metabase skickar e-post för inbjudningar, återställning av lösenord, prenumerationer på dashboards och larm på frågor. Den här guiden sätter inte upp e-post, och utan den:

  • får en inbjuden användare ett tillfälligt lösenord på din skärm i stället för ett e-postmeddelande, som i steg 10;
  • säger I seem to have forgotten my password på inloggningssidan "Please contact an administrator to have them reset your password.", och en administratör återställer lösenordet under Admin > People;
  • går det inte att sätta upp prenumerationer och larm.

Inloggning med lösenord fungerar som vanligt.

För att skicka e-post pekar du Metabase mot din e-postleverantörs SMTP-server. Som metabase sparar du SMTP-lösenordet som en hemlighet:

printf %s 'the-smtp-password' | podman secret create metabase-mail-password -

Lägg sedan till de här raderna i metabase-app.container, före AutoUpdate=registry, med din egen server, ditt konto och din avsändaradress:

Environment=MB_EMAIL_SMTP_HOST=smtp.example.com MB_EMAIL_SMTP_PORT=587 MB_EMAIL_SMTP_SECURITY=starttls
Environment=MB_EMAIL_SMTP_USERNAME=metabase@example.com MB_EMAIL_FROM_ADDRESS=metabase@example.com MB_EMAIL_FROM_NAME=Metabase
Secret=metabase-mail-password,type=env,target=MB_EMAIL_SMTP_PASSWORD
systemctl --user daemon-reload
systemctl --user restart metabase-app

Port 587 använder STARTTLS; för port 465, som använder TLS från början, sätter du MB_EMAIL_SMTP_PORT=465 och MB_EMAIL_SMTP_SECURITY=ssl. Admin > Settings > Email visar sedan inställningarna som satta via miljövariabler, och Send test email kontrollerar dem. Vi testade raderna mot en testbrevlåda på servern, inte mot en riktig leverantör: inbjudningar och återställningar av lösenord kom fram, med länkar till https://metabase.example.com. Meddelandena visar Metabases logotyp från static.metabase.com och ett typsnitt från Google Fonts, som mottagarens e-postprogram laddar när det visar bilder.

12. Säkerhetskopiera

Som metabase:

umask 077
mkdir -p ~/backup
podman exec metabase-db pg_dump -U metabase metabase > ~/backup/metabase-db.sql
podman secret inspect --showsecret --format '{{.SecretData}}' metabase-encryption-key > ~/backup/encryption-key.txt

Metabases databas innehåller användare, frågor, dashboards, behörigheter och inställningar, och anslutningsuppgifterna till dina databaser, krypterade med nyckeln. Dumpen körs medan Metabase fortsätter att fungera. Dina affärsdata finns inte i den: de ligger kvar i din egen databas, som PostgreSQL-guiden säkerhetskopierar. Kopiera ~/backup till en annan maskin, till exempel med restic, och förvara den säkert.

För att återställa till en tom pod, som metabase, med säkerhetskopian i ~/backup:

systemctl --user stop metabase-pod
podman volume rm metabase-db
systemctl --user start metabase-db
podman exec -i metabase-db psql -q -U metabase -d metabase < ~/backup/metabase-db.sql
systemctl --user start metabase-app

Genom att bara starta databasen först läses säkerhetskopian in innan Metabase sätter upp en tom databas. På en ny server skapar du nyckeln från säkerhetskopian i stället för en ny i steg 3:

tr -d '\n' < ~/backup/encryption-key.txt | podman secret create metabase-encryption-key -

13. Uppdatera

podman auto-update letar en gång om dagen efter nya avbilder av Metabase 0.64 och PostgreSQL 18 och startar om podden när någon har ändrats. För att uppdatera direkt:

podman auto-update

Varje ny version av Metabase, som 0.65, ändrar dess databas första gången den startar. Byt till den för hand, efter en säkerhetskopia (steg 12): ändra v0.64.x till v0.65.x i metabase-app.container och kör sedan

systemctl --user daemon-reload
systemctl --user restart metabase-app

Första starten laddar ner den nya avbilden och uppdaterar databasen; podman logs metabase-app visar Database Migrations Current. Vår uppdatering från 0.63 till 0.64 tog 7 sekunder för databasen och behöll alla frågor och dashboards. Metabase kan inte flytta tillbaka sin databas till en äldre version, så säkerhetskopian från före uppdateringen är din väg tillbaka, med den gamla taggen. Vi har inte testat att gå tillbaka. Läs versionsinformationen på Metabases GitHub innan du uppdaterar.

Felsökning

Det går inte att lägga till databasen: role "metabase_ro" does not exist. Host är 127.0.0.1 eller localhost, som inne i podden är Metabases egen PostgreSQL. Använd 169.254.1.3.

Det går inte att lägga till databasen: Connection refused, eller ingen svarar. Raden Network= i metabase.pod saknas, eller så har podden inte startats om sedan du lade till den: kör systemctl --user daemon-reload och systemctl --user restart metabase-pod. Kontrollera att PostgreSQL körs på servern med pg_lsclusters.

password authentication failed for user "metabase_ro". Lösenordet är fel. Sätt ett nytt som root med sudo -u postgres psql -c '\password metabase_ro' och ange det under Edit connection details för databasen i Admin > Databases.

En fråga misslyckas med permission denied for table .... Tabellen skapades av en annan inloggning än appuser, så standardrättigheterna från steg 1 gäller inte för den. Som root: sudo -u postgres psql -d appdb -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase_ro'.

Metabase säger att en inbjudan har skickats, men inget kommer fram. Metabase skickar i bakgrunden och fortsätter att försöka när SMTP-servern inte svarar. podman logs metabase-app 2>&1 | grep -i 'failed to send' visar felet.

https://metabase.example.com ger 502 en stund efter en omstart. Metabase behöver en minut eller två för att starta. curl -s http://127.0.0.1:8131/api/health skriver ut {"status":"ok"} när den är klar.

Kör det på din egen server

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy

100 kr/mån

vCPU
2
Minne
8 GB
Lagring
60 GB
Trafik
10 TB
Performance
SSD · RAID 1
  • Full root-åtkomst
  • Nativt /64 IPv6
  • RAID-skyddad lagring
  • Malmö, Sverige
  • Månadsvis, ingen bindningstid
  • 7 dagars öppet köp
Alla guider