AppFlowy auf einem Hetzner Ubuntu-Server selbst hosten

AppFlowy auf einem Hetzner Ubuntu-Server selbst hosten

Yulei Chen - Content-Engineerin bei sliplane.ioYulei Chen
21 min

AppFlowy ist eine Open-Source-Alternative zu Notion, die dir volle Kontrolle über deine Daten gibt. Wenn du AppFlowy Cloud auf deinem eigenen Ubuntu-Server hostest, bekommst du einen kollaborativen Workspace mit AI-Features, Echtzeit-Sync und ohne Nutzungslimits — zu vorhersehbaren monatlichen Kosten.

Folge dieser leicht verständlichen Anleitung, um deine eigene AppFlowy Cloud-Instanz mit Docker und dem Caddy-Webserver für automatisches HTTPS aufzusetzen.

Für diesen Beitrag verwenden wir einen günstigen Server von Hetzner. Hetzner ist bekannt für großartigen Service zu einem außergewöhnlichen Preis-Leistungs-Verhältnis und eignet sich perfekt für das Hosten von AppFlowy.

Voraussetzungen

Bevor wir beginnen, achte drauf, dass du ein Hetzner Cloud-Konto hast (oder bereit bist, eines zu erstellen).

Schritt 1: Deinen Hetzner-Server einrichten

Wenn du noch keinen Hetzner-Server hast, folge diesen Schritten, um einen zu erstellen:

  1. Geh zur Hetzner Cloud Console, wähle ein Projekt aus oder erstelle ein neues, dann geh zu ServersAdd Server

Hetzner Cloud Console

  1. Folge Hetzners Richtlinien, um zu wählen:
    • Server type: AppFlowy Cloud läuft mit mehreren Services (Datenbank, Auth, Object Storage und mehr), du brauchst also mindestens 4 GB RAM. Wir empfehlen einen CX22 oder größer.

Select Server Type

  • Location: Wähl einen Rechenzentrumsstandort, der dir oder deinen Nutzern am nächsten ist.

Select Location

  • Image: Wähl Ubuntu (neueste LTS-Version empfohlen).

Select Ubuntu Image

  1. Add SSH key: Füg deinen öffentlichen SSH-Schlüssel für sicheren Zugriff hinzu. Wenn du noch keinen SSH-Schlüssel hast, kannst du einen mit ssh-keygen generieren:
Terminal
ssh-keygen -t ed25519 -C "your_email@example.com"

Prüf ihn mit cat ~/.ssh/id_ed25519.pub und füg ihn bei deinem Server ein.

SSH Connection

  1. Konfiguriere das Networking bei Bedarf, dann klick auf Create & Pay, um deinen Server bereitzustellen.

Networking Options

Sobald dein Server erstellt wurde, notier dir seine IP-Adresse. Du brauchst sie, um dich im nächsten Schritt per SSH zu verbinden.

Server IP Address

Schritt 2: Deinen Server aktualisieren

Öffne dein Terminal und melde dich per SSH auf deinem Ubuntu-Server an:

Terminal
ssh root@your-server-ip

und aktualisiere das System, damit es die neuesten Sicherheitspatches und Updates hat:

Terminal
sudo apt-get update
sudo apt-get upgrade -y

Sobald das durch ist, ist dein Server bereit für die Installation der Software.

Schritt 3: UFW-Firewall installieren und konfigurieren

Halte nur notwendige Ports offen: SSH (22), HTTP (80), HTTPS (443).

Installiere UFW und konfiguriere die Firewall wie folgt:

Terminal
sudo apt install ufw -y
sudo ufw allow 22    # SSH
sudo ufw allow 80    # HTTP
sudo ufw allow 443   # HTTPS
sudo ufw enable

Prüf deine Firewall-Konfiguration:

Terminal
sudo ufw status verbose

Docker kann manchmal UFW-Regeln ignorieren. Mehr dazu und wie du das behebst, findest du hier erklärt.

Schritt 4: Docker installieren

Docker startet AppFlowy und alle zugehörigen Services in Containern. Installiere Docker mit diesen Befehlen:

