Deployed to a real VPS for the first time. The stack came up, the patched wizard served, the plugins activated and the 40-check auth suite passed over the public internet — and then every single export failed: cURL error 28: Failed to connect to <public ip> port 8081 after 10001 ms Not a bug in the export. A container cannot reach the host's own published port on most Docker hosts; there is simply no route back in. The exporter renders each page by asking the site for it over HTTP, so the one thing it depends on is the one thing a container cannot do. This would have hit every user of the documented install path on their first publish, and the error says nothing about the cause. SIRIUS_PRESS_LOOPBACK_URL gives the exporter a second address — in the bundled stack, the nginx service on the compose network — while the request still carries the site's real Host header. That matters twice: WordPress renders exactly the page a visitor gets rather than redirecting to a canonical URL the container cannot follow, and the internal hostname never appears in the exported HTML. Verified on the VPS: the page builds, the content is right, no absolute self-links, no `//web/` leaking out. Also documents the question underneath it — what WP_HOME should be when the site's public address is a BCNR name. Not the name: whatever the server is actually reachable at. The exported links are document-relative, so they work under the name regardless.
93 lines
3.2 KiB
YAML
93 lines
3.2 KiB
YAML
# Sirius Press — a complete self-hosted stack.
|
|
#
|
|
# Three containers: MariaDB, PHP-FPM with the patched WordPress baked in, and
|
|
# nginx in front. Only nginx is published.
|
|
#
|
|
# The volume layout is the part worth reading. WordPress core comes from the
|
|
# repository's `wordpress/` subtree, is baked into the image, and is refilled
|
|
# into the document root on every start — so `docker compose build && up -d`
|
|
# genuinely upgrades it — the usual arrangement, where the whole document root is a
|
|
# volume, freezes core at whatever version first created the volume and turns
|
|
# every security release into a manual migration. What people actually need to
|
|
# keep — uploads, plugins and themes they installed, and wp-config.php — is
|
|
# what gets a volume.
|
|
#
|
|
# cp .env.example .env # then edit it
|
|
# docker compose up -d
|
|
|
|
name: sirius-press
|
|
|
|
services:
|
|
db:
|
|
image: mariadb:11.4
|
|
restart: unless-stopped
|
|
environment:
|
|
MARIADB_DATABASE: ${DB_NAME:-wordpress}
|
|
MARIADB_USER: ${DB_USER:-wordpress}
|
|
MARIADB_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
|
|
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:?set DB_ROOT_PASSWORD in .env}
|
|
MARIADB_AUTO_UPGRADE: "1"
|
|
command:
|
|
# utf8mb4 throughout: a post containing an emoji should not be a
|
|
# database error, and WordPress has assumed this for years.
|
|
- --character-set-server=utf8mb4
|
|
- --collation-server=utf8mb4_unicode_ci
|
|
volumes:
|
|
- db:/var/lib/mysql
|
|
healthcheck:
|
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 12
|
|
|
|
app:
|
|
build:
|
|
context: ..
|
|
dockerfile: docker/Dockerfile
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
WORDPRESS_DB_HOST: db
|
|
WORDPRESS_DB_NAME: ${DB_NAME:-wordpress}
|
|
WORDPRESS_DB_USER: ${DB_USER:-wordpress}
|
|
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
|
|
WORDPRESS_SITE_URL: ${SITE_URL:-}
|
|
WORDPRESS_DEBUG: ${WP_DEBUG:-false}
|
|
SIRIUS_PRESS_KEY: ${SIRIUS_PRESS_KEY:-}
|
|
# nginx on this compose network. The exporter fetches pages here because
|
|
# a container cannot reach the host's own published port.
|
|
SIRIUS_PRESS_LOOPBACK_URL: ${SIRIUS_PRESS_LOOPBACK_URL:-http://web}
|
|
volumes:
|
|
- config:/var/www/config
|
|
# The document root is a volume so nginx can read the same files. It is
|
|
# refilled from the image on every start, so this does not pin core.
|
|
- core:/var/www/html
|
|
- uploads:/var/www/html/wp-content/uploads
|
|
- plugins:/var/www/html/wp-content/plugins
|
|
- themes:/var/www/html/wp-content/themes
|
|
|
|
web:
|
|
image: nginx:1.27-alpine
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- app
|
|
ports:
|
|
- "${HTTP_PORT:-80}:80"
|
|
volumes:
|
|
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
|
# nginx serves static files directly and only proxies PHP, so it needs
|
|
# to see the same tree. Read-only: the web tier has no business writing.
|
|
- core:/var/www/html:ro
|
|
- uploads:/var/www/html/wp-content/uploads:ro
|
|
- plugins:/var/www/html/wp-content/plugins:ro
|
|
- themes:/var/www/html/wp-content/themes:ro
|
|
|
|
volumes:
|
|
db:
|
|
config:
|
|
core:
|
|
uploads:
|
|
plugins:
|
|
themes:
|