feat: add Coolify deployment platform to dev stack

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 <noreply@anthropic.com>
This commit is contained in:
2025-11-15 13:24:09 +01:00
parent 5d3fa7618b
commit 140b240bab
3 changed files with 112 additions and 2 deletions

View File

@@ -155,7 +155,7 @@ envs:
MEDIA_FILESTASH_IMAGE: machines/filestash:latest MEDIA_FILESTASH_IMAGE: machines/filestash:latest
MEDIA_FILESTASH_TRAEFIK_HOST: filestash.media.pivoine.art MEDIA_FILESTASH_TRAEFIK_HOST: filestash.media.pivoine.art
MEDIA_FILESTASH_CANARY: true MEDIA_FILESTASH_CANARY: true
# Dev (Gitea + Runner) # Dev (Gitea + Coolify)
DEV_TRAEFIK_ENABLED: true DEV_TRAEFIK_ENABLED: true
DEV_COMPOSE_PROJECT_NAME: dev DEV_COMPOSE_PROJECT_NAME: dev
DEV_GITEA_IMAGE: gitea/gitea:latest DEV_GITEA_IMAGE: gitea/gitea:latest
@@ -163,6 +163,9 @@ envs:
DEV_GITEA_DB_NAME: gitea DEV_GITEA_DB_NAME: gitea
DEV_GITEA_RUNNER_IMAGE: gitea/act_runner:latest DEV_GITEA_RUNNER_IMAGE: gitea/act_runner:latest
DEV_GITEA_RUNNER_NAME: docker-runner 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 # PairDrop
DROP_TRAEFIK_ENABLED: true DROP_TRAEFIK_ENABLED: true
DROP_COMPOSE_PROJECT_NAME: drop DROP_COMPOSE_PROJECT_NAME: drop

View File

@@ -45,6 +45,10 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
SELECT 'CREATE DATABASE gitea' SELECT 'CREATE DATABASE gitea'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'gitea')\\gexec 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 privileges to all databases
GRANT ALL PRIVILEGES ON DATABASE directus TO $POSTGRES_USER; GRANT ALL PRIVILEGES ON DATABASE directus TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE umami 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 mattermost TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE tandoor 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 asciinema TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE gitea TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE coolify TO $POSTGRES_USER;
-- Log success -- Log success
SELECT 'Compose databases initialized:' AS status; SELECT 'Compose databases initialized:' AS status;
SELECT datname FROM pg_database 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; ORDER BY datname;
EOSQL EOSQL
@@ -75,4 +81,6 @@ echo " • joplin - Note-taking server database"
echo " • mattermost - Chat platform database" echo " • mattermost - Chat platform database"
echo " • tandoor - Recipe manager database" echo " • tandoor - Recipe manager database"
echo " • asciinema - Terminal recording server database" echo " • asciinema - Terminal recording server database"
echo " • gitea - Self-hosted Git service database"
echo " • coolify - Deployment platform database"
echo "" echo ""

View File

@@ -83,6 +83,101 @@ services:
networks: networks:
- compose_network - 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: volumes:
gitea_data: gitea_data:
name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_data name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_data
@@ -90,6 +185,10 @@ volumes:
name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_config name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_config
gitea_runner_data: gitea_runner_data:
name: ${DEV_COMPOSE_PROJECT_NAME}_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: networks:
compose_network: compose_network: