Is my Dokploy Ghost template correct? Need help with ActivityPub setup

Hey everyone,

I’ve been working on a sample Dokploy template for the Dokploy/templates GitHub repo and wanted to check if this setup looks correct before I submit it.

It’s a Ghost blog deployment with MySQL, optional Tinybird analytics, and ActivityPub support.

Here’s the docker-compose.yml I wrote:
(full code block)

version: "3.8"
services:
  ghost:
    image: ghost:${GHOST_VERSION}
    restart: always
    env_file:
      - .env
    environment:
      NODE_ENV: production
      url: https://${DOMAIN}
      #  admin__url: https://${ADMIN_DOMAIN}
      database__client: mysql
      database__connection__host: db
      database__connection__user: ${DATABASE_USER}
      database__connection__password: ${DATABASE_PASSWORD}
      database__connection__database: ghost
      tinybird__tracker__endpoint: https://${DOMAIN}/.ghost/analytics/api/v1/page_hit
      tinybird__adminToken: ${TINYBIRD_ADMIN_TOKEN}
      tinybird__workspaceId: ${TINYBIRD_WORKSPACE_ID}
      tinybird__tracker__datasource: analytics_events
      tinybird__stats__endpoint: ${TINYBIRD_API_URL}
      ACTIVITYPUB_TARGET: ${ACTIVITYPUB_TARGET:-http://activitypub:8080}
    volumes:
      - ${UPLOAD_LOCATION}:/var/lib/ghost/content
    depends_on:
      db:
        condition: service_healthy
      tinybird-sync:
        condition: service_completed_successfully
        required: false
      tinybird-deploy:
        condition: service_completed_successfully
        required: false
      activitypub:
        condition: service_started
        required: false

  db:
    image: mysql:8.0.42@sha256:4445b2668d41143cb50e471ee207f8822006249b6859b24f7e12479684def5d9
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${DATABASE_ROOT_PASSWORD}
      MYSQL_USER: ${DATABASE_USER}
      MYSQL_PASSWORD: ${DATABASE_PASSWORD}
      MYSQL_DATABASE: ghost
      MYSQL_MULTIPLE_DATABASES: activitypub
    volumes:
      - ${MYSQL_DATA_LOCATION}:/var/lib/mysql
      - ./mysql-init:/docker-entrypoint-initdb.d
    healthcheck:
      test: mysqladmin ping -p$$MYSQL_ROOT_PASSWORD -h 127.0.0.1
      interval: 1s
      start_period: 30s
      start_interval: 10s
      retries: 120

  traffic-analytics:
    image: ghost/traffic-analytics:1.0.9@sha256:693e752f420b8b1bfcf9867946a09966552a15d4797b86b90ecf3d1dd0e1067c
    restart: always
    volumes:
      - traffic_analytics_data:/data
    environment:
      NODE_ENV: production
      PROXY_TARGET: ${TINYBIRD_API_URL}/v0/events
      SALT_STORE_TYPE: ${SALT_STORE_TYPE}
      SALT_STORE_FILE_PATH: /data/salts.json
      TINYBIRD_TRACKER_TOKEN: ${TINYBIRD_TRACKER_TOKEN}
      LOG_LEVEL: debug
    profiles: [analytics]

  activitypub:
    image: ghcr.io/tryghost/activitypub:1.1.0@sha256:39c212fe23603b182d68e67d555c6b9b04b1e57459dfc0bef26d6e4980eb04d1
    restart: always
    volumes:
      - ${UPLOAD_LOCATION}:/opt/activitypub/content
    environment:
      NODE_ENV: production
      PORT: 8080
      MYSQL_HOST: db
      MYSQL_USER: ${DATABASE_USER}
      MYSQL_PASSWORD: ${DATABASE_PASSWORD}
      MYSQL_DATABASE: activitypub
      ALLOW_PRIVATE_ADDRESS: true
      USE_MQ: false
      LOCAL_STORAGE_PATH: /opt/activitypub/content/images/activitypub
      LOCAL_STORAGE_HOSTING_URL: https://${DOMAIN}/content/images/activitypub
    depends_on:
      db:
        condition: service_healthy
      activitypub-migrate:
        condition: service_completed_successfully
    profiles: [activitypub]

  tinybird-login:
    build:
      context: ./tinybird
      dockerfile: Dockerfile
    working_dir: /home/tinybird
    command: /usr/local/bin/tinybird-login
    volumes:
      - tinybird_home:/home/tinybird
      - tinybird_files:/data/tinybird
    profiles: [analytics]
    tty: false
    restart: no

  tinybird-sync:
    image: ghost:${GHOST_VERSION}
    command: >
      sh -c "
        if [ -d /var/lib/ghost/current/core/server/data/tinybird ]; then
          rm -rf /data/tinybird/*;
          cp -rf /var/lib/ghost/current/core/server/data/tinybird/* /data/tinybird/;
          echo 'Tinybird files synced into shared volume.';
        else
          echo 'Tinybird source directory not found.';
        fi
      "
    volumes:
      - tinybird_files:/data/tinybird
    depends_on:
      tinybird-login:
        condition: service_completed_successfully
    profiles: [analytics]
    restart: no

  tinybird-deploy:
    build:
      context: ./tinybird
      dockerfile: Dockerfile
    working_dir: /data/tinybird
    command: >
      sh -c "tb-wrapper --cloud deploy"
    volumes:
      - tinybird_home:/home/tinybird
      - tinybird_files:/data/tinybird
    depends_on:
      tinybird-sync:
        condition: service_completed_successfully
    profiles: [analytics]
    tty: true

  activitypub-migrate:
    image: ghcr.io/tryghost/activitypub-migrations:1.1.0@sha256:b3ab20f55d66eb79090130ff91b57fe93f8a4254b446c2c7fa4507535f503662
    environment:
      MYSQL_DB: mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@tcp(db:3306)/activitypub
    depends_on:
      db:
        condition: service_healthy
    profiles: [activitypub]
    restart: no

volumes:
  tinybird_files:
  tinybird_home:
  traffic_analytics_data:

And here’s the .toml file for the template variables/config:

[variables]
main_domain = "${domain}"
admin_domain = "${domain}"
upload_location = "./data/ghost"
mysql_data_location = "./data/mysql"
ghost_version = "6-alpine"
database_password = "${password:32}"
database_root_password = "${password:32}"
tinybird_admin_token = "${password:32}"
tinybird_workspace_id = "${uuid}"
tinybird_tracker_token = "${password:32}"
tinybird_api_url = "https://api.tinybird.co"

[config]
[[config.domains]]
serviceName = "ghost"
port = 2368
host = "${main_domain}"

[config.env]
DOMAIN = "${main_domain}"
# ADMIN_DOMAIN = "${admin_domain}"
UPLOAD_LOCATION = "${upload_location}"
MYSQL_DATA_LOCATION = "${mysql_data_location}"
GHOST_VERSION = "${ghost_version}"
DATABASE_USER = "ghost"
DATABASE_PASSWORD = "${database_password}"
DATABASE_ROOT_PASSWORD = "${database_root_password}"
TINYBIRD_ADMIN_TOKEN = "${tinybird_admin_token}"
TINYBIRD_WORKSPACE_ID = "${tinybird_workspace_id}"
TINYBIRD_TRACKER_TOKEN = "${tinybird_tracker_token}"
TINYBIRD_API_URL = "${tinybird_api_url}"
ACTIVITYPUB_TARGET = "http://activitypub:8080"

Notes:

  • The Tinybird analytics service is throwing errors right now, but that’s because I haven’t given it correct API values yet so I’m not too worried about that.

  • I do need help getting the ActivityPub part working correctly with Ghost.

My questions:

  1. Is there anything in my Docker Compose file that might cause issues when running in Dokploy?

  2. Are the depends_on conditions and profiles correctly set up for optional services like analytics and ActivityPub?

  3. For ActivityPub, am I setting the MySQL and storage paths right? Any extra env vars I should be aware of?

  4. Do the .toml variables match best practices for Dokploy templates?

Any feedback from those familiar with Dokploy, Ghost in Docker, or ActivityPub setup would be awesome :folded_hands:

1 Like