Setup a Wordpress app using Dokku and any system (not just a 5$ droplet as the original used to say).
It is worth noting that this setup uses the wordpress convention of moving the core wordpress stuff to it's own directory so we can use it as a dependency.
You don't really need to tinker much with the file system but here's a little breakdown:
public
├─ uploads # wordpress uploads folder
├─ wordpress # wordpress core
├─ wp-content # for wordpress plugins and theme customizations
├─ index.php # slightly modified index.php from wordpress
└─ wp-config.php # modified wordpress configuration
vendor # contains composer dependencies
.gitignore # some very basic list of files to ignore
composer.json # recipe for our app
nginx.conf # see nginx.conf section below
Procfile # see Procfile section
README.md # you are here
If you install plugins or themes, those changes will not be permanent. They will be removed when you rebuild the app. While this may seem like a problem, it's actually a security feature. You can place any themes or plugins under public/wp-content/themes/
or public/wp-content/plugins/
and they'll be automatically added to your deployed application.
Say a plugin or theme gets compromised and some bad code gets embedded in one of its files, your whole site is compromised. You can just update the plugin in the repo, repush the repo and a new, clean, uncompromised website is running. Note: your database does not get affected, so make sure the bad code did not alter the database.
1. Create a droplet on digitalocean
ALTERNATIVELY: just make sure you have composer installed on your local machine and have dokku running on your deployment server/machine
- Choose an image - Dokku v0.4.12 on 14.04 (at the time of writing)
- Choose a size - $5/mo
- Choose a datacenter region - Region closest to your target audience
- Select additional options
- Private Networking - optional
- Backups - optional
- IPv6 - optional
- User Data - optional
- Add your SSH keys
- Finalize and Create
- How many droplets? - optional (1 will suffice)
- Choose a hostname - optional
Grab the installer here according to your system and install as per instructions on their website.
* The succeeding instructions assume that composer.phar
is executable globally. Mine resides in /usr/local/bin/composer
- Download the package at https://github.com/jubalm/do-dokku-wordpress/archive/master.zip and extract to your project folder.
- Fire up the terminal and navigate to your project folder
- Run the following command (remember I renamed my composer executable)
composer install
- Once completed, you will find a
composer.lock
file.
* This assumes git is installed on your system
git init
git add .
git commit -m 'init'
Of course, the commit message on -m
can be anything.
As dokku is pretty much similar to heroku, you can deploy your app by simply pushing a git commit to your dokku instance.
git remote add dokkuserv dokku@HOSTNAME:wordpress
git push dokkuserv master
Breakdown of the codes above
dokkuserv
is the remote repository aliasdokku
is the default username for the dokku instanceHOSTNAME
should be your digitalocean hostnamewordpress
will be the dokku app (container) that will be created
When the push completes, you'll see dokku does it's magic building your app. The log should look like
-----> Cleaning up...
-----> Building wordpress from herokuish...
-----> Adding BUILD_ENV to build environment...
-----> PHP app detected
-----> Bootstrapping...
-----> Installing system packages...
- php (7.0.2)
- Apache (2.4.16)
- Nginx (1.8.0)
-----> Enabling PHP extensions...
- ext-zend-opcache (automatic)
-----> Installing dependencies...
Composer version 1.0.0-alpha11 2015-11-14 16:21:07
Loading composer repositories with package information
Installing dependencies from lock file
- Installing johnpbloch/wordpress-core-installer (0.2.1)
Loading from cache
- Installing johnpbloch/wordpress (4.4.2)
Loading from cache
Generating optimized autoload files
-----> Preparing runtime environment...
-----> Checking for additional extensions to install...
-----> Discovering process types
Procfile declares types -> web
-----> Releasing wordpress (dokku/wordpress:latest)...
-----> Deploying wordpress (dokku/wordpress:latest)...
-----> DOKKU_SCALE file found
=====> web=1
-----> Running pre-flight checks
For more efficient zero downtime deployments, create a file CHECKS.
See http://progrium.viewdocs.io/dokku/checks-examples.md for examples
CHECKS file not found in container: Running simple container check...
-----> Waiting for 10 seconds ...
-----> Default container check successful!
=====> wordpress container output:
DOCUMENT_ROOT changed to 'public/'
Using Nginx server-level configuration include 'nginx.conf'
No dyno detected; using defaults for 1X...
4 processes at 128MB memory limit.
Starting php-fpm...
Starting nginx...
=====> end wordpress container output
-----> Running post-deploy
-----> Configuring wordpress.yourdomain.com...
-----> Creating http nginx.conf
-----> Running nginx-pre-reload
Reloading nginx
-----> Setting config vars
DOKKU_APP_RESTORE: 1
-----> Shutting down old containers in 60 seconds
=====> 8ec330943b5655041111128287281d3eb28467876580e34990b9a89abdba521b
=====> Application deployed:
http://wordpress.yourdomain.com
Fist we need to install the mariadb plugin on our dokku instance to create our database.
Login to your instance using ssh and run the following.
dokku plugin:install https://github.com/dokku/dokku-mariadb.git mariadb
dokku mariadb:create wpdb
Once done, let's link our database to our wordpress container
dokku mariadb:link wpdb wordpress
mariadb:link
is a dokku plugin command to link our databasewpdb
is the name of the database we just createdwordpress
simply provides the name of our app
Nows a good time to setup the wordpress domain name.
dokku domains:add wordpress wordpress.yourdomain.com
domains:add
is a dokku plugin that adds a domain name to our appwordpress
is the name of our appwordpress.yourdomain.com
is the domain name
Our wordpress container also needs an environment variable DOMAIN_NAME
to setup wordpress specific urls.
dokku config:set wordpress DOMAIN_NAME=wordpress.yourdomain.com
Now visit your blog from the domain name you provided and you will be redirected to the wordpress install page.
As configured it is impossible to make uploads, themes, plugins,... persistent. The easiest way to overcome this is to mount a local folder as a storage volume.
sudo mkdir -p /var/lib/dokku/data/storage/wordpress/public
sudo chown -R dokku:dokku /var/lib/dokku/data/storage/wordpress/
sudo chown -R 32767:32767 /var/lib/dokku/data/storage/wordpress/
dokku storage:mount wordpress /var/lib/dokku/data/storage/wordpress/public/uploads/:/app/public/wordpress/app/public/uploads/
/var/lib/dokku/data/storage/wordpress/
is an application specific folder for this application generated by dokku/var/lib/dokku/data/storage/wordpress/public
is a data folder inside of your app specific folderwordpress
is the name of our app/app/public/
is the the directory in your container where /opt/wordpress/data gets mounted
For this to work, you need to rebuild the app
dokku ps:rebuild wordpress
By default this the application is configured to allow 50MB posts. However, the default Nginx installation used by Dokku for routing, only supports 1MB uploads. This must be set by you.
sudo echo 'client_max_body_size 50M;' > /home/dokku/wordpress/nginx.conf.d/upload.conf
sudo chown -R dokku:dokku /home/dokku/wordpress/nginx.conf.d/upload.conf
sudo service nginx reload
wordpres
is the name of your dokku application50M
is the maximum upload size you want to allow for this application
In case you want to increase this size, you need to customize it in 3 places:
/home/dokku/wordpress/nginx.conf.d/upload.conf
as mentioned above- In the
nginx.conf
that's in this repositoryclient_max_body_size 50M;
- In
php.ini
, bothupload_max_filesize = 50M
andpost_max_size = 50M
When you changed the size in these 3 places, repush the repository to dokku:
git add nginx.conf php.ini && git commit -m 'change upload size' && git push dokkuserv master
By now there is no good excuse not to run letsencrypt on all your websites. There is a dokku plugin for letsencrypt, this repository is adapted to work without any problems with this plugin.
For installation of this plugin check dokku-letsencrypt on Github.
Afterwards, just run dokku letsencrypt wordpress
to make the site accessible over ssl where wordpress
is the name of your application.
Do note: You might need to add your email to the application using dokku config:set wordpress [email protected]
To auto update your certificate, use dokku letsencrypt:auto-renew wordpress
where wordpress
is the name of your application.
You can find valuable resouce on dokku's website on how these configurations work.
This basically sets up commands upon starting your app. You can find more information about this file here and setting up php here
web: vendor/bin/heroku-php-nginx -C nginx.conf public/
These mean:
vendor/bin/heroku-php-nginx
use nginx as our web server-C nginx.conf
add the contents ofnginx.conf
to the nginx configurationpublic/
serve the website from thepublic/
directory
These are very basic configuration for your nginx server. More info can be found here.
# Set index
index index.php;
# Global restrictions configuration file.
# Designed to be included in any server {} block.
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
# http://wiki.nginx.org/HttpCoreModule
location / {
try_files $uri $uri/ /index.php?$args;
}
# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}