Docker – How to Fix Traefik WordPress Redirecting Issues

dockerWordpress

I have a Docker Swarm setup running Traefik 2.0. We have A LOT of wordpress sites running currently on multiple servers and we'd like to dockerize them. We have a Traefik instance running fine on Docker with a file provider to those physical servers as well as routing to the Docker WordPress instances. This part appears to be functioning fine.

We have things configured to go to https://myblog.example.com which is a wordpress instance in docker and everything works perfectly. However the boss wants it to go to https://example.com/myblog. I thought it would be pretty simple however it's becomming more and more challenging.

I configured it using the Host && PathPrefix rule in Traefik and it works as expected however when it gets to WordPress it redirects to wp-admin/install.php to install about 20+ times until it errors out due to too many redirects.

Everything that I was reading says it's the SSL passthrough causing these issues. I've attempted to do SSLProxyHeaders (Which you'll see remnants of it in the config below) I've found that Traefik 2.0 documentation compared to the older versions it quite lacking. I'd expect that since it recently came out.

After fighting with it for a few days I figured I'd rip out the http->https redirect and goto my site http only to test. It too gets the too many redirects. To me that says it's not an SSL issue however an issue with WordPress and/or traefik configuration. I'm leaning towards the traefik config since it works fine going to http(s)://myblog.example.com

docker-compose.yml:

version: '3'

services:
   db:
     image: mysql:5.7
     volumes:
       - /mnt/docker/data/wp-myblog/db/:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: XXXXXXXXXXXXXXXXXX
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
     networks:
       wordpress:

   wordpress:
     image: wordpress:latest
     restart: always
     volumes:
       - /mnt/docker/data/wp-myblog/wordpress:/var/www/html
     deploy:
       labels:
         - traefik.enable=true
         - traefik.http.routers.wp-myblog-https.rule=Host(`example.com`) && PathPrefix(`/myblog`)
         - traefik.http.routers.wp-myblog-http.rule=Host(`example.com`) && PathPrefix(`/myblog`)
         - traefik.http.routers.wp-myblog-http.entrypoints=http
         - traefik.http.routers.wp-myblog-https.entrypoints=https
         - traefik.http.routers.wp-myblog-https.middlewares=sslheaders@file
         - traefik.http.services.wp-myblog.loadbalancer.server.port=80
         - traefik.http.routers.wp-myblog-https.tls
         - traefik.docker.network=traefik_default
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
       WORDPRESS_CONFIG_EXTRA: |
        define('WP_SITEURL', 'http://example.com/myblog');
        define('WP_HOME','http://example.com/myblog');
     networks:
       traefik_default:
       wordpress:

networks:
  wordpress:
  traefik_default:
    external: true

wp-config.php:

wp-config.php:

<?php
/**
 * The base configuration for WordPress
 *
 * The wp-config.php creation script uses this file during the
 * installation. You don't have to use the web site, you can
 * copy this file to "wp-config.php" and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * MySQL settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * @link https://codex.wordpress.org/Editing_wp-config.php
 *
 * @package WordPress
 */

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress');

/** MySQL database username */
define( 'DB_USER', 'wordpress');

/** MySQL database password */
define( 'DB_PASSWORD', 'wordpress');

/** MySQL hostname */
define( 'DB_HOST', 'db:3306');

/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8');

/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '');

/**#@+
 * Authentication Unique Keys and Salts.
 *
 * Change these to different unique phrases!
 * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
 * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
define( 'AUTH_KEY',         'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define( 'SECURE_AUTH_KEY',  'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define( 'LOGGED_IN_KEY',    'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define( 'NONCE_KEY',        'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define( 'AUTH_SALT',        'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define( 'SECURE_AUTH_SALT', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define( 'LOGGED_IN_SALT',   'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define( 'NONCE_SALT',       'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');

/**#@-*/

/**
 * WordPress Database Table prefix.
 *
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
 */
$table_prefix = 'wp_';

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 *
 * For information on other constants that can be used for debugging,
 * visit the Codex.
 *
 * @link https://codex.wordpress.org/Debugging_in_WordPress
 */
define( 'WP_DEBUG', false );

// 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';
}

// WORDPRESS_CONFIG_EXTRA
define('WP_SITEURL', 'http://example.com/myblog');
define('WP_HOME','http://example.com/myblog');

/** That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
        define( 'ABSPATH', dirname( __FILE__ ) . '/' );
}

/** Sets up WordPress vars and included files. */
require_once( ABSPATH . 'wp-settings.php' );

Best Answer

Create a directory in ./wordpress/wp-content called blog and move all your data in there. Then make your docker compose look like

version: '3.7'

networks:
  http_network:
    external: true
  wp:
    external: false

services:
  database:
    image: mariadb:latest
    command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci', '--default-authentication-plugin=mysql_native_password']
    volumes:
      - .docker/data/db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    networks:
      - wp

  wordpress:
    depends_on:
      - database
    image: wordpress:latest
    volumes:
      - ./wordpress/wp-content:/var/www/html/wp-content
    environment:
      WORDPRESS_DB_HOST: database:3306
      WORDPRESS_DB_USER: ${MYSQL_USER}
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
      WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
    labels:
      - traefik.enable=true
      - traefik.frontend.rule=Host:domain;PathPrefix:/blog
      - traefik.port=80
      - traefik.docker.network=http_network
    working_dir: /var/www/html/wp-content/blog
    networks:
      - wp
      - http_network

Now It has a weird quirk, when you first configure the wordpress site you'd have to go to https://domain/blog/blog to go through the installation process. When complete you should be able to go to https://domain/blog and access it fine. I was having the same issue where /blog/wp-admin would redirect removing the /blog and now I don't.

Related Topic