Skip to content

Instantly share code, notes, and snippets.

@evildmp
Created November 2, 2020 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evildmp/8a94c39d58fc248757dc0cd909daa258 to your computer and use it in GitHub Desktop.
Save evildmp/8a94c39d58fc248757dc0cd909daa258 to your computer and use it in GitHub Desktop.
.. meta::
:description:
This guide explains step-by-step how to deploy a WordPress project with Docker, in accordance with
Twelve-factor principles.
:keywords: Docker, PHP, WordPress, MySQL, S3
.. _php-wordpress-create-deploy:
How to migrate (or create) and deploy a WordPress project
===========================================================================================
This guide will take you through the steps to deploy a portable, vendor-neutral WordPress project, either by building it
from scratch or migrating an existing application, using Docker. The project architecture is in line
with `Twelve-factor <https://www.12factor.net/config>`_ design principles.
This guide assumes that you are familiar with the basics of the Divio platform and have Docker and the :ref:`Divio CLI
<local-cli>` installed.
Edit (or create) the project files
-----------------------------------
Start in an existing WordPress project (i.e. containing ``wp-content``, ``wp-admin`` etc ), or if necessary, create a
new directory.
The ``Dockerfile``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a file named ``Dockerfile``, adding:
.. code-block:: Dockerfile
FROM wordpress:5.5.1
COPY . /var/www/html
You may need to change the version of WordPress to suit your project.
Local container orchestration with ``docker-compose.yml``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a ``docker-compose.yml`` file, :ref:`for local development purposes <docker-compose-local>`. This will replicate
the ``web`` image used in cloud deployments, allowing you to run the application in an environment as close to that of
the cloud servers as possible. Amongst other things, it will allow the project to use a MySQL database
running in a local container, and provides convenient access to files inside the containerised application.
.. code-block:: yaml
version: "2.4"
services:
web:
# the application's web service (container) will use an image based on our Dockerfile
build: "."
# map the internal port 80 to port 8000 on the host
ports:
- "8000:80"
links:
- "database_default"
env_file: .env-local
volumes:
- "./:/var/www/html:rw"
database_default:
# Select one of the following db configurations for the database
image: mysql:5.7
environment:
MYSQL_DATABASE: "db"
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
SERVICE_MANAGER: "fsm-mysql"
volumes:
- ".:/app:rw"
healthcheck:
test: "/usr/bin/mysql --user=root -h 127.0.0.1 --execute \"SHOW DATABASES;\""
interval: 2s
timeout: 20s
retries: 10
Local configuration using ``.env-local``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As you will see above, the ``web`` service refers to an ``env_file`` containing the environment variables that will be
used in the local development environment. Create a ``.env-local`` file:
.. code-block:: text
DATABASE_URL=mysql://root@database_default:3306/db
Check the local site
~~~~~~~~~~~~~~~~~~~~
First, build the Docker application:
.. code-block:: bash
docker-compose build
Then launch it:
.. code-block:: bash
docker-compose up
Install WordPress (new projects only)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``docker-compose up`` will execute ``/usr/local/bin/docker-entrypoint.sh`` inside the container. If this is a new
project, it will install WordPress by copying WordPress files from ``/usr/src/wordpress/`` to ``/var/www/html`` if they
are not already present.
``/var/www/html`` is mapped to the project directory by ``docker-compose.yml``, and the files will appear there.
A new project requires a ``wp-config.php`` - copy ``wp-config-sample.php`` to ``wp-config.php``.
Configure ``wp-config.php``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
A WordPress project's ``wp-config.php`` contains hard-coded database credentials by default. This needs to be modified
to obtain its configuration from the ``DATABASE_URL`` environment variable. Edit the "MySQL settings" section of the
file, changing the relevant section to:
.. code-block:: bash
/** get the DATABASE_URL from the environment */
$db = parse_url(getenv("DATABASE_URL"));
define('DB_NAME', trim($db["path"],"/"));
/** MySQL database username */
define('DB_USER', $db["user"]);
/** MySQL database password */
define('DB_PASSWORD', $db["pass"]);
/** MySQL hostname */
define('DB_HOST', $db["host"]);
Check the local site
~~~~~~~~~~~~~~~~~~~~
You can now open WordPress at http://127.0.0.1:8000/.
Install the ``wp-s3-smart-upload`` plugin to handle S3 storage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Open http://127.0.0.1:8000/wp-admin/plugin-install.php, and search for the *WordPress Amazon S3 – Wasabi Smart File
Uploads Plugin*; install and activate it.
This will download the plugin and copy it to ``wp-content/plugins`` in the application.
.. admonition:: not currently configured
This is yet to be configured from env vars so won't actually work.
Deployment and further development
-----------------------------------------
Create a new project on Divio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In the `Divio Control Panel <https://control.divio.com>`_ add a new project, selecting the *Build your own* option.
Add database and media services
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The new project does not include any :ref:`additional services <services>`; they must be added manually using the Divio
Control Panel if required. Use the *Services* menu to add a Postgres or MySQL database to match your choice earlier,
and an S3 object storage instance for media.
Connect the local project to the cloud project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Your Divio project has a *slug*, based on the name you gave it when you created it. Run ``divio project list -g`` to
get your project's slug; you can also read the slug from the Control Panel.
Run:
.. code-block:: bash
divio project configure
and provide the slug. (This creates a new file in the project at ``.divio/config.json``.)
If you have done this correctly, ``divio project dashboard`` will open the project in the Control Panel.
Configure the Git repository
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Initialise the project as a Git repository if it's not Git-enabled already:
.. code-block:: bash
git init .
A ``.gitignore`` file is needed to exclude unwanted files from the repository. Add:
.. code-block:: text
# Divio
.divio
/data.tar.gz
/data
# OS-specific patterns - add your own here
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Add the project's Git repository as a remote, using the *slug* value in the remote address:
.. code-block:: bash
git remote add origin git@git.divio.com:<slug>.git
(Use e.g. ``divio`` instead if you already have a remote named ``origin``.)
Commit your work
~~~~~~~~~~~~~~~~
.. code-block:: bash
git add . # add all the newly-created files
git commit -m "Created new project" # commit
git push --set-upstream --force origin [or divio] master # push, overwriting any unneeded commits made by the Control Panel at creation time
You'll now see "1 undeployed commit" listed for the project in the Control Panel.
Deploy the Test server
~~~~~~~~~~~~~~~~~~~~~~
Deploy with:
.. code-block:: bash
divio project deploy
(or use the **Deploy** button in the Control Panel).
Once deployed, your project will be accessible via the Test server URL shown in the Control Panel.
Perform initial operations on the cloud database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. admonition:: not currently working
Your cloud project does not yet have any content in the database, so you can't log in or do any other work there.
You can push the local database with the superuser you created to the Test environment:
.. code-block:: bash
divio project push db
or, :ref:`SSH to a cloud container <divio-project-ssh>` in the Test environment with ``divio project ssh`` and execute
Django migrations and create a superuser there in the usual way.
You can run migrations automatically on deployment by adding a :ref:`release command <release-commands>` in the Control
Panel.
Notes on working with the project
---------------------------------
.. admonition:: the Twelve-factor model
By default, WordPress is configured in ways that can make adopting the Twelve-factor model difficult. For example,
installation of new code is typically handled by WordPress itself, by copying it to a web server directory.
Configuration
~~~~~~~~~~~~~
The configuration described here tries to adopt Twelve-factor model as closely as possible, placing all configuration
in environment variables, so that the project can readily be moved to another host or platform, or set up locally for
development. The configuration for:
* security # to be done
* database
* media # to be done
* static files # to be done
is handled by a few simple code snippets in ``wp-config.php``. In each case, the settings will fall back to
safe and secure defaults.
Configuration for any other components should be handled in the same way:
* edit ``wp-config.php`` so that the configuration can be obtained from environment variables
* if required, add environment variables to the cloud environments with the appropriate values
* add environment variables to ``.env-local`` for the development environment
Installing and deploying new code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment