From 140b240bab5650dde80693128c8ecad19c52434f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Sat, 15 Nov 2025 13:24:09 +0100 Subject: [PATCH] feat: add Coolify deployment platform to dev stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Coolify self-hosted deployment platform with: - Coolify main service at coolify.dev.pivoine.art - Dedicated PostgreSQL database (uses shared core instance) - Soketi WebSocket server for real-time features - Traefik routing with HTTPS and compression - Environment variables in arty.yml (secrets in .env) - Database creation in PostgreSQL init script Coolify enables deploying applications from Git repositories, including the pivoine.art Jekyll site from Gitea. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- arty.yml | 5 +- core/postgres/init/01-init-databases.sh | 10 ++- dev/compose.yaml | 99 +++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/arty.yml b/arty.yml index be387ed..9b51e21 100644 --- a/arty.yml +++ b/arty.yml @@ -155,7 +155,7 @@ envs: MEDIA_FILESTASH_IMAGE: machines/filestash:latest MEDIA_FILESTASH_TRAEFIK_HOST: filestash.media.pivoine.art MEDIA_FILESTASH_CANARY: true - # Dev (Gitea + Runner) + # Dev (Gitea + Coolify) DEV_TRAEFIK_ENABLED: true DEV_COMPOSE_PROJECT_NAME: dev DEV_GITEA_IMAGE: gitea/gitea:latest @@ -163,6 +163,9 @@ envs: DEV_GITEA_DB_NAME: gitea DEV_GITEA_RUNNER_IMAGE: gitea/act_runner:latest DEV_GITEA_RUNNER_NAME: docker-runner + DEV_COOLIFY_IMAGE: ghcr.io/coollabsio/coolify:latest + DEV_COOLIFY_TRAEFIK_HOST: coolify.dev.pivoine.art + DEV_COOLIFY_DB_NAME: coolify # PairDrop DROP_TRAEFIK_ENABLED: true DROP_COMPOSE_PROJECT_NAME: drop diff --git a/core/postgres/init/01-init-databases.sh b/core/postgres/init/01-init-databases.sh index 286a964..6bcb9f3 100644 --- a/core/postgres/init/01-init-databases.sh +++ b/core/postgres/init/01-init-databases.sh @@ -45,6 +45,10 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E SELECT 'CREATE DATABASE gitea' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'gitea')\\gexec + -- Coolify deployment platform database + SELECT 'CREATE DATABASE coolify' + WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'coolify')\\gexec + -- Grant privileges to all databases GRANT ALL PRIVILEGES ON DATABASE directus TO $POSTGRES_USER; GRANT ALL PRIVILEGES ON DATABASE umami TO $POSTGRES_USER; @@ -54,11 +58,13 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E GRANT ALL PRIVILEGES ON DATABASE mattermost TO $POSTGRES_USER; GRANT ALL PRIVILEGES ON DATABASE tandoor TO $POSTGRES_USER; GRANT ALL PRIVILEGES ON DATABASE asciinema TO $POSTGRES_USER; + GRANT ALL PRIVILEGES ON DATABASE gitea TO $POSTGRES_USER; + GRANT ALL PRIVILEGES ON DATABASE coolify TO $POSTGRES_USER; -- Log success SELECT 'Compose databases initialized:' AS status; SELECT datname FROM pg_database - WHERE datname IN ('directus', 'umami', 'n8n', 'linkwarden', 'joplin', 'mattermost', 'tandoor', 'asciinema') + WHERE datname IN ('directus', 'umami', 'n8n', 'linkwarden', 'joplin', 'mattermost', 'tandoor', 'asciinema', 'gitea', 'coolify') ORDER BY datname; EOSQL @@ -75,4 +81,6 @@ echo " • joplin - Note-taking server database" echo " • mattermost - Chat platform database" echo " • tandoor - Recipe manager database" echo " • asciinema - Terminal recording server database" +echo " • gitea - Self-hosted Git service database" +echo " • coolify - Deployment platform database" echo "" diff --git a/dev/compose.yaml b/dev/compose.yaml index 428fd70e..3f513ac 100644 --- a/dev/compose.yaml +++ b/dev/compose.yaml @@ -83,6 +83,101 @@ services: networks: - compose_network + # Coolify - Self-hosted deployment platform + coolify: + image: ${DEV_COOLIFY_IMAGE:-ghcr.io/coollabsio/coolify:latest} + container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify + restart: unless-stopped + depends_on: + coolify_postgres: + condition: service_healthy + coolify_soketi: + condition: service_started + volumes: + - coolify_data:/data/coolify + - /var/run/docker.sock:/var/run/docker.sock + - /data/coolify/ssh:/var/www/html/storage/app/ssh + - /data/coolify/applications:/var/www/html/storage/app/applications + - /data/coolify/databases:/var/www/html/storage/app/databases + - /data/coolify/services:/var/www/html/storage/app/services + - /data/coolify/backups:/var/www/html/storage/app/backups + environment: + - APP_ID=${DEV_COOLIFY_APP_ID} + - APP_KEY=${DEV_COOLIFY_APP_KEY} + - APP_NAME=Coolify + - APP_ENV=production + - APP_URL=https://${DEV_COOLIFY_TRAEFIK_HOST} + - APP_PORT=8000 + - DB_HOST=${CORE_DB_HOST} + - DB_PORT=${CORE_DB_PORT} + - DB_DATABASE=${DEV_COOLIFY_DB_NAME} + - DB_USERNAME=${DB_USER} + - DB_PASSWORD=${DB_PASSWORD} + - REDIS_HOST=${CORE_REDIS_HOST} + - REDIS_PORT=${CORE_REDIS_PORT} + - PUSHER_HOST=coolify_soketi + - PUSHER_PORT=6001 + - PUSHER_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID} + - PUSHER_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY} + - PUSHER_APP_SECRET=${DEV_COOLIFY_PUSHER_APP_SECRET} + - SSL_MODE=off + networks: + - compose_network + labels: + - 'traefik.enable=${DEV_TRAEFIK_ENABLED}' + # HTTP to HTTPS redirect + - 'traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure.redirectscheme.scheme=https' + - 'traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure' + - 'traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.entrypoints=web' + # HTTPS router + - 'traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.tls.certresolver=resolver' + - 'traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.entrypoints=web-secure' + - 'traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress.compress=true' + - 'traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress,security-headers@file' + # Service + - 'traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.loadbalancer.server.port=8000' + - 'traefik.docker.network=${NETWORK_NAME}' + # Watchtower + - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' + + # Coolify PostgreSQL + coolify_postgres: + image: postgres:15-alpine + container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_postgres + restart: unless-stopped + volumes: + - coolify_postgres_data:/var/lib/postgresql/data + environment: + - POSTGRES_USER=${DB_USER} + - POSTGRES_PASSWORD=${DB_PASSWORD} + - POSTGRES_DB=${DEV_COOLIFY_DB_NAME} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"] + interval: 5s + timeout: 5s + retries: 10 + networks: + - compose_network + + # Coolify Soketi (WebSocket server) + coolify_soketi: + image: quay.io/soketi/soketi:1.0.10-16-alpine + container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_soketi + restart: unless-stopped + environment: + - SOKETI_DEFAULT_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID} + - SOKETI_DEFAULT_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY} + - SOKETI_DEFAULT_APP_SECRET=${DEV_COOLIFY_PUSHER_APP_SECRET} + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:6001/ready"] + interval: 5s + timeout: 5s + retries: 10 + networks: + - compose_network + volumes: gitea_data: name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_data @@ -90,6 +185,10 @@ volumes: name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_config gitea_runner_data: name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_runner_data + coolify_data: + name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_data + coolify_postgres_data: + name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_postgres_data networks: compose_network: