Kör projektverktyget Plane med Podman utan root

Plane Community Edition på Debian 13, ett alternativ till Jira och Linear med öppen källkod, med ärenden, tavlor och cykler, i rootless Podman under en egen användare bakom Caddy, med Garage för bilagor och telemetrin avstängd.

Testad på Plane 1.4.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

Plane är ett verktyg för att planera och följa upp ett teams arbete, i samma familj som Jira och Linear. Varje projekt har work items, Planes namn på uppgifter och ärenden, som du kan visa som en lista, en tavla, en kalender, ett kalkylblad eller en tidslinje. Cykler delar upp arbetet i sprintar på en vecka eller två, moduler delar upp det efter funktion, och sidor rymmer anteckningar och specifikationer som flera kan redigera samtidigt.

Plane utvecklas av Plane Software, Inc., som också säljer en molntjänst och betalversioner. Community Edition, som används här, är öppen källkod under GNU AGPL v3, utan gräns för antalet användare, projekt, ärenden eller hur mycket du lagrar. Betalversionerna lägger bland annat till egna ärendetyper och fält, mallar, tidrapportering, fler roller, LDAP och egna rapporter; Billing & Plans i arbetsytans inställningar listar dem. I Community Edition loggar man in med e-post och lösenord, med en kod som skickas per e-post, eller via Google, GitHub, GitLab eller Gitea.

Som standard skickar Plane användningsdata till sina utvecklare, och rutan för det är förifylld på installationssidan. Steg 8 stänger av det, och steg 12 visar vad som skickades och vad som är kvar.

Plane består av tretton containrar: webbappen, adminsidorna (Plane kallar dem God mode), de publika sidorna, en server för samtidig redigering, API:t med två bakgrundsprocesser, PostgreSQL, Valkey, RabbitMQ, S3-lagring för bilagor och Planes egen proxy framför. Planes installationsskript kör dem med Docker Compose. Här körs samma avbilder som Quadlet-enheter, i Podman under en egen användare som heter plane, bakom Caddy från Podman-guiden. De delar ett Podman-nätverk i stället för en pod, eftersom fyra av Planes avbilder lyssnar på samma port, 3000, och i en pod skulle de krocka.

För bilagor behöver Plane S3-lagring. Tidigare körde dess Compose-fil MinIO, men avbilden minio/minio finns inte längre på Docker Hub, och Plane använder nu pgsty/minio, en ombyggd version från projektet Pigsty. Den här guiden använder i stället Garage, S3-lagringen från Garage-guiden, som görs av Deuxfleurs, en ideell förening i Frankrike, och som också är öppen källkod under AGPL. Plane fungerade med den utan ändringar.

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

  • Plane 1.4.1 startade med PostgreSQL 15, Valkey 7.2, RabbitMQ 3.13 och Garage 2.4.1, instansens administratör sattes upp i God mode, och Plane uppdaterades sedan till 1.4.2.
  • Registreringen var öppen för alla från början: en främling kunde skapa ett konto tills den stängdes av. Efteråt fick ett försök att registrera sig svaret "Sign up disabled. Please contact your administrator."
  • En arbetsyta och ett projekt skapades, med ärenden, en cykel och en sida. På tavlan bytte ett kort status när det drogs till In Progress. Sökningen hittade ett ärende på ett ord i rubriken.
  • En kollega bjöds in per e-post, skapade ett konto från länken trots att registreringen var stängd och kom med i arbetsytan. Med Plane kopplad till en lokal testserver för e-post kom inbjudan, ett testmeddelande och en återställning av lösenord fram. Att skicka via en riktig e-postleverantör har vi inte testat.
  • En PNG och en PDF som bifogades till ett ärende lagrades i Garage och kom tillbaka med samma kontrollsummor. En fil över 5 MB nekades, och utan en signerad länk gick filerna inte att hämta.
  • Plane loggade varje besökares riktiga adress, över IPv4 och IPv6, och struntade i en förfalskad X-Forwarded-For-header.
  • En avlyssning av serverns trafik visade användningsdata som gick till telemetry.plane.so, och inget efter att det stängts av, utom en kontroll av senaste version hos GitHub när API:t startar.
  • En säkerhetskopia återställdes för en nyskapad plane-användare, med alla ärenden och bilagor kvar, och allt startade igen av sig självt efter en omstart av servern.

