diff --git a/Dockerfile b/Dockerfile index 116646ca7032a1cb7f256c81090667cb93ea8b13..980f31ef022d6ce4a3055618799b0692ccc3fb6e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,74 @@ -FROM wordpress:latest +FROM php:7.2-apache MAINTAINER Open Tools <office@open-tools.net> -RUN apt-get update +RUN set -ex; \ + \ + apt-get update; \ + apt-get install -y \ + libjpeg-dev \ + libpng-dev \ + ; \ + rm -rf /var/lib/apt/lists/*; \ + \ + docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr; \ + docker-php-ext-install gd mysqli opcache +# TODO consider removing the *-dev deps and only keeping the necessary lib* packages + +#RUN apt-get update \ +# && DEBIAN_FRONTEND=noninteractive apt-get install -o Dpkg::Options::='--force-confnew' -y --no-install-recommends php-mysql +# libapache2-mod-php RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -o Dpkg::Options::='--force-confnew' -y --no-install-recommends libapache2-mod-php5 php5-mysql - -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends unzip curl wget sudo vim aptitude less -RUN rm -rf /var/lib/apt/lists/* + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends unzip curl wget sudo vim aptitude less \ + && rm -rf /var/lib/apt/lists/* + +# set recommended PHP.ini settings +# see https://secure.php.net/manual/en/opcache.installation.php +RUN { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + echo 'opcache.enable_cli=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini + +RUN a2enmod rewrite expires + +RUN echo "mysql-server-5.5 mysql-server/root_password password root" | debconf-set-selections \ + && echo "mysql-server-5.5 mysql-server/root_password_again password root" | debconf-set-selections \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server \ + && rm -rf /var/lib/apt/lists/* + +RUN apt-get update && apt-get install -y supervisor && rm -rf /var/lib/apt/lists/* +RUN echo "[program:mysql]\ncommand=/usr/bin/pidproxy /run/mysqld/mysqld.pid /usr/bin/mysqld_safe \nautorestart=true\n" > /etc/supervisor/conf.d/mysql.conf.save + RUN curl -L "https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar" -o /usr/bin/wp-cli && \ chmod +x /usr/bin/wp-cli + +ENV WORDPRESS_VERSION 4.9.1 +ENV WORDPRESS_SHA1 892d2c23b9d458ec3d44de59b753adb41012e903 + +RUN set -ex; \ + curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ + echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +# upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress + tar -xzf wordpress.tar.gz -C /usr/src/; \ + rm wordpress.tar.gz; \ + chown -R www-data:www-data /usr/src/wordpress + ADD disable-curl.php /var/www/html/wp-content/plugins/disable-curl/disable-curl.php - + ADD install-wc.sh /install-wc.sh RUN chmod +x /install-wc.sh && chown www-data.www-data /install-wc.sh -VOLUME ["/var/www/html"] +COPY docker-entrypoint.sh /usr/local/bin/ +COPY supervisord.conf /etc/supervisor/supervisord.conf + +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] +#CMD ["apache2-foreground"] +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] + diff --git a/add-docker-vhost.sh b/add-docker-vhost.sh index 3220ff15be33aeb65911fc44e2e89a9097a2b390..9e2c5ec35dd3fa74c4483e3e175154c0da899bec 100755 --- a/add-docker-vhost.sh +++ b/add-docker-vhost.sh @@ -13,7 +13,8 @@ NAME=$1 PORT=$2 sudo echo "<VirtualHost *:80> - ServerName $NAME.dev + ServerName $NAME.test + ServerAlias $NAME.lacolhost.com ServerAdmin $NAME@demo.open-tools.net ProxyPreserveHost on diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000000000000000000000000000000000000..37828784fb696d8e858181e7fe153b2548aa8395 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,252 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +MYSQL_LOCAL=0 +WORDPRESS_INSTALLING=0 + + +if [[ "$1" == apache2* ]] || [[ "$1" == /usr/bin/supervisor* ]] || [ "$1" == php-fpm ]; then + file_env 'WORDPRESS_DB_HOST' '' + # if we're linked to MySQL and thus have credentials already, let's use them + file_env 'WORDPRESS_DB_USER' "${MYSQL_ENV_MYSQL_USER:-wordpress}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + file_env 'WORDPRESS_DB_PASSWORD' "${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}" + else + file_env 'WORDPRESS_DB_PASSWORD' "${MYSQL_ENV_MYSQL_PASSWORD:-wordpress}" + fi + file_env 'WORDPRESS_DB_NAME' "${MYSQL_ENV_MYSQL_DATABASE:-wordpress}" +# if [ -z "$WORDPRESS_DB_PASSWORD" ]; then +# echo >&2 'error: missing required WORDPRESS_DB_PASSWORD environment variable' +# echo >&2 ' Did you forget to -e WORDPRESS_DB_PASSWORD=... ?' +# echo >&2 +# echo >&2 ' (Also of interest might be WORDPRESS_DB_USER and WORDPRESS_DB_NAME.)' +# exit 1 +# fi + + # Check for local MySQL installation: + if [ -z "$WORDPRESS_DB_HOST" ] || [ "$WORDPRESS_DB_HOST" = "localhost" ] || ["$WORDPRESS_DB_HOST" = "127.0.0.1"]; then + MYSQL_LOCAL=1 + fi + + if ! [ -e index.php -a -e wp-includes/version.php ]; then + WORDPRESS_INSTALLING=1 + echo >&2 "WordPress not found in $(pwd) - copying now... First checking local database installation if neccessary." + if [ "$MYSQL_LOCAL" = "1" ]; then + # No linked container and no explicit DB host => local MySQL installation + echo >&2 "Neither linked database container nor mysql dabase server host given. " + echo >&2 " Assuming local installation. An instance of the MySQL server will be installed locally." + # No linked container and no explicit DB host => local MySQL installation + WORDPRESS_DB_HOST="127.0.0.1" + if [ -z "${WORDPRESS_DB_PASSWORD}" ]; then + WORDPRESS_DB_PASSWORD='wordpress' + echo >&2 "No MySQL password given. Assuming password 'wordpress'." + fi + echo >&2 " MySQL password for wordpress installation is ${WORDPRESS_DB_PASSWORD}." + + # Temporarily start the mysql daemon to set up the database and shut it + # down again (supervisord will start it at the very end) + echo "Starting local mysql server temporarily to set up the database..." + /usr/bin/mysqld_safe > /dev/null 2>&1 & + timeout=30 + echo -n "Waiting for database server to accept connections" + while ! /usr/bin/mysqladmin --user=root --password=root status > /dev/null 2>&1; do + timeout=$(($timeout-1)) + if [ $timeout -eq 0 ]; then + echo -e "\n Unable to connect to the database server. Aborting..." + exit 1 + fi + echo -n "." + sleep 1 + done + /usr/bin/mysqladmin --user=root --password=root status + /usr/bin/mysqladmin --user=root --password=root create "${WORDPRESS_DB_NAME}" + echo + echo "GRANT ALL PRIVILEGES ON *.* to '${WORDPRESS_DB_USER}'@'%' IDENTIFIED BY '${WORDPRESS_DB_PASSWORD}';" + echo "GRANT ALL PRIVILEGES ON *.* to '${WORDPRESS_DB_USER}'@'%' IDENTIFIED BY '${WORDPRESS_DB_PASSWORD}';" | mysql --user=root --password=root ${WORDPRESS_DB_NAME} + echo "Granted privileges" +# echo "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '${WORDPRESS_DB_PASSWORD}';" | mysql --user=root --password=root +# echo " update mysql.user set plugin = 'mysql_native_password' where User='root';" | mysql --user=root --password=root +# echo " flush privileges; " | mysql --user=root --password=root +# mysqladmin --user=root --password=root password "${WORDPRESS_DB_PASSWORD}" + + # enable mysqld in the supervisor config + echo "Copying MySQL config:" + cp /etc/supervisor/conf.d/mysql.conf.save /etc/supervisor/conf.d/mysql.conf + fi + + + echo >&2 "WordPress not found in $(pwd) - copying now..." +# if [ "$(ls -A)" ]; then +# echo >&2 "WARNING: $(pwd) is not empty - press Ctrl+C now if this is an error!" +# ( set -x; ls -A; sleep 100 ) +# fi + tar cf - --one-file-system -C /usr/src/wordpress . | tar xf - + echo >&2 "Complete! WordPress has been successfully copied to $(pwd)" + if [ ! -e .htaccess ]; then + # NOTE: The "Indexes" option is disabled in the php:apache base image + cat > .htaccess <<-'EOF' + # BEGIN WordPress + <IfModule mod_rewrite.c> + RewriteEngine On + RewriteBase / + RewriteRule ^index\.php$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . /index.php [L] + </IfModule> + # END WordPress + EOF + chown www-data:www-data .htaccess + fi + + # TODO handle WordPress upgrades magically in the same way, but only if wp-includes/version.php's $wp_version is less than /usr/src/wordpress/wp-includes/version.php's $wp_version + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r\n|\r/\n/g' wp-config* + + if [ ! -e wp-config.php ]; then + awk '/^\/\*.*stop editing.*\*\/$/ && c == 0 { c = 1; system("cat") } { print }' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert Wordpress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} +EOPHP + chown www-data:www-data wp-config.php + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + php -r 'var_export(('$2') $argv[1]);' -- "$1" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + UNIQUES=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + for unique in "${UNIQUES[@]}"; do + uniqVar="WORDPRESS_$unique" + file_env "$uniqVar" + if [ "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + current_set="$(sed -rn -e "s/define\((([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\);/\4/p" wp-config.php)" + if [ "$current_set" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + file_env 'WORDPRESS_TABLE_PREFIX' + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + file_env 'WORDPRESS_DEBUG' + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if [ "$MYSQL_LOCAL" != "1" ]; then + + TERM=dumb php -- "$WORDPRESS_DB_HOST" "$WORDPRESS_DB_USER" "$WORDPRESS_DB_PASSWORD" "$WORDPRESS_DB_NAME" <<'EOPHP' +<?php +// database might not exist, so let's try creating it (just to be safe) +$stderr = fopen('php://stderr', 'w'); +// https://codex.wordpress.org/Editing_wp-config.php#MySQL_Alternate_Port +// "hostname:port" +// https://codex.wordpress.org/Editing_wp-config.php#MySQL_Sockets_or_Pipes +// "hostname:unix-socket-path" +list($host, $socket) = explode(':', $argv[1], 2); +$port = 0; +if (is_numeric($socket)) { + $port = (int) $socket; + $socket = null; +} +$maxTries = 10; +do { + $mysql = new mysqli($host, $argv[2], $argv[3], '', $port, $socket); + if ($mysql->connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($argv[4]) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} +$mysql->close(); +EOPHP + + fi + if [ "$MYSQL_LOCAL" = "1" ] && [ "$WORDPRESS_INSTALLING" = "1" ]; then + # Local installation, so shut down MySQL again, will later be started through supervisord + echo "Shutting down temporary MySQL instance ..." + /usr/bin/mysqladmin --user=root --password=root shutdown + fi + + fi +fi + +exec "$@" diff --git a/install-wc.sh b/install-wc.sh index 57789e2892d692e0b12e62b13c0026c43667815d..901b2af196abea7194ef79acedacc3eae623eee7 100755 --- a/install-wc.sh +++ b/install-wc.sh @@ -9,8 +9,8 @@ cd /var/www/html pwd # sudo -u www-data /usr/bin/wp-cli core download --version=$1 --allow-root # sudo -u www-data /usr/bin/wp-cli core config --dbname=wordpress --dbuser=root --allow-root -sudo -u www-data /usr/bin/wp-cli core install --url="http://wc-$WC_HOST.dev/" --title="${WC_SITENAME}" --admin_user=opentools --admin_password=opentools --admin_email="wc-${WC_HOST}@demo.open-tools.net" -sudo -u www-data /usr/bin/wp-cli db query --allow-root "UPDATE wp_options SET option_value='http://wc-${WC_HOST}.dev/' WHERE option_name IN ('siteurl', 'home')" +sudo -u www-data /usr/bin/wp-cli core install --url="http://$WC_HOST/" --title="${WC_SITENAME}" --admin_user=opentools --admin_password=opentools --admin_email="demo@demo.open-tools.net" +sudo -u www-data /usr/bin/wp-cli db query --allow-root "UPDATE wp_options SET option_value='http://${WC_HOST}' WHERE option_name IN ('siteurl', 'home')" for p in debug-bar debug-bar-actions-and-filters-addon debug-bar-hook-log; do sudo -u www-data /usr/bin/wp-cli plugin install $p --activate @@ -34,7 +34,7 @@ sudo -u www-data /usr/bin/wp-cli plugin activate woocommerce-shipping-by-rules/w # Before we can setup the menu, we need to run through the WC setup wizzard! echo "Please run the WooCommerce Setup Wizzard at:" -echo " http://wc-${WC_HOST}.dev/wp-admin/admin.php?page=wc-setup" +echo " http://${WC_HOST}/wp-admin/admin.php?page=wc-setup" echo "" echo "Press [Enter] when you have finished..." read var_name @@ -44,10 +44,15 @@ read var_name sudo -u www-data /usr/bin/wp-cli menu create "Main Menu" sudo -u www-data /usr/bin/wp-cli menu location assign main-menu primary for page in shop cart checkout my-account; do - id=$(wp-cli post list --post_type=page --name="$page" --field=ID --allow-root) + id=$(sudo -u www-data /usr/bin/wp-cli post list --post_type=page --name="$page" --field=ID ) sudo -u www-data /usr/bin/wp-cli menu item add-post main-menu $id done +# Set the shop as homepage +id=$(sudo -u www-data /usr/bin/wp-cli post list --post_type=page --name="Shop" --field=ID --allow-root) +sudo -u www-data /usr/bin/wp-cli option update show_on_front page +sudo -u www-data /usr/bin/wp-cli option update page_on_front $id + # Setup WooCommerce Products -sudo -u www-data /usr/bin/wp-cli wc product create --title="Test Product" --sku="test-sku" --regular_price=15 --status="publish" +sudo -u www-data /usr/bin/wp-cli wc product create --name="Test Product" --sku="test-sku" --regular_price=15 --status="publish" --user=opentools diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 0000000000000000000000000000000000000000..d5d19a313ccd350bf7ed729de8ae6a1e0a1de4bc --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,10 @@ +[supervisord] +nodaemon=true + +[program:apache] +command=/usr/local/bin/apache2-foreground +autorestart=true + +[include] +files = /etc/supervisor/conf.d/*.conf + diff --git a/wc-docker-create.sh b/wc-docker-create.sh index 4dd8c1e581a27004cfaaf600f807ee17f623a69a..266ea0fb9aa75dae8a8e7a4e03be5457ae25c27a 100755 --- a/wc-docker-create.sh +++ b/wc-docker-create.sh @@ -1,5 +1,6 @@ #!/bin/bash +REPO=registry.open-tools.net/opentools/docker-woocommerce if [ $# -lt 3 ]; then echo "Usage: wc-docker-create.sh NAME PORT SITE_NAME" exit @@ -12,11 +13,12 @@ SCRIPTDIR="$(dirname "$0")" # docker run -p $PORT:80 -d --name wc-$NAME -v /home/reinhold/OpenTools/Software/WooCommerce/AdvancedOrdernumbers:/var/www/html/wp-content/plugins/woocommerce-advanced-ordernumbers -v /home/reinhold/OpenTools/Software/WooCommerce/ShippingByRules:/var/www/html/wp-content/plugins/woocommerce-shipping-by-rules --link mysql-dev:mysql -e WORDPRESS_DB_NAME=wc_$NAME agrothberg/docker-woocommerce:latest -docker run -p $PORT:80 -d --name wc-$NAME -v /home/reinhold/OpenTools/Software/WooCommerce/AdvancedOrdernumbers:/var/www/html/wp-content/plugins/woocommerce-advanced-ordernumbers -v /home/reinhold/OpenTools/Software/WooCommerce/ShippingByRules:/var/www/html/wp-content/plugins/woocommerce-shipping-by-rules --link mysql-dev:mysql -e WORDPRESS_DB_NAME=wc_$NAME opentools/woocommerce:latest +# docker run -p $PORT:80 -d --name wc-$NAME -v /home/reinhold/OpenTools/Software/WooCommerce/AdvancedOrdernumbers:/var/www/html/wp-content/plugins/woocommerce-advanced-ordernumbers -v /home/reinhold/OpenTools/Software/WooCommerce/ShippingByRules:/var/www/html/wp-content/plugins/woocommerce-shipping-by-rules --link mysql-dev:mysql -e WORDPRESS_DB_NAME=wc_$NAME $REPO +docker run -p $PORT:80 -d --name wc-$NAME -v /home/reinhold/OpenTools/Software/WooCommerce/AdvancedOrdernumbers:/var/www/html/wp-content/plugins/woocommerce-advanced-ordernumbers -v /home/reinhold/OpenTools/Software/WooCommerce/ShippingByRules:/var/www/html/wp-content/plugins/woocommerce-shipping-by-rules -e WORDPRESS_DB_NAME=wc_$NAME $REPO sudo $SCRIPTDIR/add-docker-vhost.sh wc-$NAME $PORT echo "Waiting for Docker to set up the database etc. Otherwise the wp-cli setup scripts cannot access the DB and will fail!" -sleep 15 +sleep 5 -docker exec -ti wc-$NAME /install-wc.sh "$NAME" "$SITE" +docker exec -ti wc-$NAME /install-wc.sh "wc-${NAME}.test" "$SITE"