diff --git a/.gitignore b/.gitignore index 30d52b7..192d1d5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ config/production.tfvars config/ssh-keys # generated files +all-apps/.env all-apps/lb/Caddyfile all-apps/nextcloud/nextcloud.env all-apps/nextcloud/nextcloud_admin_user diff --git a/Makefile b/Makefile index 9d391b2..1add306 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,17 @@ app/.dirstamp: all-apps/app.service all-apps/docker-compose.yaml \ $(wildcard all-apps/lb/*) \ $(wildcard all-apps/nextcloud/*) \ $(wildcard all-apps/wg-easy/*) \ +$(wildcard all-apps/ghost/*) \ $(wildcard all-apps/dozzle/*) rm -Rf app/ cp -a all-apps app && touch $@ +# compose .env files +# (compose only supports one .env file at the root by default) +all-apps/.env: all-apps/*/.compose-env + find all-apps/ -name ".compose-env" -exec cat > all-apps/.env {} + + # Caddy / lb all-apps/lb/Caddyfile: $(apps_config) make-caddyfile.sh mkdir -p all-apps/lb @@ -42,6 +48,7 @@ restic-password: $(apps_config) make-restic-password.sh ./make-restic-password.sh $(apps_config) > restic-password ignition.json: cl.yaml app/.dirstamp \ +all-apps/.env \ all-apps/lb/Caddyfile \ all-apps/nextcloud/nextcloud_admin_user \ all-apps/nextcloud/nextcloud_admin_password \ diff --git a/all-apps/ghost/docker-compose.yaml b/all-apps/ghost/docker-compose.yaml new file mode 100644 index 0000000..a0091fd --- /dev/null +++ b/all-apps/ghost/docker-compose.yaml @@ -0,0 +1,187 @@ +services: + ghost: + image: ghost:${GHOST_VERSION:-6-alpine} + restart: always + # This is required to import current config when migrating + environment: + NODE_ENV: production + url: https://${GHOST_DOMAIN:?GHOST_DOMAIN environment variable is required} + admin__url: ${GHOST_ADMIN_DOMAIN:+https://${GHOST_ADMIN_DOMAIN}} + database__client: mysql + database__connection__host: ghost_db + database__connection__user: ${GHOST_DATABASE_USER:-ghost} + database__connection__password: ${GHOST_DATABASE_PASSWORD:?GHOST_DATABASE_PASSWORD environment variable is required} + database__connection__database: ghost + tinybird__tracker__endpoint: https://${GHOST_DOMAIN:?GHOST_DOMAIN environment variable is required}/.ghost/analytics/api/v1/page_hit + tinybird__adminToken: ${GHOST_TINYBIRD_ADMIN_TOKEN:-} + tinybird__workspaceId: ${GHOST_TINYBIRD_WORKSPACE_ID:-} + tinybird__tracker__datasource: analytics_events + tinybird__stats__endpoint: ${GHOST_TINYBIRD_API_URL:-https://api.tinybird.co} + volumes: + - ${GHOST_UPLOAD_LOCATION:-./data/ghost}:/var/lib/ghost/content + depends_on: + ghost_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 + networks: + - ghost_network + - lb + + ghost_db: + image: mysql:8.0.44@sha256:f37951fc3753a6a22d6c7bf6978c5e5fefcf6f31814d98c582524f98eae52b21 + restart: always + expose: + - "3306" + environment: + MYSQL_ROOT_PASSWORD: ${GHOST_DATABASE_ROOT_PASSWORD:?GHOST_DATABASE_ROOT_PASSWORD environment variable is required} + MYSQL_USER: ${GHOST_DATABASE_USER:-ghost} + MYSQL_PASSWORD: ${GHOST_DATABASE_PASSWORD:?GHOST_DATABASE_PASSWORD environment variable is required} + MYSQL_DATABASE: ghost + MYSQL_MULTIPLE_DATABASES: activitypub + volumes: + - ${GHOST_MYSQL_DATA_LOCATION:-./data/mysql}:/var/lib/mysql + - ./mysql-init:/docker-entrypoint-initdb.d + healthcheck: + test: mysqladmin ping -p$$GHOST_MYSQL_ROOT_PASSWORD -h 127.0.0.1 + interval: 1s + start_period: 30s + start_interval: 10s + retries: 120 + networks: + - ghost_network + + traffic-analytics: + image: ghost/traffic-analytics:1.0.20@sha256:a72573d89457e778b00e9061422516d2d266d79a72a0fc02005ba6466e391859 + restart: always + expose: + - "3000" + volumes: + - traffic_analytics_data:/data + environment: + NODE_ENV: production + PROXY_TARGET: ${GHOST_TINYBIRD_API_URL:-https://api.tinybird.co}/v0/events + SALT_STORE_TYPE: ${GHOST_SALT_STORE_TYPE:-file} + SALT_STORE_FILE_PATH: /data/salts.json + TINYBIRD_TRACKER_TOKEN: ${GHOST_TINYBIRD_TRACKER_TOKEN:-} + LOG_LEVEL: debug + profiles: [analytics] + networks: + - ghost_network + + activitypub: + image: ghcr.io/tryghost/activitypub:1.1.0@sha256:39c212fe23603b182d68e67d555c6b9b04b1e57459dfc0bef26d6e4980eb04d1 + restart: always + expose: + - "8080" + volumes: + - ${GHOST_UPLOAD_LOCATION:-./data/ghost}:/opt/activitypub/content + environment: + # See https://github.com/TryGhost/ActivityPub/blob/main/docs/env-vars.md + NODE_ENV: production + MYSQL_HOST: ghost_db + MYSQL_USER: ${GHOST_DATABASE_USER:-ghost} + MYSQL_PASSWORD: ${GHOST_DATABASE_PASSWORD:?GHOST_DATABASE_PASSWORD environment variable is required} + MYSQL_DATABASE: activitypub + LOCAL_STORAGE_PATH: /opt/activitypub/content/images/activitypub + LOCAL_STORAGE_HOSTING_URL: https://${GHOST_DOMAIN}/content/images/activitypub + depends_on: + ghost_db: + condition: service_healthy + activitypub-migrate: + condition: service_completed_successfully + profiles: [activitypub] + networks: + - ghost_network + + # Supporting Services + + 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] + networks: + - ghost_network + tty: false + restart: no + + tinybird-sync: + # Do not alter this without updating the Ghost container as well + image: ghost:${GHOST_VERSION:-6-alpine} + 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 + networks: + - ghost_network + 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] + networks: + - ghost_network + tty: true + + activitypub-migrate: + image: ghcr.io/tryghost/activitypub-migrations:1.1.0@sha256:b3ab20f55d66eb79090130ff91b57fe93f8a4254b446c2c7fa4507535f503662 + environment: + MYSQL_DB: mysql://${GHOST_DATABASE_USER:-ghost}:${GHOST_DATABASE_PASSWORD:?GHOST_DATABASE_PASSWORD environment variable is required}@tcp(ghost_db:3306)/activitypub + networks: + - ghost_network + depends_on: + ghost_db: + condition: service_healthy + profiles: [activitypub] + restart: no + +volumes: + caddy_data: + caddy_config: + tinybird_files: + tinybird_home: + traffic_analytics_data: + +networks: + lb: + ghost_network: + driver: bridge + internal: true diff --git a/config/apps.config.tmpl b/config/apps.config.tmpl index c215616..83432c2 100644 --- a/config/apps.config.tmpl +++ b/config/apps.config.tmpl @@ -1,5 +1,5 @@ ROOT_DOMAIN= # example.com :: the root of the domain that all apps should be subdomains of -APP_CONFIGS="nextcloud,nextcloud wg-easy,wg-easy" # apps to deploy and their corresponding sub-domain (app,sub-domain) +APP_CONFIGS="nextcloud,nextcloud wg-easy,wg-easy ghost,ghost" # apps to deploy and their corresponding sub-domain (app,sub-domain) NEXTCLOUD_ADMIN_USER=admin # admin user for nextcloud, can be whatever you want NEXTCLOUD_ADMIN_PASSWORD= # the password for the nextcloud admin user NEXTCLOUD_POSTGRES_DB=nextcloud # recommended to leave as 'nextcloud'. The postgres db nextcloud uses diff --git a/config/production.tfvars.tmpl b/config/production.tfvars.tmpl index 3571527..128469f 100644 --- a/config/production.tfvars.tmpl +++ b/config/production.tfvars.tmpl @@ -9,4 +9,4 @@ cloudflare_account_id = "" # corresponding account ID for API token cluster_name = "mycluster" # currently only used as the name of the machine on DigitalOcean datacenter = "sfo3" # datacenter to deploy the droplet to ssh_keys = [""] # unused -flatcar_stable_version = "4230.2.1" # (source <(curl -sSfL https://stable.release.flatcar-linux.net/amd64-usr/current/version.txt); echo "${FLATCAR_VERSION_ID}") +flatcar_stable_version = "4459.2.1" # (source <(curl -sSfL https://stable.release.flatcar-linux.net/amd64-usr/current/version.txt); echo "${FLATCAR_VERSION_ID}") diff --git a/make-caddyfile.sh b/make-caddyfile.sh index d4e70f6..ca00b0a 100755 --- a/make-caddyfile.sh +++ b/make-caddyfile.sh @@ -25,6 +25,7 @@ APP_CONFIGS+=('lb,root') declare -A bodys bodys["nextcloud"]=" reverse_proxy http://nextcloud:80" bodys["wg-easy"]=" reverse_proxy http://wg-easy:80" +bodys["ghost"]=" reverse_proxy http://ghost:2368" bodys["dozzle"]=$(cat <