Dependencies und Docker GPG-Key einrichten:

Terminal
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Docker-Repository hinzufügen:

Terminal
echo \
  "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo $VERSION_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update

Docker Engine und compose-plugin installieren:

Terminal
sudo apt-get install docker-ce docker-ce-cli \
containerd.io docker-buildx-plugin docker-compose-plugin -y

Installation prüfen:

Terminal
sudo docker run hello-world

Wenn du die "hello-world"-Meldung siehst, ist Docker bereit.

Schritt 5: Caddy für automatisches HTTPS installieren

Caddy vereinfacht die HTTPS-Konfiguration, weil es SSL-Zertifikate automatisch von Let's Encrypt holt.

Caddy installieren:

Terminal
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install caddy -y

Bevor du Caddy konfigurierst, musst du deine Domain auf die IP-Adresse deines Servers zeigen. Wenn du DNS noch nicht eingerichtet hast, folge diesen Schritten:

DNS für deine Domain konfigurieren

  1. Melde dich im Dashboard deines Domain-Registrars an (wo du die Domain gekauft hast)
  2. Geh zu den DNS-Einstellungen oder dem DNS-Management-Bereich
  3. Füg einen A-Record mit diesen Einstellungen hinzu:
    • Type: A
    • Name: @ (für Root-Domain) oder eine Subdomain wie appflowy (für appflowy.yourdomain.com)
    • Value/Target: Die IPv4-Adresse deines Hetzner-Servers
  4. Füg einen AAAA-Record für IPv6-Support hinzu:
    • Type: AAAA
    • Name: @ (für Root-Domain) oder dieselbe Subdomain wie beim A-Record
    • Value/Target: Die IPv6-Adresse deines Hetzner-Servers

DNS-Änderungen können ein paar Minuten bis mehrere Stunden brauchen, bis sie propagiert sind. Du kannst mit Tools wie dig oder Online-DNS-Checkern prüfen, ob dein DNS korrekt konfiguriert ist. Sobald der DNS-Record aktiv ist, kannst du mit der Caddy-Konfiguration weitermachen.

Caddy konfigurieren

Bearbeite die Caddyfile-Konfigurationsdatei:

Terminal
sudo nano /etc/caddy/Caddyfile

Trag deine Domain ein und konfiguriere den Reverse Proxy. Ersetze "yourdomain.com" durch deine echte Domain:

Caddyfile
yourdomain.com {
    reverse_proxy localhost:8080
}

Wenn du noch keine Domain hast, nutze vorübergehend diese Variante:

Caddyfile
:80 {
    reverse_proxy localhost:8080
}

Starte Caddy neu, damit die Config geladen wird:

Terminal
sudo systemctl restart caddy

Schritt 6: AppFlowy mit Docker Compose starten

AppFlowy Cloud besteht aus mehreren Services: dem Haupt-API-Server, Authentifizierung (GoTrue), einem Admin-Panel, einem Background Worker, AI-Service, PostgreSQL mit pgvector, Redis, MinIO für Object Storage und einem Nginx Reverse Proxy, der alles zusammenbringt.

Erstell zuerst ein Verzeichnis für AppFlowy und die Nginx-Config:

Terminal
mkdir -p /opt/appflowy/nginx
cd /opt/appflowy

Environment-Datei erstellen

Generiere starke Passwörter für die Services:

Terminal
openssl rand -base64 32

Führ diesen Befehl mehrmals aus, um für jedes Feld unten ein eigenes Passwort zu bekommen.

Erstell die .env-Datei:

Terminal
sudo nano /opt/appflowy/.env

Füg folgenden Inhalt ein und ersetze alle CHANGE_ME_...-Werte durch deine generierten Passwörter:

.env
# AppFlowy Base URL (deine Domain mit https, ohne Slash am Ende)
APPFLOWY_BASE_URL=https://yourdomain.com

# PostgreSQL
POSTGRES_USER=appflowy
POSTGRES_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD
POSTGRES_DB=appflowy

# MinIO Object Storage
MINIO_USER=minioadmin
MINIO_PASSWORD=CHANGE_ME_MINIO_PASSWORD

# JWT Secret (generieren mit: openssl rand -base64 32)
JWT_SECRET=CHANGE_ME_JWT_SECRET

# GoTrue Admin-Zugangsdaten
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=CHANGE_ME_ADMIN_PASSWORD

# SMTP-Einstellungen (optional — für E-Mail-Einladungen)
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_ADMIN_EMAIL=

# OpenAI API Key (optional — für AI-Features)
OPENAI_API_KEY=

Achte drauf, dass du jeden CHANGE_ME_...-Platzhalter durch ein starkes, einzigartiges Passwort ersetzt. Passwörter zwischen Services wiederzuverwenden ist ein Sicherheitsrisiko.

Nginx-Config erstellen

Der integrierte Nginx-Service leitet den Traffic an die richtigen AppFlowy-Backend-Services weiter.

Terminal
sudo nano /opt/appflowy/nginx/nginx.conf

Füg folgende Config ein:

nginx/nginx.conf
error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    resolver 127.0.0.11 valid=10s;
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    server {
        listen 80;
        client_max_body_size 10M;
        underscores_in_headers on;

        set $appflowy_cloud_backend "http://appflowy_cloud:8000";
        set $gotrue_backend "http://gotrue:9999";
        set $admin_frontend_backend "http://admin_frontend:3000";

        # GoTrue Authentication
        location /gotrue/ {
            proxy_pass $gotrue_backend;
            rewrite ^/gotrue(/.*)$ $1 break;
            proxy_set_header Host $http_host;
            proxy_pass_request_headers on;
        }

        # WebSocket-Endpoint
        location /ws {
            proxy_pass $appflowy_cloud_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            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;
            proxy_read_timeout 86400s;
        }

        # API-Endpoints
        location /api {
            proxy_pass $appflowy_cloud_backend;
            proxy_set_header X-Request-Id $request_id;
            proxy_set_header Host $http_host;

            # Publish-Endpoint (große Uploads)
            location ~* ^/api/workspace/([a-zA-Z0-9_-]+)/publish$ {
                proxy_pass $appflowy_cloud_backend;
                proxy_request_buffering off;
                client_max_body_size 256M;
            }

            # Chat-Endpoint (Streaming)
            location /api/chat {
                proxy_pass $appflowy_cloud_backend;
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                chunked_transfer_encoding on;
                proxy_buffering off;
                proxy_cache off;
                proxy_read_timeout 600s;
                proxy_connect_timeout 600s;
                proxy_send_timeout 600s;
            }

            # Import-Endpoint (sehr große Uploads)
            location /api/import {
                proxy_pass $appflowy_cloud_backend;
                proxy_set_header X-Request-Id $request_id;
                proxy_set_header Host $http_host;
                proxy_read_timeout 600s;
                proxy_connect_timeout 600s;
                proxy_send_timeout 600s;
                proxy_request_buffering off;
                proxy_buffering off;
                proxy_cache off;
                client_max_body_size 2G;
            }
        }

        # Admin Frontend
        location /console {
            proxy_pass $admin_frontend_backend;
            proxy_set_header X-Scheme $scheme;
            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;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_buffering off;
            proxy_cache off;
            proxy_read_timeout 60s;
            proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
        }

        # Root zur Admin-Konsole umleiten
        location = / {
            return 301 /console;
        }

        # Health Check
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
}

Docker Compose-Datei erstellen

Terminal
sudo nano /opt/appflowy/compose.yml

Füg folgenden Inhalt ein:

