compose.dev.yaml
Rama main · réplica de lectura del repositorio original.
name: ghost-dev
services:
mysql:
image: mysql:8.4.11@sha256:0f51e63e537a1f176423fa03ef559aabe6fa4372a53160a44bc7e75da7d15364
container_name: ghost-dev-mysql
# Shared by every checkout's Ghost and DB test runs, which outgrow MySQL's default 151 connections
command: --innodb-buffer-pool-size=1G --innodb-log-buffer-size=500M --innodb-change-buffer-max-size=50 --innodb-flush-log-at-trx_commit=0 --innodb-flush-method=O_DIRECT --log-error-verbosity=1 --max-connections=1000
ports:
- '3306:3306'
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root}
MYSQL_DATABASE: ${MYSQL_DATABASE:-ghost_dev}
MYSQL_USER: ghost
MYSQL_PASSWORD: ghost
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test:
[
'CMD',
'mysql',
'-h',
'127.0.0.1',
'-uroot',
'-p${MYSQL_ROOT_PASSWORD:-root}',
'-e',
'SELECT 1',
]
interval: 1s
retries: 120
timeout: 5s
start_period: 10s
start_interval: 1s
redis:
image: redis:7.4@sha256:2e3eb11462c4e3759e6972678dd051d150ff54b1e60714b3c33b701260172a90
container_name: ghost-dev-redis
command: ['redis-server', '--loglevel', 'warning']
ports:
- '6379:6379'
volumes:
- redis-data:/data
healthcheck:
test:
- CMD
- redis-cli
- --raw
- incr
- ping
interval: 1s
retries: 120
mailpit:
image: axllent/mailpit@sha256:9b3a463be15354c0f0eba91697d80e3e0d8a5623ef0e627cacc836bc17fd5231
container_name: ghost-dev-mailpit
# Tags each message with the SMTP username, which `pnpm dev` sets to the checkout's name
command: ['--quiet', '--smtp-auth-accept-any', '--smtp-auth-allow-insecure', '--tags-username']
ports:
- '1025:1025' # SMTP server
- '8025:8025' # Web interface
- '8026:8025' # Web interface (for e2e tests)
healthcheck:
interval: 1s
retries: 30
# Main development Ghost instance
# Additional instances can be created programmatically via E2E GhostManager
# `pnpm dev` runs Ghost and the dev servers on the host; these two services back
# `pnpm dev:docker` and the modes built on it, and e2e dev mode.
ghost-dev:
profiles: ['docker-dev']
build:
context: ./
dockerfile: docker/ghost-dev/Dockerfile
container_name: ghost-dev
working_dir: /home/ghost/ghost
command: ['pnpm', 'dev']
# The entrypoint drains Ghost before exiting; give that longer than Docker's 10s
stop_grace_period: 45s
volumes:
# Mount the backend source as whole-directory mounts instead of
# enumerating each server-graph workspace package. `pnpm dev` runs in
# ghost, and pnpm's verify-deps-before-run only checks ghost's
# own dependency closure — which is fully installed in the root
# /home/ghost/node_modules baked into the image and never mounted over —
# so the non-server packages these dirs also expose (e.g. koenig-lexical)
# fall outside that closure and don't trigger a
# workspace repair. Because root node_modules is never mounted,
# linux-built native modules survive; each package's local node_modules
# holds only relative symlinks that re-resolve into the root store.
# verify-deps-before-run=false is set below as belt-and-suspenders in
# case a future pnpm widens that check back to the whole workspace.
- ./ghost:/home/ghost/ghost
- ./koenig:/home/ghost/koenig
- ./configs:/home/ghost/configs
- ./packages:/home/ghost/packages
# Mount specific content subdirectories to preserve themes/adapters from source
- ghost-dev-data:/home/ghost/ghost/content/data
- ghost-dev-images:/home/ghost/ghost/content/images
- ghost-dev-media:/home/ghost/ghost/content/media
- ghost-dev-files:/home/ghost/ghost/content/files
- ghost-dev-logs:/home/ghost/ghost/content/logs
- shared-config:/mnt/shared-config:ro
environment:
NODE_ENV: development
NODE_TLS_REJECT_UNAUTHORIZED: '0'
DEBUG: ${DEBUG:-}
pnpm_config_verify_deps_before_run: 'false'
database__client: mysql2
database__connection__host: mysql
database__connection__user: root
database__connection__password: ${MYSQL_ROOT_PASSWORD:-root}
database__connection__database: ${MYSQL_DATABASE:-ghost_dev}
server__host: 0.0.0.0
server__port: 2368
# Apply Ghost(Pro)'s public query parameter allowlist in local development
queryParameterFiltering__enabled: '${QUERY_PARAMETER_FILTERING_ENABLED:-true}'
mail__transport: SMTP
mail__options__host: mailpit
mail__options__port: 1025
# Redis cache (optional)
adapters__cache__Redis__host: redis
adapters__cache__Redis__port: 6379
# Apps under development run on the host machine, where `localhost` is not this
# container: Ghost fetches their manifests through this alias instead
apps__localhostAlias: host.docker.internal
# Docker Desktop and OrbStack provide host.docker.internal and forward it to the host's
# loopback. On Linux it needs this, and it reaches the docker bridge rather than
# loopback: an app that only listens on 127.0.0.1 (Vite's default) is not reachable
# through it, so bind the app to 0.0.0.0 while developing against this container.
extra_hosts:
- 'host.docker.internal:host-gateway'
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
mailpit:
condition: service_healthy
stripe:
condition: service_healthy
required: false
healthcheck:
test:
[
'CMD',
'node',
'-e',
"fetch('http://localhost:2368',{redirect:'manual'}).then(r=>process.exit(r.status<500?0:1)).catch(()=>process.exit(1))",
]
timeout: 5s
retries: 10
start_period: 5s
# Caddy reverse proxy for the main dev instance
# Routes Ghost backend + proxies asset requests to host dev servers
ghost-dev-gateway:
profiles: ['docker-dev']
build:
context: ./docker/dev-gateway
dockerfile: Dockerfile
container_name: ghost-dev-gateway
environment:
ANALYTICS_PROXY_TARGET: ${ANALYTICS_PROXY_TARGET:-analytics:3000}
ports:
- '2368:80'
- '80:80'
extra_hosts:
- 'host.docker.internal:host-gateway'
volumes:
# Mount Caddyfile for live config changes without rebuilding
- ./docker/dev-gateway/Caddyfile:/etc/caddy/Caddyfile:ro
# All workspace apps mounted read-only. Caddy file_server resolves
# /srv/apps/<name>/umd dynamically for the public-app routes (see
# the Caddyfile @public_app block). Replaces the per-app `vite preview`
# sirv layer + avoids per-app bind mounts.
- ./apps:/srv/apps:ro
depends_on:
ghost-dev:
condition: service_healthy
stripe:
image: stripe/stripe-cli:latest@sha256:c8e5a48108fb4c1e83583912c85810e9ac3bc8db91070da3f915ac369ceecf31
container_name: ghost-dev-stripe
entrypoint: ['/entrypoint.sh']
profiles: ['stripe']
volumes:
- ./docker/stripe/entrypoint.sh:/entrypoint.sh:ro
- shared-config:/mnt/shared-config
environment:
- GHOST_URL=${GHOST_URL:-http://ghost-dev:2368}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY:-}
# `pnpm dev:stripe --listen` forwards to the Admin dev server on the host
extra_hosts:
- 'host.docker.internal:host-gateway'
healthcheck:
test: ['CMD', 'test', '-f', '/mnt/shared-config/.env.stripe']
interval: 1s
retries: 120
volumes:
mysql-data:
redis-data:
shared-config:
ghost-dev-data:
ghost-dev-images:
ghost-dev-media:
ghost-dev-files:
ghost-dev-logs:
networks:
default:
name: ghost_dev