TryGhost / TryGhost/ghost-docker

Simplify compose.yml (suggestion)

Open
#189 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Shell
Stars
95
Forks
96
Avg merge
1d 1h
Merged PRs (30d)
32

Description

I am not sure whether this is the right place to discuss this topic, but I think that compose.yml is much more complex that it needs to be. This is because it is being (ab)used as a scripting tool, to automate some steps. A better tool to implement automation would be bash scripting (the obvious choice, which is so obvious that nobody ever thinks about it, especially in the context of docker compose projects).

For example, to automate tinybird setup I would suggest a script like this:

setup-tinybird.sh
cmd_setup-tinybird_help() {
    cat <<_EOF
    setup-tinybird

        Automates the steps for Tinybird setup.  But it is not
        completely automated, requires manual intervention.

        Before starting, make sure you have an account
        with a workspace at: https://www.tinybird.co/

_EOF
}

cmd_setup-tinybird() {
    cat <<EOF

Before starting, make sure you have an account with a workspace
at: https://www.tinybird.co/

Press Ctrl-C to interrupt, or Enter to continue...

EOF
    read

    set -x
    get_the_repo
    build_the_image
    tinybird_login
    tinybird_sync
    tinybird_deploy
    get_tinybird_tokens
    update_config_files
    cleanup_and_restart
}

get_the_repo() {
    : Make a temporary directory and get the ghost-docker repo
    rm -rf tmp/
    mkdir tmp
    cd tmp/
    git clone https://github.com/TryGhost/ghost-docker.git .
    cd tinybird/
}

build_the_image() {
    : Build the docker image
    docker build -t tinybird-image .
}

tinybird_login() {
    : Authenticate the terminal
    docker run --rm -it \
           -v $(pwd)/tinybird_home:/home/tinybird \
           -v $(pwd)/tinybird_files:/data/tinybird \
           -w /home/tinybird \
           tinybird-image \
           /usr/local/bin/tinybird-login
}

tinybird_sync() {
    : Sync Tinybird files
    docker run --rm -it \
           -v $(pwd)/tinybird_files:/data/tinybird \
           ghost:6-alpine \
           bash -c 'cp -rf /var/lib/ghost/current/core/server/data/tinybird/* /data/tinybird/'
}

tinybird_deploy() {
    : Deploy Tinybird files to the workspace
    docker run --rm -it \
           -v $(pwd)/tinybird_home:/home/tinybird \
           -v $(pwd)/tinybird_files:/data/tinybird \
           -w /data/tinybird \
           tinybird-image \
           bash -c 'tb-wrapper --cloud deploy'
}

get_tinybird_tokens() {
    : Get the tokens
    docker run --rm -it \
           -v $(pwd)/tinybird_home:/home/tinybird \
           -v $(pwd)/tinybird_files:/data/tinybird \
           -w /home/tinybird \
           tinybird-image \
           get-tokens \
           > ../../env/tinybird-tokens.env
}

update_config_files() {
    : Read the tokens and update config files
    cd ../../env/
    source tinybird-tokens.env

    cat <<EOF > ghost-tinybird.env
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}
EOF
    
    cat <<EOF > analytics.env
NODE_ENV=production
PROXY_TARGET=${TINYBIRD_API_URL:-https://api.tinybird.co}/v0/events
SALT_STORE_TYPE=${SALT_STORE_TYPE:-file}
SALT_STORE_FILE_PATH=/data/salts.json
TINYBIRD_TRACKER_TOKEN=${TINYBIRD_TRACKER_TOKEN}
LOG_LEVEL=debug
EOF

    : Enable the analytics profile
    cd ..
    echo 'COMPOSE_PROFILES=activitypub,analytics' > .env
}

cleanup_and_restart() {
    : Cleanup
    docker rmi tinybird-image
    rm -rf tmp/

    : Restart
    docker compose up -d
}

This would make obsolete the services tinybird-login, tinybird-sync, tinybird-deploy, etc.

In my implementation, compose.yml looks like this:

create_compose_yml() {
    local container_name=${DOMAIN//./-}

    # create compose.yml
    cat <<EOF > compose.yml
services:
  ghost:
    image: ghost:6-alpine
    container_name: $container_name
    restart: unless-stopped
    env_file:
      - env/ghost.env
      - env/ghost-tinybird.env
    volumes:
      - ./content:/var/lib/ghost/content

  activitypub:
    image: ghcr.io/tryghost/activitypub:1.2.2
    container_name: ${container_name}-activitypub
    restart: unless-stopped
    profiles: [activitypub]
    env_file: env/activitypub.env
    volumes:
      - ./content:/opt/activitypub/content

  traffic-analytics:
    image: ghost/traffic-analytics:1.0.204
    container_name: ${container_name}-analytics
    restart: unless-stopped
    env_file: env/analytics.env
    profiles: [analytics]
    volumes:
      - ./content/traffic_analytics:/data

networks:
  default:
    external: true
    name: $NETWORK
EOF
}

Some of the modifications that I have done are these:

  • I have my own (external) reverse proxy and database containers (because I use them for other projects too)
  • I am using env_file: to define all the env variables of a service (this makes compose.yml smaller)
  • All the volumes are mounted to the local sub-directory ./content (this makes backup easier)

env files look like this:

env files
create_env_files() {
    # create ghost.env, if it does not exist
    local smtp_domain=${SMTP_DOMAIN:-${DOMAIN#*.}}
    local smtp_server=${SMTP_SERVER:-smtp.$smtp_domain}
    local from_address=${DOMAIN%%.*}@$smtp_domain
    mkdir -p env
    cat <<EOF > env/ghost.env
NODE_ENV=production
url=https://$DOMAIN

database__client=mysql
database__connection__host=$DBHOST
database__connection__user=$DBUSER
database__connection__password=$DBPASS
database__connection__database=$DBNAME

mail__transport=SMTP
mail__options__host=$smtp_server
mail__options__requireTLS=false
mail__from=$from_address

EOF
    
    cat <<'EOF' > env/ghost-tinybird.env
#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:-https://api.tinybird.co}
EOF
    
    cat <<EOF > env/activitypub.env
NODE_ENV=production
MYSQL_HOST=$DBHOST
MYSQL_USER=$DBUSER
MYSQL_PASSWORD=$DBPASS
MYSQL_DATABASE=${DBNAME}_activitypub
LOCAL_STORAGE_PATH=/opt/activitypub/content/images/activitypub
LOCAL_STORAGE_HOSTING_URL=https://${DOMAIN}/content/images/activitypub
EOF

    cat <<'EOF' > env/analytics.env
NODE_ENV=production
PROXY_TARGET=${TINYBIRD_API_URL:-https://api.tinybird.co}/v0/events
SALT_STORE_TYPE=${SALT_STORE_TYPE:-file}
SALT_STORE_FILE_PATH=/data/salts.json
TINYBIRD_TRACKER_TOKEN=${TINYBIRD_TRACKER_TOKEN:-}
LOG_LEVEL=debug
EOF
}

By the way, tinybird analytics is not working for me. ActivityPub is also not working properly (for example mastodon.social cannot find my handle @index@gazeta.univlora.al). Maybe it is related to my reverse proxy configuration (NGINX), which looks like this:

nginx config
server {
    listen 443 ssl;
    server_name gazeta.univlora.al ;

    ssl_certificate     certs/gazeta.univlora.al/fullchain.pem;
    ssl_certificate_key certs/gazeta.univlora.al/privkey.pem;

    access_log /var/log/nginx/gazeta.univlora.al-access.log;
    error_log /var/log/nginx/gazeta.univlora.al-error.log error;
    
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "frame-ancestors 'self'";

    include conf.d/proxy_params;
    proxy_set_header X-Forwarded-Host $host;

    #proxy_http_version 1.1;
    #proxy_set_header Upgrade $http_upgrade;
    #proxy_set_header Connection "upgrade";
    
    location / {
        proxy_pass http://gazeta-univlora-al:2368;
    }   
    
    location ^~ /.ghost/activitypub/ {
        proxy_pass http://gazeta-univlora-al-activitypub:8080;
    }   

    location ~ ^/\.well-known/(webfinger|nodeinfo) {
        proxy_pass http://gazeta-univlora-al-activitypub:8080;
    }   

    location ~ ^.*/\.ghost/analytics(?<suffix>.*)$ {
        proxy_pass http://gazeta-univlora-al-analytics:3000$suffix;
    }   
}   

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading compose.yml and comparing its automation services with the proposed setup-tinybird.sh and ds.sh examples. Review the referenced env files and NGINX configuration only as needed to separate the compose simplification from the reported Tinybird and ActivityPub problems. Done requires an agreed scope and a working replacement for the services being removed.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, docker-compose, nginx, shell
Domain
devops, infrastructure
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.