compose.yml
services:
  nginx:
    image: nginx:1.29.2
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - appflowy_cloud
      - gotrue
      - admin_frontend
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  appflowy_cloud:
    image: appflowyinc/appflowy_cloud:0.9.149
    restart: unless-stopped
    environment:
      - RUST_LOG=info
      - APPFLOWY_BASE_URL=${APPFLOWY_BASE_URL}
      - APPFLOWY_ENVIRONMENT=production
      - APPFLOWY_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
      - APPFLOWY_REDIS_URI=redis://redis:6379
      - APPFLOWY_GOTRUE_JWT_SECRET=${JWT_SECRET}
      - APPFLOWY_GOTRUE_BASE_URL=http://gotrue:9999
      - APPFLOWY_S3_CREATE_BUCKET=true
      - APPFLOWY_S3_USE_MINIO=true
      - APPFLOWY_S3_MINIO_URL=http://minio:9000
      - APPFLOWY_S3_ACCESS_KEY=${MINIO_USER}
      - APPFLOWY_S3_SECRET_KEY=${MINIO_PASSWORD}
      - APPFLOWY_S3_BUCKET=appflowy
      - APPFLOWY_S3_REGION=us-east-1
      - APPFLOWY_MAILER_SMTP_HOST=${SMTP_HOST:-smtp.gmail.com}
      - APPFLOWY_MAILER_SMTP_PORT=${SMTP_PORT:-587}
      - APPFLOWY_MAILER_SMTP_USERNAME=${SMTP_USER:-notify@appflowy.io}
      - APPFLOWY_MAILER_SMTP_EMAIL=${SMTP_USER:-notify@appflowy.io}
      - APPFLOWY_MAILER_SMTP_PASSWORD=${SMTP_PASS:-email_sender_password}
      - APPFLOWY_MAILER_SMTP_TLS_KIND=none
      - APPFLOWY_ACCESS_CONTROL=true
      - APPFLOWY_DATABASE_MAX_CONNECTIONS=40
      - AI_SERVER_HOST=ai
      - AI_SERVER_PORT=5001
      - AI_OPENAI_API_KEY=${OPENAI_API_KEY:-}
      - APPFLOWY_WEB_URL=http://appflowy_web:3000
    healthcheck:
      test: "curl --fail http://127.0.0.1:8000/api/health || exit 1"
      interval: 5s
      timeout: 5s
      retries: 12
    depends_on:
      gotrue:
        condition: service_healthy
      postgres:
        condition: service_healthy
      redis:
        condition: service_started

  gotrue:
    image: appflowyinc/gotrue:0.9.149
    restart: unless-stopped
    environment:
      - GOTRUE_API_HOST=0.0.0.0
      - GOTRUE_API_PORT=9999
      - PORT=9999
      - GOTRUE_ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com}
      - GOTRUE_ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - GOTRUE_DISABLE_SIGNUP=false
      - GOTRUE_SITE_URL=appflowy-flutter://
      - GOTRUE_URI_ALLOW_LIST=**
      - GOTRUE_JWT_SECRET=${JWT_SECRET}
      - GOTRUE_JWT_EXP=7200
      - GOTRUE_DB_DRIVER=postgres
      - API_EXTERNAL_URL=${APPFLOWY_BASE_URL}/gotrue
      - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?search_path=auth
      - GOTRUE_SMTP_HOST=${SMTP_HOST}
      - GOTRUE_SMTP_PORT=${SMTP_PORT:-587}
      - GOTRUE_SMTP_USER=${SMTP_USER}
      - GOTRUE_SMTP_PASS=${SMTP_PASS}
      - GOTRUE_MAILER_URLPATHS_CONFIRMATION=/verify
      - GOTRUE_MAILER_URLPATHS_INVITE=/verify
      - GOTRUE_MAILER_URLPATHS_RECOVERY=/verify
      - GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE=/verify
      - GOTRUE_SMTP_ADMIN_EMAIL=${SMTP_ADMIN_EMAIL}
      - GOTRUE_SMTP_MAX_FREQUENCY=1ns
      - GOTRUE_RATE_LIMIT_EMAIL_SENT=100
      - GOTRUE_MAILER_AUTOCONFIRM=true
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: "curl --fail http://127.0.0.1:9999/health || exit 1"
      interval: 5s
      timeout: 5s
      retries: 12

  admin_frontend:
    image: appflowyinc/admin_frontend:0.9.149
    restart: unless-stopped
    environment:
      - APPFLOWY_GOTRUE_BASE_URL=${APPFLOWY_BASE_URL}/gotrue
      - APPFLOWY_BASE_URL=${APPFLOWY_BASE_URL}
    depends_on:
      gotrue:
        condition: service_healthy
      appflowy_cloud:
        condition: service_started

  appflowy_web:
    image: appflowyinc/appflowy_web:0.9.132
    restart: unless-stopped
    environment:
      - APPFLOWY_BASE_URL=${APPFLOWY_BASE_URL}
      - APPFLOWY_GOTRUE_BASE_URL=${APPFLOWY_BASE_URL}/gotrue
      - APPFLOWY_WS_BASE_URL=${APPFLOWY_BASE_URL}/ws/v2
    depends_on:
      - appflowy_cloud

  ai:
    image: appflowyinc/appflowy_ai:0.9.149
    restart: unless-stopped
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY:-}
      - AI_SERVER_PORT=5001
      - DEFAULT_AI_MODEL=gpt-4.1-mini
      - DEFAULT_AI_COMPLETION_MODEL=gpt-4.1-mini
      - AI_APPFLOWY_HOST=http://appflowy_web:3000
      - APPFLOWY_GOTRUE_JWT_SECRET=${JWT_SECRET}
      - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY:-}
      - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT:-}
      - AZURE_OPENAI_API_VERSION=${AZURE_OPENAI_API_VERSION:-}
      - APPFLOWY_S3_ACCESS_KEY=${MINIO_USER}
      - APPFLOWY_S3_SECRET_KEY=${MINIO_PASSWORD}
      - APPFLOWY_S3_BUCKET=appflowy
      - APPFLOWY_S3_REGION=us-east-1
      - AI_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
      - AI_REDIS_URL=redis://redis:6379
      - AI_USE_MINIO=true
      - AI_MINIO_URL=http://minio:9000
    depends_on:
      postgres:
        condition: service_healthy

  appflowy_worker:
    image: appflowyinc/appflowy_worker:0.9.149
    restart: unless-stopped
    environment:
      - RUST_LOG=info
      - APPFLOWY_ENVIRONMENT=production
      - APPFLOWY_WORKER_ENVIRONMENT=production
      - APPFLOWY_WORKER_REDIS_URL=redis://redis:6379
      - APPFLOWY_WORKER_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
      - APPFLOWY_WORKER_DATABASE_NAME=${POSTGRES_DB}
      - APPFLOWY_WORKER_IMPORT_TICK_INTERVAL=30
      - APPFLOWY_S3_USE_MINIO=true
      - APPFLOWY_S3_MINIO_URL=http://minio:9000
      - APPFLOWY_S3_ACCESS_KEY=${MINIO_USER}
      - APPFLOWY_S3_SECRET_KEY=${MINIO_PASSWORD}
      - APPFLOWY_S3_BUCKET=appflowy
      - APPFLOWY_S3_REGION=us-east-1
      - APPFLOWY_MAILER_SMTP_HOST=${SMTP_HOST:-smtp.gmail.com}
      - APPFLOWY_MAILER_SMTP_PORT=${SMTP_PORT:-587}
      - APPFLOWY_MAILER_SMTP_USERNAME=${SMTP_USER:-notify@appflowy.io}
      - APPFLOWY_MAILER_SMTP_EMAIL=${SMTP_USER:-notify@appflowy.io}
      - APPFLOWY_MAILER_SMTP_PASSWORD=${SMTP_PASS:-email_sender_password}
      - APPFLOWY_MAILER_SMTP_TLS_KIND=none
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started

  minio:
    image: minio/minio:RELEASE.2025-09-07T16-13-09Z
    restart: unless-stopped
    environment:
      - MINIO_ROOT_USER=${MINIO_USER}
      - MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
    command: server /data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3
    volumes:
      - minio_data:/data

  postgres:
    image: pgvector/pgvector:pg16
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_HOST=postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}", "-d", "${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 12

  redis:
    image: redis:8.2.2-alpine3.22
    restart: unless-stopped
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli -h localhost -p 6379 ping"]
      interval: 5s
      timeout: 5s
      retries: 3

volumes:
  minio_data:
  postgres_data:
  redis_data:

Die Image-Versionen oben waren zum Zeitpunkt des Schreibens aktuell. Prüf Docker Hub für die neuesten stabilen AppFlowy-Versionen.

Jetzt alle Services starten:

Terminal
cd /opt/appflowy
sudo docker compose up -d

Damit werden alle Images heruntergeladen und der komplette AppFlowy Cloud-Stack gestartet. Der erste Start dauert ein paar Minuten, während PostgreSQL initialisiert und alle Health Checks durchlaufen. Du kannst den Fortschritt überwachen mit:

Terminal
sudo docker compose logs -f

Warte, bis die Haupt-Services als healthy angezeigt werden, bevor du weitermachst. Du kannst das prüfen mit:

Terminal
sudo docker compose ps

Schritt 7: Auf deine selbst gehostete AppFlowy-Instanz zugreifen

Sobald alle Services laufen, ist deine AppFlowy-Admin-Konsole unter https://yourdomain.com/console erreichbar. Bei temporärem HTTP-Setup öffne http://your-server-ip:8080/console.

Melde dich im Admin-Panel mit den Zugangsdaten aus deiner .env-Datei an:

  • Email: Der ADMIN_EMAIL-Wert (Standard: admin@example.com)
  • Password: Der ADMIN_PASSWORD-Wert, den du konfiguriert hast

Um AppFlowy als Workspace zu nutzen, lad die AppFlowy Desktop- oder Mobile-App herunter und gib beim Setup deine Server-URL (https://yourdomain.com) an.

Sicherheitsempfehlungen

Ein öffentlicher Server sollte immer gut abgesichert sein:

  • Nutze starke, einzigartige Passwörter für alle Services in deiner .env-Datei.
  • HTTPS wird bereits automatisch von Caddy über Let's Encrypt gehandhabt.
  • Spiel regelmäßig System-Updates und Sicherheitspatches ein mit sudo apt-get update && sudo apt-get upgrade -y.
  • Prüf deine Firewall-Konfiguration regelmäßig mit sudo ufw status verbose.
  • Richte regelmäßige Backups deiner PostgreSQL-Datenbank und des MinIO Object Storage ein. Schau dir unseren Guide zum Backup und Restore von Postgres via SSH-Tunnel für mehr Details an.
  • Installiere Tools wie Fail2ban für zusätzlichen Brute-Force-Schutz.

AppFlowy-Installation aktualisieren

Wenn du AppFlowy aktualisieren willst, prüf zuerst Docker Hub für die neuesten Image-Versionen. Aktualisiere die Version-Tags in deiner compose.yml, dann führ aus:

Terminal
cd /opt/appflowy
sudo docker compose pull
sudo docker compose up -d

Docker lädt die aktualisierten Images und ersetzt deine aktuellen Container. Deine Daten liegen in Docker Volumes und bleiben bei Updates erhalten.

Kostenvergleich mit anderen Anbietern

AppFlowy Cloud läuft mit mehreren Services und profitiert von einem Server mit mindestens 4 GB RAM:

ProvidervCPU CoresRAMDiskGeschätzte monatliche KostenHinweise
Sliplane48 GB160 GB€44Abrechnung pro Server
Render48 GB80 GB~$85–$120Pro-Plan nötig
Fly.io48 GB40 GB~$60–$80VM + Volumes
Railway48 GB40 GB~$50–$100Nutzungsbasiert

Fazit

Du hast jetzt eine vollständig selbst gehostete AppFlowy Cloud-Instanz auf Hetzner mit Docker, automatischem HTTPS über Caddy und allen unterstützenden Services für einen kompletten kollaborativen Workspace. Verbinde dich mit der Desktop- oder Mobile-App und organisiere deine Projekte mit voller Datenhoheit.

Deploy AppFlowy in Minuten

Überspring Server-Setup und starte AppFlowy auf Sliplane mit einem Klick, HTTPS und persistentem Storage.