Containrarna använde tillsammans omkring 1,3 GB minne, det mesta för Planes API, bakgrundsprocesser och server för samtidig redigering. Avbilderna tar omkring 3,3 GB disk.

Innan du börjar

Du behöver:

  • en server uppsatt som i Podman-guiden, med Caddy igång;
  • en A-post och en AAAA-post för plane.example.com som pekar på din server;
  • för inbjudningar och återställning av lösenord per e-post, ett konto hos en e-postleverantör som tillåter att du skickar via SMTP.

Exemplen använder plane.example.com för Plane och smtp.example.com för din leverantörs SMTP-server. Byt ut dem genomgående.

1. Skapa användaren

Som root:

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

Allt fram till steg 7 körs som plane.

2. Skapa hemligheterna

for s in plane-secret-key plane-live-key plane-db-password plane-mq-password plane-s3-rpc; do
  openssl rand -hex 32 | tr -d '\n' | podman secret create $s -
done

Det skapar fem slumpade hemligheter, som lagras av Podman och inte i filerna nedan:

  • plane-secret-key är Planes egen nyckel. Den signerar inloggningar och inbjudningslänkar och krypterar SMTP-lösenordet du anger i steg 11. Steg 13 sparar en kopia.
  • plane-live-key låter servern för samtidig redigering prata med API:t.
  • plane-db-password och plane-mq-password är lösenorden till PostgreSQL och RabbitMQ.
  • plane-s3-rpc är Garages interna hemlighet.

3. Skriv konfigurationen

Skapa ~/plane.env, inställningarna som API:t och dess bakgrundsprocesser delar:

WEB_URL=https://plane.example.com
CORS_ALLOWED_ORIGINS=https://plane.example.com
POSTGRES_HOST=plane-db
POSTGRES_PORT=5432
POSTGRES_DB=plane
POSTGRES_USER=plane
REDIS_URL=redis://plane-redis:6379/
RABBITMQ_HOST=plane-mq
RABBITMQ_PORT=5672
RABBITMQ_USER=plane
RABBITMQ_VHOST=plane
USE_MINIO=1
AWS_REGION=garage
AWS_S3_ENDPOINT_URL=http://plane-minio:9000
AWS_S3_BUCKET_NAME=uploads
FILE_SIZE_LIMIT=5242880
GUNICORN_WORKERS=2

Och ~/garage.toml, Garages konfiguration:

metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "sqlite"
metadata_fsync = true
replication_factor = 1
rpc_bind_addr = "127.0.0.1:3901"
rpc_public_addr = "127.0.0.1:3901"

