diff --git a/.env.sample b/.env.sample index 6237de2..1491138 100644 --- a/.env.sample +++ b/.env.sample @@ -1,3 +1,6 @@ +#SECRET_DB_PASSWORD_VERSION=v1 +#SECRET_SMTP_PASSWORD_VERSION=v1 + TYPE=ghost DOMAIN=ghost.example.com @@ -13,4 +16,7 @@ LETS_ENCRYPT_ENV=production #MAIL_OPTIONS_PORT=587 #MAIL_OPTIONS_SECURE=false #MAIL_OPTIONS_AUTH_USER=smtpuser@example.com -#MAIL_OPTIONS_AUTH_PASS=XXXX \ No newline at end of file + +## Matrix-Synapse-Redirection +# COMPOSE_FILE="$COMPOSE_FILE:compose.matrix.yml" +# MATRIX_DOMAIN=matrix-synapse.example.com \ No newline at end of file diff --git a/README.md b/README.md index 884f441..fe78550 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ # ghost -Headless Node.js CMS for professional publishing +Node.js CMS for professional publishing (headless possible). * **Category**: Apps -* **Status**: -* **Image**: -* **Healthcheck**: -* **Backups**: -* **Email**: Y -* **Tests**: -* **SSO**: +* **Status**: 3, stable +* **Image**: [`ghost`](https://hub.docker.com/_/ghost), 4, upstream +* **Healthcheck**: Yes +* **Backups**: Yes +* **Email**: Yes +* **Tests**: No +* **SSO**: N/A @@ -28,3 +28,8 @@ Headless Node.js CMS for professional publishing [`abra`]: https://git.coopcloud.tech/coop-cloud/abra [`coop-cloud/traefik`]: https://git.coopcloud.tech/coop-cloud/traefik + + +## Further configuration +### Matrix-Synapse configuration +If you want to use Ghost on a top-level-domain which you want to use as matrix server name as well, just uncomment the respective section in `YOURAPPDOMAIN.env` and insert your `MATRIX_DOMAIN` \ No newline at end of file diff --git a/abra.sh b/abra.sh new file mode 100644 index 0000000..d6cf678 --- /dev/null +++ b/abra.sh @@ -0,0 +1 @@ +export GHOST_ENTRYPOINT_VERSION=v1 \ No newline at end of file diff --git a/compose.matrix.yml b/compose.matrix.yml new file mode 100644 index 0000000..187d8e6 --- /dev/null +++ b/compose.matrix.yml @@ -0,0 +1,7 @@ +services: + app: + deploy: + labels: + - "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}-redirect-matrix-well-known" + - "traefik.http.middlewares.${STACK_NAME}-redirect-matrix-well-known.redirectregex.regex=^https://(.*)/.well-known/matrix/(.*)" + - "traefik.http.middlewares.${STACK_NAME}-redirect-matrix-well-known.redirectregex.replacement=https://${MATRIX_DOMAIN}/.well-known/matrix/$$2" \ No newline at end of file diff --git a/compose.yml b/compose.yml index 5339968..c7bea9a 100644 --- a/compose.yml +++ b/compose.yml @@ -1,4 +1,3 @@ -version: "3.8" services: app: image: ghost:5-alpine @@ -7,18 +6,29 @@ services: database__client: mysql database__connection__host: ${STACK_NAME}_db database__connection__user: root - database__connection__password: ghost database__connection__database: ghost + database__connection__password_FILE: /run/secrets/db_password url: https://$DOMAIN mail__transport: ${MAIL_TRANSPORT} mail__from: ${MAIL_FROM} mail__options__host: ${MAIL_OPTIONS_HOST} mail__options__port: ${MAIL_OPTIONS_PORT} mail__options__secure: ${MAIL_OPTIONS_SECURE} - #mail__options__auth__user: ${MAIL_OPTIONS_AUTH_USER} - #mail__options__auth__pass: ${MAIL_OPTIONS_AUTH_PASS} + mail__options__auth__user: ${MAIL_OPTIONS_AUTH_USER} + mail__options__auth__pass_FILE: /run/secrets/smtp_password # contrary to the default mentioned in the linked documentation, this image defaults to NODE_ENV=production (so development mode needs to be explicitly specified if desired) #NODE_ENV: development + secrets: + - db_password + - smtp_password + configs: + - source: ghost_entrypoint + target: /abra-entrypoint.sh + mode: 0555 + command: ["node", "current/index.js"] + entrypoint: /abra-entrypoint.sh + depends_on: + - db networks: - proxy - backend @@ -39,29 +49,38 @@ services: - "traefik.http.middlewares.${STACK_NAME}-redirect.headers.SSLHost=${DOMAIN}" - "backupbot.backup=true" - "backupbot.backup.path=/var/lib/ghost/content" - - "coop-cloud.${STACK_NAME}.version=0.1.0+5.2.4" - # healthcheck: - # test: ["CMD", "curl", "-f", "http://localhost"] - # interval: 30s - # timeout: 10s - # retries: 10 - # start_period: 1m + - "coop-cloud.${STACK_NAME}.version=0.1.0+5-alpine" + healthcheck: + test: ["CMD", "wget", "--header=X-Forwarded-Proto: https", "--spider", "-q", "http://localhost:2368/ghost/api/admin/site"] + interval: 30s + timeout: 10s + retries: 10 + start_period: 1m db: - image: mysql:5.7 + image: mysql:8.0 networks: - backend environment: - MYSQL_ROOT_PASSWORD: ghost + MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password + secrets: + - db_password volumes: - "mysql:/var/lib/mysql" deploy: labels: - "backupbot.backup=true" - - "backupbot.backup.pre-hook=mysqldump -u root -pghost ghost --tab /var/lib/mysql-files/" + - "backupbot.backup.pre-hook=mysqldump -u root -p\"$$(cat /run/secrets/db_password)\" ghost --tab /var/lib/mysql-files/" - "backupbot.backup.post-hook=rm -rf /var/lib/mysql-files/*" - "backupbot.backup.path=/var/lib/mysql-files/" + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p\"$$(cat /run/secrets/db_password)\""] + interval: 30s + timeout: 10s + retries: 10 + start_period: 1m + networks: proxy: external: true @@ -70,3 +89,16 @@ networks: volumes: mysql: ghost_content: + +secrets: + db_password: + name: ${STACK_NAME}_db_password_${SECRET_DB_PASSWORD_VERSION} + external: true + smtp_password: + external: true + name: ${STACK_NAME}_smtp_password_${SECRET_SMTP_PASSWORD_VERSION} + +configs: + ghost_entrypoint: + name: ${STACK_NAME}_ghost_entrypoint_${GHOST_ENTRYPOINT_VERSION} + file: entrypoint.sh \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..007eaff --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +set -e + +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + + local val="$def" + + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + + export "$var"="$val" + unset "$fileVar" +} + + +file_env "database__connection__password" +file_env "mail__options__auth__pass" + +# upstream entrypoint https://github.com/docker-library/ghost/blob/master/5/alpine/Dockerfile +exec /usr/local/bin/docker-entrypoint.sh "$@" \ No newline at end of file diff --git a/release/1.0.0+5-alpine.txt b/release/1.0.0+5-alpine.txt new file mode 100644 index 0000000..ef99a1e --- /dev/null +++ b/release/1.0.0+5-alpine.txt @@ -0,0 +1,66 @@ +# ! BREAKING CHANGE ! Attention! +There are two things you need to change manually: +1. insert secrets for mysql database and smtp +2. migrate your MySQL database from 5.7 to 8.0 + +## 1. insert secret +The recipe now includes two secrets: `db_password` and `smtp_password` make sure you change them. +To not break somthing, just insert `ghost` as `db_password` because this was the hard coded password before. +If desired to change the db-password, I recommend to do try it after migrating as I run in some difficult to debug problems doing this. + +abra app secret insert $APP db_password v1 ghost +abra app secret insert $APP smtp_password v1 your_smtp_password + +and adapt your env: + +add + +SECRET_DB_PASSWORD_VERSION=v1 +SECRET_SMTP_PASSWORD_VERSION=v1 + +delete mysql and smtp-password env. + +## 2. migrate your MySQL database from 5.7 to 8.0 +Recipe updates MySQL version from 5.7 to 8.0 as it is the only supported version of ghost: +https://ghost.org/docs/faq/supported-databases/ + +This makes a manual migration necessary. + +This one worked for me. + +Although you create a database-backup. Better to make sure you have a full backup before. + +## Follow these steps: + +# set your env-var to APP_URL to not have to repeat yourself +APP_URL=queerit.org + +# First make a full backup of database +abra app run "$APP_URL" db -t -- mysqldump -u root -pghost ghost > ~/.abra/backups/"$APP_URL"_pre_upgrade_to_mysql_8.sql 2>/dev/null + +# undeploy +abra app undeploy "$APP_URL" + +# delete database volume +abra app volume rm "$APP_URL" +# -> press "left" to deselect all, then "up"/"down" to find the volume, "space" to select "foo_bar_com_mysql, "enter" to confirm + +# redeploy (with the current recipe, db version 8.0 - will recreate database volume +# attention: because the app service is restarted as well, it will reinitialize soon the database +# this can lead to errors when restoring the database. I ran into: ERROR 1050 (42S01) at line 1147: Table 'members_stripe_customers_subscriptions' already exists +# solved it be deleting the volume again and restoring the databse as soon as possible after redeploying +abra app deploy "$APP_URL" + +# restore database +abra app run "$APP_URL" db -t -- mysql -u root -pghost ghost < ~/.abra/backups/"$APP_URL"_pre_upgrade_to_mysql_8.sql + +# correct db by creating ALTER TABLE commands like its described here: https://ghost.org/docs/faq/supported-databases/ +echo "SET foreign_key_checks=0;" > ~/.abra/backups/"$APP_URL"_alter_table.sql +abra app run ghost.dev.local-it.cloud db -t -- mysql -u root -pghost ghost -B --disable-column-names -e 'SELECT CONCAT("ALTER TABLE ",TABLE_SCHEMA,".",TABLE_NAME," CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; ", "ALTER TABLE ",TABLE_SCHEMA,".",TABLE_NAME," CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;") AS alter_sql FROM information_schema.TABLES WHERE TABLE_SCHEMA = database();' >> ~/.abra/backups/"$APP_URL"_alter_table.sql 2>/dev/null +echo "SET foreign_key_checks=1;" >> ~/.abra/backups/"$APP_URL"_alter_table.sql + +# run these alter_table.sql commands +abra app run "$APP_URL" db -t -- mysql -u root -pghost ghost < ~/.abra/backups/"$APP_URL"_alter_table.sql + + +