Create local WordPress sites with Docker, the easy way.
The purpose of this library is for easy creation and management of local WordPress development environments with Docker. Under the hood, this library uses visiblevc
's excellent Docker images as the base and adds CLI options via a nodejs
script to make environment management even easier.
With most other tools, the user must manually create and manage docker-compose.yml
files. This method has several drawbacks though. docker-compose
files are not tailored to WordPress specifically and require at least basic knowledge of Docker. Docker is a fantastic tool but can eat up a lot of development time. Another big problem for development, in particular, is that docker-compose
files are intended to be mostly unchanged. Their rigidity is not well suited for development environments. In terms of WordPress, this could be mounting/unmounting plugin/theme folders, changing the PHP version, importing SQL dump files, pulling third-party non-free plugins/themes from an SSH server, etc.
Instead, this tool uses JSON
files structured specifically for managing WordPress environments. With this approach, you can easily manage environments without any prior knowledge of Docker.
This library is only for managing development environments and is not intended for creating production ready containers.
- Mount local plugin/theme folders from anywhere on your system
- Download and install plugins/themes automatically on start-up
- Download and install private plugins/themes via SSH/FTP automatically on start-up
- XDebug built-in for easy debugging
- Local SMTP mail server with MailHog
ngrok
support for easy SSL testing on localhost- Take a snapshot of your environment and re-use for significantly reduced start-up time
- Configurable WordPress version
- Configurable PHP version (
7.2
,7.3
,7.4
, or8.0
) - Configurable PHP environment variables
- Import a database on environment start-up (with URL replacement)
- Import and replace the database of a running environment (with URL replacement)
- Export an environments database
- A single
phpMyAdmin
container for all of your environments - Use proxy URL for media files
- Mount local
uploads
folder
- Requirements
- Installation
- Quickstart Guide
- Examples
- CLI Usage
- Environments
- MailHog
- PHP Debugging
- JSON Structure
- FTP/SSH Config Files
- node・npm
- docker
Install globally with npm
.
$ npm -g install @aivec/wp-docker-dev-factory
To spin-up a minimal environment, create a file named wp-instances.json
with the following contents:
{
"instanceName": "my-local-wordpress",
"containerPort": 8000,
"locale": "en_US",
"downloadPlugins": ["wordpress-plugin-1", "wordpress-plugin-2"],
"downloadThemes": ["wordpress-theme-1", "wordpress-theme-2"],
"localPlugins": [
"/absolute/path/to/plugin/directory",
"relative/path/to/plugin/directory",
"../relative/path/to/plugin/directory"
],
"localThemes": [
"/absolute/path/to/theme/directory",
"relative/path/to/theme/directory",
"../relative/path/to/theme/directory"
]
}
Where:
instanceName
is the environment name and title of your website.containerPort
is the port number the environment will expose. In this case the final URL will belocalhost:8000
.locale
is the language you want for the WordPress install.downloadPlugins
is a list of any number of publicly available WordPress plugins to be downloaded.downloadThemes
is a list of any number of publicly available WordPress themes to be downloaded.localPlugins
is a list of absolute or relative paths to any number of local plugin folders.localThemes
is a list of absolute or relative paths to any number of local theme folders.
After setting up your config file, invoke the CLI tool from within the folder where your wp-instances.json
file is saved:
$ aivec-wpdocker
A select prompt will appear:
Press the enter key on Start WordPress
and wait for the environment to be created (if this is your first time it might take a while). After the environment is created, open your browser and navigate to localhost:8000/wp-admin.
You should see the WordPress login screen. Login with the default username and password root
.
That's it!
A full example config can be found here. For a detailed description of every setting, refer to the JSON Structure section.
The CLI is completely interactive. There are two ways to use it:
- With no arguments
- With a relative/absolute path
If you invoke aivec-wpdocker
with no arguments, it will look for a wp-instances.json
file in the current directory.
Alternatively, you can pass a relative or absolute path as an argument to tell the CLI where it should look for a wp-instances.json
file. For example, assuming you have a wp-instances.json
file in a folder called configs
relative to the current directory, you would invoke the CLI like so:
$ aivec-wpdocker configs
The CLI has seven different operations:
Operation | Description |
---|---|
Start WordPress |
This will start the WordPress container, as well as create and run the MySQL and phpMyAdmin containers if they are not already created and running. If the environment's WordPress container is already running the CLI will abort with an error. Note that exiting with Ctrl+c will only stop the log stream, not the containers |
Stop WordPress |
This will stop the WordPress container for the selected environment. It will not stop the MySQL and phpMyAdmin containers. |
Save snapshot |
This will take a snapshot of the WordPress container's filesystem and save it as a .tar file. You can reference snapshot files with the image key in wp-instances.json to significantly reduce start-up time. |
Show server logs |
By default, when you start a WordPress container with Start WordPress , it will stream the Apache logs to standard output. You can use this command to pipe the log stream to your console again if you have exited the stream. |
Launch NGROK (local SSL) |
This will start the ngrok client for local SSL. Ctrl+c to stop the client. If you use ngrok , we highly recommend creating a free account on ngrok.com so that you get more connections per minute. |
Update dumpfile |
This will only work if you specified mysqlDumpfile in your config. By invoking this command, the dumpfile, which is mounted as a volume in the container, will be overwritten with a dump of the database of the selected environment |
Create new dumpfile |
This will create a dumpfile from the database of the selected environment and prompt the user to name the dumpfile. The dumpfile will be placed in a folder called dumpfiles in the same folder as wp-instances.json . If a dumpfiles folder does not already exist, it will be created. |
Import database |
This will prompt you to choose from a list of dump files in the dumpfiles directory adjacent to wp-instances.json . The selected dump file will then be used to replace the current database of the selected environment |
Config files can contain any number of environments. To do so, wrap your config objects in an array:
[
{
"instanceName": "my-local-wordpress-1",
"containerPort": 8000,
"locale": "en_US",
},
{
"instanceName": "my-local-wordpress-2",
"containerPort": 8010,
"locale": "en_US",
},
]
The CLI will then prompt you to choose which environment to use:
Every environment has exactly one WordPress
container associated with it. Conversely, there is only one MySQL
and phpMyAdmin
container used for the databases of all WordPress
environments. The naming pattern for containers is as follows:
Container | Name | Example |
---|---|---|
MySQL |
aivec_wp_mysql | |
phpMyAdmin |
aivec_wp_pma | |
WordPress |
instanceName | test-wordpress |
You can access phpMyAdmin
at localhost:22222 with the following login information:
- Username:
root
- Password:
root
For WordPress
environments that do not specify a mysqlDumpfile, the login information is the same:
- Username:
root
- Password:
root
The database for each WordPress environment will only be created the first time that environment is started, regardless of whether you set a mysqlDumpfile or not. If you want the database to be re-created every time you start WordPress, set flushOnRestart to true
.
Emails sent via WordPress' built-in wp_mail
function are caught by MailHog. All outgoing email can be viewed in a web UI at localhost:8025
Any environment you create will have XDebug
installed and configured by default listening on port 9900
. Visual Studio Code users can debug with the PHP Debug extension. Create a launch.json
file and place it either in the .vscode
directory of a workspace folder for a plugin/theme, or the .vscode
directory of a workspace folder specifically for managing PHP debugging.
For users who have many plugins and themes scattered across their filesystem, we recommend creating a workspace folder for managing path mappings of all of those environments with a launch.json
file like the following:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9900,
"pathMappings": {
"/var/www/html/wp-content/plugins/my-plugin": "/home/user/path/to/my-plugin",
"/var/www/html/wp-content/themes/my-theme": "/home/user/path/to/my-theme"
}
}
]
}
For users who would rather have a separate launch.json
file for each of their plugin/theme workspaces, the file would look something like this:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9900,
"pathMappings": {
"/var/www/html/wp-content/plugins/my-plugin": "{workspaceRoot}"
}
}
]
}
Some users prefer to keep all of their plugins and themes in a local WordPress installation folder. For those users, only one launch.json
file is required:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9900,
"pathMappings": {
"/var/www/html/wp-content": "/absolute/path/to/my/local/wordpress/wp-content"
}
}
]
}
Reference for the wp-instances.json
config file.
- Required
- Type:
String
- Description: The
instanceName
becomes the title of your website. Note that even if you import a database with an SQL dumpfile that contains a WordPress install with a different title,instanceName
will override it.
- Required
- Type:
Number
- Description: This is the port number for the WordPress installation. The final URL is
localhost
with this port number appended. AcontainerPort
of 8000 would result inlocalhost:8000
.
- Optional
- Type:
String
- Default:
7.3
- Description: This is the PHP version Apache will use. Possible values are
7.2
,7.3
, and7.4
.
- Optional
- Type:
String
- Default:
latest
- Description: Specify the WordPress version to install. Accepts any valid semver number,
latest
, ornightly
for beta builds. Note thatnightly
builds only support theen_US
locale. If you set this tonightly
and the locale is noten_US
,en_US
will be used anyways.
- Optional
- Type:
String
- Default:
en_US
- Description: This is the locale used by WordPress to determine which language to use.
- Optional
- Type:
String[]
- Description: May be any number of absolute or relative paths to
sh
orbash
scripts to be executed at the end of environment creation. Note that absolute paths are resolved starting from your home directory and relative paths are resolved starting from the folder of thewp-instances.json
config file
- Optional
- Type:
String
- Description: Absolute or relative path to a
.tar
snapshot file created with theSave snapshot
command. Note that absolute paths are resolved starting from your home directory and relative paths are resolved starting from the folder of thewp-instances.json
config file
- Optional
- Type:
String
- Description: Absolute or relative path to an
uploads
folder. Note that absolute paths are resolved starting from your home directory and relative paths are resolved starting from the folder of thewp-instances.json
config file
- Optional
- Type:
String
- Description: Specify a base URL for the
uploads
folder. If specified, any time a WordPress core function such aswp_get_attachment_url
is called and the file doesn't exist locally, it will be fetched from the URL. Note that the URL should point to theABSPATH
of the WordPress install (eg:https://www.my-site.com/cms
for a site whereuploads
exists atcms/wp-content/uploads
).
- Optional
- Type:
Object
- Optional
- Type:
String
- Description: A relative or absolute path to a
MySQL
dump file with the extension.sql
. Note that absolute paths are resolved starting from your home directory and relative paths are resolved starting from the folder of thewp-instances.json
config file
- Optional
- Type:
Boolean
- Default:
false
- Description: If
true
, the database will be re-created every time the WordPress container is stopped and started again.
- Optional
- Type:
String
- Description: By default, if you do not specify a
mysqlDumpfile
then the database name will become theinstanceName
. If you do specify amysqlDumpfile
and the database name therein is different than theinstanceName
, you must define this property with the database name defined in the dump file.
- Optional
- Type:
String
- Default:
wp_
- Description: This is the prefix for table names. Again, if
mysqlDumpfile
is specified but the table prefix therein differs from the default, you must define this property.
{
"database": {
"mysqlDumpfile": "dumpfiles/testdatabase.sql",
"flushOnRestart": true,
"dbName": "dbname",
"dbPrefix": "dbprefix_"
}
}
- Optional
- Type:
Object
- Description: May be any number of arbitrary key-value pairs to be set as PHP environment variables at start-up. The environment variables can then be accessed in PHP via the PHP environmment global
$_ENV
- Optional
- Type:
String[]
- Description: May be any number of plugins that you want to be installed during environment creation. The following forms are accepted:
plugin-slug
: Used when installing a plugin direct from WordPress.org.[plugin-slug]http://pluginsite.com/plugin.zip
: Used when installing plugin from URL.
- Optional
- Type:
String[]
- Description: May be any number of themes that you want to be installed during environment creation. The following forms are accepted:
theme-slug
: Used when installing a theme direct from WordPress.org.[theme-slug]http://themesite.com/theme.zip
: Used when installing theme from URL.
- Optional
- Type:
String[]
- Description: May be any number of relative or absolute paths pointing to local plugins that you want mapped into the container. Note that absolute paths are resolved starting from your home directory and relative paths are resolved starting from the folder of the
wp-instances.json
config file
- Optional
- Type:
String[]
- Description: May be any number of relative or absolute paths pointing to local themes that you want mapped into the container. Note that absolute paths are resolved starting from your home directory and relative paths are resolved starting from the folder of the
wp-instances.json
config file
- Optional
- Type:
Object[]
- Description:
ftp
may contain an array of any number offtp
config objects
- Optional*
- Type:
String
- Description: Can refer to either a file of the same name in a folder called
aivec-devenv-configs
which exists in your home folder, or the name of one of the properties specified in a file calledftp.json
which exists in theaivec-devenv-configs
folder. If you do not have anaivec-devenv-configs
folder, create one in your home directory. For more information about FTP config files, refer to the FTP Config Files section. - * Required if
confpath
is not set
- Optional*
- Type:
String
- Description: Can be either a relative or absolute path pointing to a
.json
file containing login information. If bothconfname
andconfpath
are set,confpath
will take precedence. For information about FTP config files, refer to the FTP Config Files section. - * Required if
confname
is not set
- Optional
- Type:
String[]
- Description: Can be any number of relative paths to plugin
.zip
files that exist on the FTP server. Paths are resolved relative to the directory that is opened upon access via FTP. Do not include the extension.zip
as part of the file name.
- Optional
- Type:
String[]
- Description: Can be any number of relative paths to theme
.zip
files that exist on the FTP server. Paths are resolved relative to the directory that is opened upon access via FTP. Do not include the extension.zip
as part of the file name.
{
"ftp": [
{
"confname": "my-ftp-config",
"plugins": ["relative/path/to/plugin/zipfile/noextension"],
"themes": ["relative/path/to/theme/zipfile/noextension"]
},
{
"confpath": "path/to/ftp-config.json",
"plugins": ["relative/path/to/plugin/zipfile/noextension"],
"themes": ["relative/path/to/theme/zipfile/noextension"]
}
]
}
- Optional
- Type:
Object[]
- Description:
ssh
may contain an array of any number ofssh
config objects
- Optional*
- Type:
String
- Description: Can refer to either a file of the same name in a folder called
aivec-devenv-configs
which exists in your home folder, or the name of one of the properties specified in a file calledssh.json
which exists in theaivec-devenv-configs
folder. If you do not have anaivec-devenv-configs
folder, create one in your home directory. For more information about SSH config files, refer to the SSH Config Files section. - * Required if
confpath
is not set
- Optional*
- Type:
String
- Description: Can be either a relative or absolute path pointing to a
.json
file containing login information. If bothconfname
andconfpath
are set,confpath
will take precedence. For information about SSH config files, refer to the SSH Config Files section. - * Required if
confname
is not set
- Optional
- Type:
String[]
- Description: Can be any number of relative paths to plugin
.zip
files that exist on the SSH server. Paths are resolved relative to the directory that is opened upon access via SSH. Do not include the extension.zip
as part of the file name.
- Optional
- Type:
String[]
- Description: Can be any number of relative paths to theme
.zip
files that exist on the SSH server. Paths are resolved relative to the directory that is opened upon access via SSH. Do not include the extension.zip
as part of the file name.
{
"ssh": [
{
"confname": "my-ssh-config",
"plugins": ["relative/path/to/plugin/zipfile/noextension"],
"themes": ["relative/path/to/theme/zipfile/noextension"]
},
{
"confpath": "path/to/ssh-config.json",
"plugins": ["relative/path/to/plugin/zipfile/noextension"],
"themes": ["relative/path/to/theme/zipfile/noextension"]
}
]
}
For security reasons, FTP and SSH login information is not part of the wp-instances.json
schema. Instead, the SSH and FTP properties in wp-instances.json
contain a reference to their respective config files that exist elsewhere. This makes it easier and safer to share wp-instances.json
config files between colleagues and teammates.
If confname
is used for your FTP config and a file named <confname>.json
exists in the aivec-devenv-configs
folder in your home directory, the file must have the following JSON
structure:
{
"host": "some-host.com",
"user": "ftpuser",
"password": "somepassword"
}
If confpath
is used for your FTP config then the JSON
structure of the file must be the same as above.
Alternatively, if confname
is used for your FTP config and a file named <confname>.json
does not exist in the aivec-devenv-configs
folder in your home directory, the CLI will look for a key in aivec-devenv-configs/ftp.json
with the same name as confname
. For example, given that confname
is my-ftp-conf
, the ftp.json
would look like this:
{
"my-ftp-conf": {
"host": "some-host.com",
"user": "ftpuser",
"password": "somepassword"
}
}
This method allows you to have any number of unique configurations all in the same file.
The same rules used for FTP config resolution also apply to SSH configs. SSH configs must have the following JSON
structure:
{
"host": "my-server.com",
"user": "ssh-user",
"privateKeyPath": "relativepath/sshkeys/my_key"
}
privateKeyPath
can be either a relative or absolute path. Relative paths are resolved starting from the same folder as the ssh config file, while absolute paths are resolved starting from the users home directory.
Additionally, the private key must not be password protected. There are tools out there like sshpass
for automating password input for password protected SSH keys, but in our experience this is not very reliable and not worth the effort. Our recommendation is to generate a passwordless SSH key pair where only non-interactive downloads are allowed.