[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:9000"

Vad inställningarna gör:

  • WEB_URL är adressen som Plane sätter i länkar, inbjudningar och omdirigeringar. Den måste vara den publika https://-adressen. CORS_ALLOWED_ORIGINS låter webbläsare på den adressen använda API:t.
  • USE_MINIO=1 får Plane att skicka uppladdningar och nedladdningar via sin egen adress, https://plane.example.com/uploads/, där Planes proxy skickar dem vidare till lagringen. Webbläsaren pratar aldrig direkt med Garage. plane-minio är namnet som proxyn väntar sig att lagringen har; steg 4 ger Garage det namnet.
  • AWS_REGION måste stämma med s3_region i garage.toml, annars nekar Garage anropen.
  • FILE_SIZE_LIMIT är den största bilagan i byte, här 5 MB, som är Planes standard. Vill du tillåta större filer höjer du den här och i plane-proxy.container nedan.
  • I garage.toml håller db_engine = "sqlite" med metadata_fsync = true Garages register över filerna intakt om servern tappar strömmen, och replication_factor = 1 betyder en kopia, det enda valet på en server. Garage-guiden förklarar resten.

4. Definiera containrarna

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

Först nätverket som de delar. Skapa plane.network:

[Network]
NetworkName=plane

På det kan varje container nå de andra med namn, till exempel plane-db. Sedan de fyra tjänsterna där Plane lagrar sina data. Skapa plane-db.container:

[Container]
ContainerName=plane-db
Image=docker.io/library/postgres:15-alpine
Network=plane.network
Exec=postgres -c max_connections=1000
Volume=plane-db:/var/lib/postgresql/data
Environment=POSTGRES_USER=plane POSTGRES_DB=plane
Secret=plane-db-password,type=env,target=POSTGRES_PASSWORD
HealthCmd=pg_isready -U plane
HealthInterval=10s
Notify=healthy
AutoUpdate=registry

[Service]
Restart=always

plane-redis.container, cachen:

[Container]
ContainerName=plane-redis
Image=docker.io/valkey/valkey:7.2-alpine
Network=plane.network
Volume=plane-redis:/data
AutoUpdate=registry

[Service]
Restart=always

plane-mq.container, kön för bakgrundsjobb som e-post:

[Container]
ContainerName=plane-mq
# RabbitMQ keeps its data under its host name: keep it the same
HostName=plane-mq
Image=docker.io/library/rabbitmq:3.13-alpine
Network=plane.network
Volume=plane-mq:/var/lib/rabbitmq
Environment=RABBITMQ_DEFAULT_USER=plane RABBITMQ_DEFAULT_VHOST=plane
Secret=plane-mq-password,type=env,target=RABBITMQ_DEFAULT_PASS
AutoUpdate=registry

[Service]
Restart=always

Och plane-s3.container, Garage:

[Container]
ContainerName=plane-s3
# Plane's proxy sends uploads to this name
NetworkAlias=plane-minio
Image=docker.io/dxflrs/garage:v2.4.1
Exec=/garage server --single-node
Network=plane.network
Volume=%h/garage.toml:/etc/garage.toml:ro
Volume=plane-s3-meta:/var/lib/garage/meta
Volume=plane-s3-data:/var/lib/garage/data
Secret=plane-s3-rpc,type=env,target=GARAGE_RPC_SECRET
StopTimeout=30

[Service]
Restart=always

Versionerna är de som Planes egen Compose-fil använder: PostgreSQL 15, Valkey 7.2 och RabbitMQ 3.13. Podman uppdaterar dem inom de versionerna (steg 14). Garage har ingen tagg som följer nya versioner, så versionen står utskriven.

Nu själva Plane. Avbilden för API:t körs på fyra sätt: den sätter upp databasen, kör API:t och kör två bakgrundsprocesser. De fyra filerna är likadana utom namnet, kommandot och [Unit]-raderna överst. Skapa plane-migrator.container, som uppdaterar databasen och sedan stannar:

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

[Container]
ContainerName=plane-migrator
Image=docker.io/makeplane/plane-backend:v1.4.2
Exec=./bin/docker-entrypoint-migrator.sh
Network=plane.network
EnvironmentFile=%h/plane.env
Secret=plane-secret-key,type=env,target=SECRET_KEY
Secret=plane-live-key,type=env,target=LIVE_SERVER_SECRET_KEY
Secret=plane-db-password,type=env,target=POSTGRES_PASSWORD
Secret=plane-mq-password,type=env,target=RABBITMQ_PASSWORD
Secret=plane-s3-key-id,type=env,target=AWS_ACCESS_KEY_ID
Secret=plane-s3-secret-key,type=env,target=AWS_SECRET_ACCESS_KEY

[Service]
Type=oneshot
RemainAfterExit=yes
TimeoutStartSec=900

plane-api.container:

[Unit]
Requires=plane-migrator.service plane-redis.service plane-mq.service
Wants=plane-s3.service
After=plane-migrator.service plane-redis.service plane-mq.service plane-s3.service

[Container]
ContainerName=plane-api
NetworkAlias=api
Image=docker.io/makeplane/plane-backend:v1.4.2
Exec=./bin/docker-entrypoint-api.sh
Network=plane.network
EnvironmentFile=%h/plane.env
Secret=plane-secret-key,type=env,target=SECRET_KEY
Secret=plane-live-key,type=env,target=LIVE_SERVER_SECRET_KEY
Secret=plane-db-password,type=env,target=POSTGRES_PASSWORD
Secret=plane-mq-password,type=env,target=RABBITMQ_PASSWORD
Secret=plane-s3-key-id,type=env,target=AWS_ACCESS_KEY_ID
Secret=plane-s3-secret-key,type=env,target=AWS_SECRET_ACCESS_KEY

[Service]
Restart=always

plane-worker.container:

[Unit]
Requires=plane-api.service
After=plane-api.service

[Container]
ContainerName=plane-worker
Image=docker.io/makeplane/plane-backend:v1.4.2
Exec=./bin/docker-entrypoint-worker.sh
Network=plane.network
EnvironmentFile=%h/plane.env
Secret=plane-secret-key,type=env,target=SECRET_KEY
Secret=plane-live-key,type=env,target=LIVE_SERVER_SECRET_KEY
Secret=plane-db-password,type=env,target=POSTGRES_PASSWORD
Secret=plane-mq-password,type=env,target=RABBITMQ_PASSWORD
Secret=plane-s3-key-id,type=env,target=AWS_ACCESS_KEY_ID
Secret=plane-s3-secret-key,type=env,target=AWS_SECRET_ACCESS_KEY

[Service]
Restart=always

plane-beat.container, som startar schemalagda jobb:

[Unit]
Requires=plane-api.service
After=plane-api.service

[Container]
ContainerName=plane-beat
Image=docker.io/makeplane/plane-backend:v1.4.2
Exec=./bin/docker-entrypoint-beat.sh
Network=plane.network
EnvironmentFile=%h/plane.env
Secret=plane-secret-key,type=env,target=SECRET_KEY
Secret=plane-live-key,type=env,target=LIVE_SERVER_SECRET_KEY
Secret=plane-db-password,type=env,target=POSTGRES_PASSWORD
Secret=plane-mq-password,type=env,target=RABBITMQ_PASSWORD
Secret=plane-s3-key-id,type=env,target=AWS_ACCESS_KEY_ID
Secret=plane-s3-secret-key,type=env,target=AWS_SECRET_ACCESS_KEY

[Service]
Restart=always

Sedan de fyra delarna som visar sidor. plane-web.container, själva appen:

[Unit]
After=plane-api.service

[Container]
ContainerName=plane-web
NetworkAlias=web
Image=docker.io/makeplane/plane-frontend:v1.4.2
Network=plane.network

[Service]
Restart=always

plane-admin.container, God mode:

[Unit]
After=plane-api.service

[Container]
ContainerName=plane-admin
NetworkAlias=admin
Image=docker.io/makeplane/plane-admin:v1.4.2
Network=plane.network

[Service]
Restart=always

plane-space.container, för projekt som du publicerar:

[Unit]
After=plane-api.service

[Container]
ContainerName=plane-space
NetworkAlias=space
Image=docker.io/makeplane/plane-space:v1.4.2
Network=plane.network

[Service]
Restart=always

plane-live.container, för samtidig redigering av sidor:

[Unit]
After=plane-api.service

[Container]
ContainerName=plane-live
NetworkAlias=live
Image=docker.io/makeplane/plane-live:v1.4.2
Network=plane.network
Environment=API_BASE_URL=http://api:8000 REDIS_HOST=plane-redis REDIS_PORT=6379 REDIS_URL=redis://plane-redis:6379/
Secret=plane-live-key,type=env,target=LIVE_SERVER_SECRET_KEY

[Service]
Restart=always

Och sist Planes proxy framför dem, plane-proxy.container:

[Unit]
Wants=plane-web.service plane-admin.service plane-space.service plane-live.service plane-worker.service plane-beat.service
After=plane-web.service plane-admin.service plane-space.service plane-live.service plane-api.service

[Container]
ContainerName=plane-proxy
Image=docker.io/makeplane/plane-proxy:v1.4.2
Network=plane.network
Environment=SITE_ADDRESS=:80 FILE_SIZE_LIMIT=5242880 BUCKET_NAME=uploads
# Only Caddy, on this server, can reach Plane: the port is not open to the internet.
PublishPort=127.0.0.1:8152:80

[Service]
Restart=always

[Install]
WantedBy=default.target

Så hänger det ihop:

  • Proxyn är en liten Caddy som Plane ger ut med varje version. Den skickar /api/ och /auth/ till API:t, /god-mode/ till adminsidorna, /spaces/ till de publika sidorna, /live/ till servern för samtidig redigering, /uploads/ till lagringen och allt annat till webbappen. Den är den enda containern med en port, 8152, och bara på 127.0.0.1. Genom att behålla Planes proxy stämmer vägarna även när en ny version ändrar dem. NetworkAlias ger varje container det korta namn som proxyn använder.
  • Bara proxyn har en [Install]-del. När den startar, startar resten via raderna Wants och Requires, så en enda rad startar Plane vid uppstart.
  • Migratorn körs före API:t varje gång Plane startar och gör de ändringar i databasen som en ny version kräver. API:t väntar på den. TimeoutStartSec ger en stor uppdatering tid att bli klar.
  • Planes avbilder saknar raden AutoUpdate: alla fem måste ha samma version, och en uppdatering kan ändra databasen. Steg 14 uppdaterar dem för hand.
  • Besökarens adress når Plane i headern X-Forwarded-For. Caddy sätter den och ersätter en sådan header om besökaren skickat en, och Planes proxy skickar den vidare. Därför ser API:t riktiga adresser trots att containrarna ligger på ett Podman-nätverk.

5. Starta Garage och skapa bucketen

systemctl --user daemon-reload
systemctl --user start plane-s3
echo "alias garage='podman exec -e RUST_LOG=warn plane-s3 /garage'" >> ~/.bashrc
source ~/.bashrc
garage status

garage status visar en frisk nod. Skapa bucketen för bilagor och en nyckel för Plane, som bara kommer åt den bucketen, och spara nyckeln som två hemligheter till:

garage bucket create uploads
garage key create plane
garage bucket allow --read --write --owner uploads --key plane
garage key info plane --show-secret | awk '/^Key ID/ {printf "%s", $3}' | podman secret create plane-s3-key-id -
garage key info plane --show-secret | awk '/^Secret key/ {printf "%s", $3}' | podman secret create plane-s3-secret-key -

6. Starta Plane

Ladda ner Planes avbilder först. De är omkring 2,7 GB, och att ladda ner dem som en del av starten kan ta längre tid än systemd väntar:

for i in backend frontend space admin live proxy; do
  podman pull docker.io/makeplane/plane-$i:v1.4.2
done

Starta sedan Plane, och låt Podman hålla databasen, cachen och kön uppdaterade:

systemctl --user start plane-proxy
systemctl --user enable --now podman-auto-update.timer

Första starten tar omkring fem minuter medan migratorn sätter upp databasen, och kommandot väntar tills den är klar. Plane är klar när det här skriver ut 200:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8152/api/instances/

podman logs plane-api slutar med Listening at: http://0.0.0.0:8000, efter Bucket 'uploads' exists..

7. Sätt Caddy framför

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

plane.example.com {
    reverse_proxy 127.0.0.1:8152
}

Starta om Caddy med systemctl --user restart caddy. Gör steg 8 direkt: tills det finns en administratör för instansen blir den första som öppnar God mode det.

8. Sätt upp God mode

Öppna https://plane.example.com/god-mode/. Under Setup your Plane Instance fyller du i ditt namn, din e-postadress, Company name och ett lösenord med minst 8 tecken, en versal, en gemen, en siffra och ett specialtecken. Avmarkera Allow Plane to anonymously collect usage events (steg 12 förklarar varför) och välj Continue. Det här kontot är instansens administratör och också ditt vanliga konto i Plane.

God mode öppnas sedan på General. Gå igenom de här sidorna:

  • Authentication: stäng av Allow anyone to sign up even without an invite. Den är påslagen från början, och så länge den är det kan vem som helst som hittar adressen skapa ett konto. Efteråt kan bara de du bjuder in registrera sig; andra får "Sign up disabled. Please contact your administrator." Låt Passwords vara påslaget. Unique codes kräver e-post (steg 11).
  • General: om du lät rutan vid installationen vara markerad stänger du av Let Plane collect anonymous usage data under Telemetry och väljer Save changes.

Artificial intelligence och Images in Plane frågar efter en nyckel till OpenAI och till Unsplash. Lämna dem tomma om du inte vill använda de tjänsterna. Redirect to Plane längst ner tar dig till appen.

9. Skapa en arbetsyta och bjud in teamet

Logga in i appen med samma e-postadress och lösenord. Plane frågar efter ditt namn och sedan efter en arbetsyta: ge den ett namn, till exempel Example, så följer adressen, plane.example.com/example, med. Välj hur många som ska använda den och Create workspace, och I'll do it later när den erbjuder dig att bjuda in folk. Plane lägger också ett demoprojekt med exempelärenden i den nya arbetsytan.

Gå nu tillbaka till God mode, på https://plane.example.com/god-mode/, och slå på Prevent anyone else from creating a workspace under Workspaces, så att de du bjuder in går med i din arbetsyta i stället för att skapa egna. Gör det först när du har din arbetsyta: med den påslagen stoppar Planes första uppsättning i appen även dig, med "You don't seem to have any invites to a workspace and your instance admin has restricted creation of new workspaces".

För att bjuda in en kollega öppnar du arbetsytans meny uppe till vänster och väljer Settings, Members och Add member. Ange kollegans e-postadress, välj en roll, till exempel Member, och välj Send invitations. Kollegan får ett mejl med länken Accept invite, skapar sitt konto från den och är med i arbetsytan. Utan e-post (steg 11) säger Plane ändå "Invitations sent successfully", men inget skickas: be kollegan registrera sig på https://plane.example.com/sign-up/ med adressen du bjöd in, vilket fungerar även när registreringen är stängd, och välja arbetsytan under Join invites or create a workspace.

Varje användare väljer tidszon och språk i sin profil, under Preferences > Language & Time. Tidszonen är UTC från början, så välj Europe/Stockholm. Plane är översatt till många språk, bland annat tyska, franska och polska, men inte svenska.

10. Projekt, ärenden och cykler

Under Projects frågar Add Project efter ett namn och en kort id, till exempel WEB; ärendena numreras sedan WEB-1, WEB-2 och så vidare. Efter Create project erbjuder Plane dig att slå på Cycles, Modules, Views och Intake, som är avstängda från början. Du kan också göra det senare under projektets Settings.

  • New work item skapar ett ärende. Dess sida har en beskrivning, underärenden, länkar, kommentarer, status, ansvariga, prioritet, datum och etiketter.
  • Ikonerna överst i projektets ärendelista växlar mellan lista, tavla, kalender, kalkylblad och tidslinje. På tavlan är varje kolumn en status, från Backlog till Done, och du drar ett kort för att flytta det.
  • Cycles > Add cycle skapar en cykel med start- och slutdatum. Öppna den och använd Add existing work item för att lägga in ärenden. Den visar hur långt arbetet har kommit.
  • Attach på ett ärende laddar upp en fil, upp till 5 MB, FILE_SIZE_LIMIT från steg 3. Filerna lagras i Garage, och länkarna som Plane delar ut är signerade och slutar fungera efter en timme.
  • Pages rymmer dokument som flera kan redigera samtidigt.
  • Sökrutan högst upp, Search commands..., hittar ärenden på ord i rubriken. I vårt test hittade den inte ett ord som bara fanns i en beskrivning.

Nya projekt får en slumpad omslagsbild, som webbläsaren hämtar från images.unsplash.com. Du kan byta den under projektets Settings.

11. E-post

Plane skickar e-post för inbjudningar, återställning av lösenord, koder för att logga in utan lösenord och aviseringar om ärenden. Utan e-post:

  • säger en inbjudan "Invitations sent successfully", men inget mejl skickas (steg 9 visar hur du kommer runt det);
  • visar Forgot your password? "Something went wrong. Please try again.";
  • går det inte att logga in med Unique codes.

Plane sparar sina SMTP-inställningar i databasen, där du anger dem i God mode. Lösenordet krypteras med plane-secret-key från steg 2, så det ligger inte i någon fil, men det kan inte vara en hemlighet i Podman. Öppna Email i God mode, slå på det och fyll i:

  • Host: smtp.example.com, din leverantörs SMTP-server;
  • Port: 587;
  • Sender's email address: en adress som leverantören låter dig skicka från, till exempel plane@example.com;
  • Email security: TLS, som är STARTTLS på port 587. För port 465 väljer du SSL;
  • Username och Password: ditt konto hos leverantören.

Välj Save changes, sedan Send test email, och ange din egen adress. Vi testade Planes e-post mot en lokal testserver; att skicka via en riktig leverantör har vi inte testat.

Tills e-posten fungerar kan du sätta ett nytt lösenord åt en användare från servern, som plane:

podman exec -it plane-api python manage.py reset_password colleague@example.com

Kommandot frågar efter lösenordet två gånger och nekar lösenord som är lätta att gissa.

12. Externa anslutningar

Vi avlyssnade serverns DNS-uppslagningar och utgående anslutningar medan Plane sattes upp och användes.

Med användningsdata påslaget skickar API:t en rapport till telemetry.plane.so när det startar och var sjätte timme. Den innehåller instansens id, instansens namn (Company name från installationen), din adress till Plane, versionen, antalet användare, arbetsytor, projekt, ärenden, cykler, moduler och sidor, och för varje arbetsyta dess korta namn och samma antal. Den innehåller inga namn på personer eller e-postadresser. Med Let Plane collect anonymous usage data avstängt i God mode upphörde den.

Det som är kvar:

  • Varje gång API:t startar frågar det api.github.com efter Planes senaste version, för att kunna visa i God mode när en uppdatering finns. Det skickar inget annat, och det går inte att stänga av.
  • I webbläsaren hämtar nya projekt en omslagsbild från images.unsplash.com (steg 10).
  • Inbjudningsmejl visar Planes logotyp från media.docs.plane.so, som mottagarens e-postprogram hämtar.
  • Inloggning med Google, GitHub, GitLab eller Gitea, nycklarna till OpenAI och Unsplash, och webhooks kontaktar de tjänsterna bara om du sätter upp dem. En webhook till en annan app på samma server, till exempel n8n, behöver en av lösningarna i steg 8 i Podman-guiden. Planes containrar delar ett eget nätverk, och båda lösningarna fungerar även där.

13. Säkerhetskopiera

Som plane:

umask 077
mkdir -p ~/backup
podman exec plane-db pg_dump -U plane plane > ~/backup/plane-db.sql
systemctl --user stop plane-s3
podman volume export plane-s3-meta > ~/backup/plane-s3-meta.tar
podman volume export plane-s3-data > ~/backup/plane-s3-data.tar
systemctl --user start plane-s3
for s in $(podman secret ls --format '{{.Name}}'); do
  podman secret inspect --showsecret --format '{{.SecretData}}' $s > ~/backup/secret-$s
done
tar -cf ~/backup/config.tar plane.env garage.toml .config/containers/systemd

Det sparar:

  • databasen, med alla arbetsytor, projekt, ärenden, kommentarer, sidor och inställningar. Dumpen körs medan Plane fortsätter att fungera;
  • bilagorna, i Garages två volymer. Garage stoppas de få sekunder som exporten tar, så att filerna hänger ihop, och uppladdningar misslyckas under de sekunderna;
  • hemligheterna, där plane-secret-key är den du inte klarar dig utan: den dekrypterar SMTP-lösenordet och håller inloggningarna giltiga;
  • konfigurationen och enhetsfilerna.

Valkey och RabbitMQ innehåller bara en cache och pågående jobb och behöver ingen säkerhetskopia. Kopiera ~/backup till en annan maskin, till exempel med restic, och förvara den säkert: den innehåller era data och hemligheterna.

För att återställa på en ny server sätter du upp den med steg 1, kopierar säkerhetskopian till /home/plane/backup och kör chown -R plane: /home/plane/backup som root. Sedan, som plane:

tar -xf ~/backup/config.tar -C ~
for f in ~/backup/secret-*; do tr -d '\n' < "$f" | podman secret create "${f#*/secret-}" -; done
podman volume create plane-s3-meta
podman volume import plane-s3-meta ~/backup/plane-s3-meta.tar
podman volume create plane-s3-data
podman volume import plane-s3-data ~/backup/plane-s3-data.tar
systemctl --user daemon-reload
systemctl --user start plane-db
podman exec -i plane-db psql -q -U plane plane < ~/backup/plane-db.sql

Ladda sedan ner avbilderna och starta Plane som i steg 6, och lägg till blocket i Caddy som i steg 7. Genom att bara starta databasen först läses säkerhetskopian in innan migratorn sätter upp en tom databas.

För att i stället återställa på samma server, till tomma volymer, stoppar du Plane och tar bort de gamla data först, och kör sedan raderna för volymerna och databasen ovan:

systemctl --user stop 'plane-*'
podman volume rm plane-db plane-s3-meta plane-s3-data

14. Uppdatera

podman auto-update uppdaterar PostgreSQL, Valkey och RabbitMQ en gång om dagen inom deras versioner och startar om Plane runt dem. Själva Plane uppdaterar du för hand. Läs först versionsinformationen på Planes sida på GitHub och ta en säkerhetskopia. Sedan, som plane, med versionen du kör och den nya i sed-raden:

for i in backend frontend space admin live proxy; do
  podman pull docker.io/makeplane/plane-$i:v1.4.3
done
cd ~/.config/containers/systemd
sed -i 's/:v1.4.2/:v1.4.3/' plane-*.container
systemctl --user daemon-reload
systemctl --user restart plane-migrator plane-web plane-admin plane-space plane-live plane-proxy
podman image prune -af

När migratorn startar om, startas API:t och bakgrundsprocesserna om efter den, när databasen är uppdaterad. Vi uppdaterade från 1.4.1 till 1.4.2 på det här sättet. Plane var tillbaka efter ungefär en minut, och API:t visade den nya versionen.

Felsökning

502 Bad Gateway i några minuter efter start. Migratorn sätter fortfarande upp eller uppdaterar databasen, och API:t väntar på den. journalctl --user -u plane-migrator visar hur det går, och podman logs plane-api skriver Listening at när API:t är igång.

Bilagor går inte att ladda upp. Kontrollera att podman logs plane-api innehåller Bucket 'uploads' exists.. Står det Access to the bucket 'uploads' is forbidden är nyckeln i hemligheterna inte den som Garage har: jämför garage key info plane med podman secret inspect --showsecret plane-s3-key-id. AWS_REGION i plane.env måste vara garage.

"Could not send email. Please check your configuration" efter Send test email. Plane kunde inte nå SMTP-servern eller logga in. Kontrollera värdnamnet, porten och Email security: TLS för port 587, SSL för port 465.

"Something went wrong. Please try again." efter Forgot your password?. E-post är inte uppsatt. Sätt upp den som i steg 11, eller sätt ett nytt lösenord med reset_password.

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