165 lines
6 KiB
Bash
165 lines
6 KiB
Bash
|
|
#!/bin/sh
|
||
|
|
# Prepare the site, then hand over to PHP-FPM.
|
||
|
|
#
|
||
|
|
# Three jobs, all of which have to survive an image upgrade without destroying
|
||
|
|
# anything the site owner did:
|
||
|
|
#
|
||
|
|
# 1. WordPress core and the fork's own plugins are copied out of the image
|
||
|
|
# into the document root on every start, so rebuilding the image is a
|
||
|
|
# real upgrade. Plugins and themes installed from the dashboard live in
|
||
|
|
# their own volumes and are left alone.
|
||
|
|
#
|
||
|
|
# 2. wp-config.php is generated once, into a volume, and copied into place
|
||
|
|
# each start. Never regenerated — new salts would end every session, and
|
||
|
|
# a new SIRIUS_PRESS_KEY would make the stored publishing phrase
|
||
|
|
# undecryptable, which looks exactly like a corrupted wallet.
|
||
|
|
#
|
||
|
|
# 3. Nothing waits on the network except the database, and that with a
|
||
|
|
# bounded timeout: a site that will not start is worse than one that
|
||
|
|
# starts and says the database is unreachable.
|
||
|
|
|
||
|
|
set -eu
|
||
|
|
|
||
|
|
DOCROOT=/var/www/html
|
||
|
|
SOURCE=/opt/sirius-press/core
|
||
|
|
CONFIG_STORE=/var/www/config/wp-config.php
|
||
|
|
CONFIG=$DOCROOT/wp-config.php
|
||
|
|
|
||
|
|
random_key() {
|
||
|
|
# 64 characters of printable entropy. `tr -dc` over /dev/urandom is the one
|
||
|
|
# method available in a slim image without adding tools.
|
||
|
|
tr -dc 'A-Za-z0-9!@#%^&*()_+=-' < /dev/urandom | head -c 64
|
||
|
|
}
|
||
|
|
|
||
|
|
wait_for_db() {
|
||
|
|
# Compose's healthcheck covers the container, but a first run also has to
|
||
|
|
# wait out MariaDB's own initialisation.
|
||
|
|
i=0
|
||
|
|
while [ "$i" -lt 60 ]; do
|
||
|
|
if php -r 'exit(@mysqli_connect(getenv("WORDPRESS_DB_HOST"), getenv("WORDPRESS_DB_USER"), getenv("WORDPRESS_DB_PASSWORD")) ? 0 : 1);' 2>/dev/null; then
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
i=$((i + 1))
|
||
|
|
sleep 1
|
||
|
|
done
|
||
|
|
echo "sirius-press: the database did not answer within 60s; starting anyway" >&2
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
|
||
|
|
# --------------------------------------------------------------------- core
|
||
|
|
|
||
|
|
# Copy everything except wp-content, which has volumes of its own, then put
|
||
|
|
# back the directories the fork owns. Anything the site owner installed from
|
||
|
|
# the dashboard sits in those same volumes and is never touched.
|
||
|
|
echo "sirius-press: syncing WordPress $(cat "$SOURCE/.sirius-core-version" 2>/dev/null || echo '?') into the document root"
|
||
|
|
|
||
|
|
for entry in "$SOURCE"/*; do
|
||
|
|
name="$(basename "$entry")"
|
||
|
|
if [ "$name" = "wp-content" ]; then
|
||
|
|
continue
|
||
|
|
fi
|
||
|
|
rm -rf "${DOCROOT:?}/${name}"
|
||
|
|
cp -R "$entry" "$DOCROOT/"
|
||
|
|
done
|
||
|
|
cp "$SOURCE/.sirius-core-version" "$DOCROOT/.sirius-core-version" 2>/dev/null || true
|
||
|
|
|
||
|
|
mkdir -p "$DOCROOT/wp-content/plugins" "$DOCROOT/wp-content/themes" "$DOCROOT/wp-content/mu-plugins" "$DOCROOT/wp-content/uploads"
|
||
|
|
|
||
|
|
# Seed bundled themes only when the themes volume is empty — replacing them on
|
||
|
|
# every start would undo a site owner's edits to a bundled theme.
|
||
|
|
if [ -z "$(ls -A "$DOCROOT/wp-content/themes" 2>/dev/null)" ]; then
|
||
|
|
cp -R "$SOURCE/wp-content/themes/." "$DOCROOT/wp-content/themes/" 2>/dev/null || true
|
||
|
|
fi
|
||
|
|
|
||
|
|
# The fork's own plugins are the image's to own, and are replaced outright.
|
||
|
|
for dir in "$SOURCE"/wp-content/plugins/sirius-press-*/; do
|
||
|
|
[ -d "$dir" ] || continue
|
||
|
|
name="$(basename "$dir")"
|
||
|
|
rm -rf "${DOCROOT:?}/wp-content/plugins/${name}"
|
||
|
|
cp -R "$dir" "$DOCROOT/wp-content/plugins/"
|
||
|
|
done
|
||
|
|
cp "$SOURCE"/wp-content/mu-plugins/*.php "$DOCROOT/wp-content/mu-plugins/" 2>/dev/null || true
|
||
|
|
|
||
|
|
# Everything else WordPress ships in wp-content (akismet, the index.php
|
||
|
|
# guards) only needs to exist once.
|
||
|
|
for extra in akismet index.php; do
|
||
|
|
if [ ! -e "$DOCROOT/wp-content/plugins/$extra" ] && [ -e "$SOURCE/wp-content/plugins/$extra" ]; then
|
||
|
|
cp -R "$SOURCE/wp-content/plugins/$extra" "$DOCROOT/wp-content/plugins/"
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
chown -R www-data:www-data "$DOCROOT"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------- wp-config
|
||
|
|
|
||
|
|
if [ ! -f "$CONFIG_STORE" ]; then
|
||
|
|
echo "sirius-press: generating wp-config.php"
|
||
|
|
|
||
|
|
: "${WORDPRESS_DB_HOST:=db}"
|
||
|
|
: "${WORDPRESS_DB_NAME:=wordpress}"
|
||
|
|
: "${WORDPRESS_DB_USER:=wordpress}"
|
||
|
|
: "${WORDPRESS_DB_PASSWORD:=wordpress}"
|
||
|
|
: "${WORDPRESS_TABLE_PREFIX:=wp_}"
|
||
|
|
if [ -z "${SIRIUS_PRESS_KEY:-}" ]; then
|
||
|
|
SIRIUS_PRESS_KEY="$(random_key)"
|
||
|
|
fi
|
||
|
|
|
||
|
|
mkdir -p "$(dirname "$CONFIG_STORE")"
|
||
|
|
{
|
||
|
|
echo "<?php"
|
||
|
|
echo "// Generated by the Sirius Press container on first start."
|
||
|
|
echo "// Edit freely — this file is kept in a volume and never rewritten."
|
||
|
|
echo
|
||
|
|
echo "define( 'DB_NAME', '${WORDPRESS_DB_NAME}' );"
|
||
|
|
echo "define( 'DB_USER', '${WORDPRESS_DB_USER}' );"
|
||
|
|
echo "define( 'DB_PASSWORD', '${WORDPRESS_DB_PASSWORD}' );"
|
||
|
|
echo "define( 'DB_HOST', '${WORDPRESS_DB_HOST}' );"
|
||
|
|
echo "define( 'DB_CHARSET', 'utf8mb4' );"
|
||
|
|
echo "define( 'DB_COLLATE', '' );"
|
||
|
|
echo
|
||
|
|
for k in AUTH_KEY SECURE_AUTH_KEY LOGGED_IN_KEY NONCE_KEY \
|
||
|
|
AUTH_SALT SECURE_AUTH_SALT LOGGED_IN_SALT NONCE_SALT; do
|
||
|
|
echo "define( '${k}', '$(random_key)' );"
|
||
|
|
done
|
||
|
|
echo
|
||
|
|
echo "// The key the publishing phrase is encrypted with. Separate from"
|
||
|
|
echo "// the auth salts so rotating sessions does not orphan the stored"
|
||
|
|
echo "// key. Lose this and the phrase must be entered again."
|
||
|
|
echo "define( 'SIRIUS_PRESS_KEY', '${SIRIUS_PRESS_KEY}' );"
|
||
|
|
echo
|
||
|
|
echo "// nginx terminates TLS in front of this container, so PHP has to"
|
||
|
|
echo "// be told. Without it WordPress builds http:// URLs and a"
|
||
|
|
echo "// redirect loop follows."
|
||
|
|
echo "if ( isset( \$_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === \$_SERVER['HTTP_X_FORWARDED_PROTO'] ) {"
|
||
|
|
echo " \$_SERVER['HTTPS'] = 'on';"
|
||
|
|
echo "}"
|
||
|
|
echo "define( 'SIRIUS_PRESS_TRUST_PROXY', true );"
|
||
|
|
echo
|
||
|
|
if [ -n "${WORDPRESS_SITE_URL:-}" ]; then
|
||
|
|
echo "define( 'WP_HOME', '${WORDPRESS_SITE_URL}' );"
|
||
|
|
echo "define( 'WP_SITEURL', '${WORDPRESS_SITE_URL}' );"
|
||
|
|
fi
|
||
|
|
echo "define( 'FS_METHOD', 'direct' );"
|
||
|
|
echo "define( 'WP_DEBUG', ${WORDPRESS_DEBUG:-false} );"
|
||
|
|
echo
|
||
|
|
echo "\$table_prefix = '${WORDPRESS_TABLE_PREFIX}';"
|
||
|
|
echo
|
||
|
|
echo "if ( ! defined( 'ABSPATH' ) ) {"
|
||
|
|
echo " define( 'ABSPATH', __DIR__ . '/' );"
|
||
|
|
echo "}"
|
||
|
|
echo "require_once ABSPATH . 'wp-settings.php';"
|
||
|
|
} > "$CONFIG_STORE"
|
||
|
|
chmod 640 "$CONFIG_STORE"
|
||
|
|
fi
|
||
|
|
|
||
|
|
cp "$CONFIG_STORE" "$CONFIG"
|
||
|
|
chown www-data:www-data "$CONFIG"
|
||
|
|
chmod 640 "$CONFIG"
|
||
|
|
|
||
|
|
|
||
|
|
if [ "${1:-}" = "php-fpm" ]; then
|
||
|
|
wait_for_db || true
|
||
|
|
fi
|
||
|
|
|
||
|
|
exec "$@"
|