Configure HTTPS for Wordpress on Docker using NGINX as a reverse proxy

konkri

Konstantinos Kritikakis

Posted on July 24, 2024

Configure HTTPS for Wordpress on Docker using NGINX as a reverse proxy

If you want to host Wordpress in a Docker container but have trouble configuring HTTPS, the steps below might help you!

Composing the docker-compose.yml file

Let's create a docker-compose.yml file to define the services we are going to need.

First, we are going to add the db to the services.



db:
    image: mysql:5.7
    container_name: db
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: notanotheruser
      MYSQL_PASSWORD: 1234
      MYSQL_ROOT_PASSWORD: root1234
    volumes:
      - db_data:/var/lib/mysql


Enter fullscreen mode Exit fullscreen mode
  • We are exposing the port 3306 in case we want to connect to the database with MySQL Workbench to take a better look.
  • We are passing the environment variables needed to init the MySQL server as per documentation
  • We are creating a volume to keep the state of the MySQL server even after we shut down the service container.

After we have set up the db, we are going to add wordpress to the services.



wordpress:
    depends_on:
      - db
    image: wordpress:latest
    container_name: wordpress
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: notanotheruser
      WORDPRESS_DB_PASSWORD: 1234
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wordpress/wp-config.php:/var/www/html/wp-config.php


Enter fullscreen mode Exit fullscreen mode
  • We are adding the depends_on: db because we want the db service to be started prior to the wordpress service.
  • We are passing the environment variables needed to init Wordpress as per documentation
  • We need to overwrite the wp-config.php file in the wordpress installation with our own only to add one line that is going to allow us to use https, and that is: $_SERVER['HTTPS'] = 'on';

A wp-config.php file locally should look like this:



<?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 website, you can copy this file to "wp-config.php"
 * and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * Database settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * This has been slightly modified (to read environment variables) for use in Docker.
 *
 * @link https://developer.wordpress.org/advanced-administration/wordpress/wp-config/
 *
 * @package WordPress
 */

// IMPORTANT: this file needs to stay in-sync with https://github.com/WordPress/WordPress/blob/master/wp-config-sample.php
// (it gets parsed by the upstream wizard in https://github.com/WordPress/WordPress/blob/f27cb65e1ef25d11b535695a660e7282b98eb742/wp-admin/setup-config.php#L356-L392)

// a helper function to lookup "env_FILE", "env", then fallback
if (!function_exists('getenv_docker')) {
    // https://github.com/docker-library/wordpress/issues/588 (WP-CLI will load this file 2x)
    function getenv_docker($env, $default) {
        if ($fileEnv = getenv($env . '_FILE')) {
            return rtrim(file_get_contents($fileEnv), "\r\n");
        }
        else if (($val = getenv($env)) !== false) {
            return $val;
        }
        else {
            return $default;
        }
    }
}

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

/** Database username */
define( 'DB_USER', getenv_docker('WORDPRESS_DB_USER', 'example username') );

/** Database password */
define( 'DB_PASSWORD', getenv_docker('WORDPRESS_DB_PASSWORD', 'example password') );

/**
 * Docker image fallback values above are sourced from the official WordPress installation wizard:
 * https://github.com/WordPress/WordPress/blob/1356f6537220ffdc32b9dad2a6cdbe2d010b7a88/wp-admin/setup-config.php#L224-L238
 * (However, using "example username" and "example password" in your database is strongly discouraged.  Please use strong, random credentials!)
 */

/** Database hostname */
define( 'DB_HOST', getenv_docker('WORDPRESS_DB_HOST', 'mysql') );

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

/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', getenv_docker('WORDPRESS_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',         getenv_docker('WORDPRESS_AUTH_KEY',         'a04e06eaef05d9dc187680cdccb8aae37d90bfcd') );
define( 'SECURE_AUTH_KEY',  getenv_docker('WORDPRESS_SECURE_AUTH_KEY',  'f1d35321ba3ff820430674efc877f53b64bdb50e') );
define( 'LOGGED_IN_KEY',    getenv_docker('WORDPRESS_LOGGED_IN_KEY',    '5d880df893cba59fed67def1acac2c61e46c4671') );
define( 'NONCE_KEY',        getenv_docker('WORDPRESS_NONCE_KEY',        '2fe4fdf4ff93153db924369eb7bbd823f446577c') );
define( 'AUTH_SALT',        getenv_docker('WORDPRESS_AUTH_SALT',        '326143348bb31e5451cf0e838048043ea39e5351') );
define( 'SECURE_AUTH_SALT', getenv_docker('WORDPRESS_SECURE_AUTH_SALT', '33aa7ae0aa39497d0d13e84413061e0168eadea3') );
define( 'LOGGED_IN_SALT',   getenv_docker('WORDPRESS_LOGGED_IN_SALT',   'f032c820677ec84f4ef05a6d2e4c2547be1e7b1b') );
define( 'NONCE_SALT',       getenv_docker('WORDPRESS_NONCE_SALT',       '506e5adc0340e19f13b1018ecb7b7776e92b0a73') );
// (See also https://wordpress.stackexchange.com/a/152905/199287)

/**#@-*/

/**
 * 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 = getenv_docker('WORDPRESS_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 documentation.
 *
 * @link https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/
 */
define( 'WP_DEBUG', !!getenv_docker('WORDPRESS_DEBUG', '') );

/* Add any custom values between this line and the "stop editing" line. */

// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact
// see also https://wordpress.org/support/article/administration-over-ssl/#using-a-reverse-proxy
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
    $_SERVER['HTTPS'] = 'on';
}
// (we include this by default because reverse proxying is extremely common in container environments)

if ($configExtra = getenv_docker('WORDPRESS_CONFIG_EXTRA', '')) {
    eval($configExtra);
}

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

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

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

$_SERVER['HTTPS'] = 'on';


Enter fullscreen mode Exit fullscreen mode

Keep in mind that the Wordpress image by itself doesn't support HTTPS. Thus the need for a reverse proxy.

Finally we need to add webserver to the services.



webserver:
    depends_on:
      - wordpress
    image: nginx:latest
    container_name: webserver
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./nginx/certs:/etc/nginx/certs


Enter fullscreen mode Exit fullscreen mode
  • We are adding the depends_on: wordpress because we want the wordpress service to be started prior to the webserver service.
  • We are exposing both port 80 and 443.
  • We need to pass a nginx.conf file that allows for the reverse proxy to be possible as well as .crt and .key files for the SSL.

A nginx.conf file locally should look like this:



server {
    listen 80;
    location / {
        proxy_pass http://wordpress;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 443 ssl;

    ssl_certificate /etc/nginx/certs/nginx.crt;
    ssl_certificate_key /etc/nginx/certs/nginx.key;

    location / {
        proxy_pass http://wordpress;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}



Enter fullscreen mode Exit fullscreen mode

In order to serve HTTPS content, an SSL certificate is required.

For development purposes I used this online tool to generate my self-signed certificate (.crt and .key files). Feel free to use certbot or openssl

Finally, fingers crossed, we are ready to run docker-compose up!

docker-compose up

After the setup process, if you go to Settings you will see that the httpshas been added to the WordPress Address and the Site Address

https result

That's it!

I had trouble myself to setup https for wordpress so I thought once I figured it out I should share. Feel free to share any feedback! Thanks and have a great day!

Here is the GitHub repo with the code used.

that's all folks

💖 💪 🙅 🚩
konkri
Konstantinos Kritikakis

Posted on July 24, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related