Docker Compose for LEMP stack and several separate Wordpress sites

I am starting to explore Docker through Docker for Mac using Docker Compose, with the intention of using it as a development environment for WordPress sites to be hosted on a Digital Ocean droplet.

On my regular DO droplet, I have nginx running with php-fpm and mysql, along with separate WordPress installs for each domain in /var/www/html. I’m trying to follow this approach in DC, but I’m not quite sure how to get there. None of the tutorials I’ve read explain how to have separate containers for each WordPress install, and separate containers each for nginx, php, mysql/mariadb, all supporting all of the WP sites. These are very low traffic sites.

Can someone suggest an approach to this with Docker Compose? Also, will this same approach for Docker for Mac and Docker Compose transfer to a DO droplet relatively seamlessly?

My thanks in advance.


Here is something similar to to a site I did with docker compose, running on a single host machine. In this arrangement each Wordpress site is in a separate container. I used haproxy to direct the requests to the appropriate container.

Here is an example docker compose file:

version: '2'

     image: mariadb
       - /container-volumes/db_data:/var/lib/mysql
     restart: always
       MYSQL_ROOT_PASSWORD: amazingrootpassword
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: amazinguserpassword

       - db
     image: wordpress
       - /container-volumes/sites/amazingwebsite_com/site_html:/var/www/html
       - /container-volumes/sites/amazingwebsite_com/apache_etc:/etc/apache2
     restart: always
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: amazinguserpassword
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_TABLE_PREFIX: wp_amazing_

       - db
     image: wordpress
       - /container-volumes/sites/moreamazingwebsite_com/site_html:/var/www/html
       - /container-volumes/sites/moreamazingwebsite_com/apache_etc:/etc/apache2
     restart: always
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: amazinguserpassword
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_TABLE_PREFIX: wp_moreamazing_

      - wordpress_site_amazingwebsite_com
      - wordpress_site_moreamazingwebsite_com
     image: haproxy
      - /container-volumes-config/haproxy_config:/usr/local/etc/haproxy:ro
     restart: always
      - 443:443
      - 80:80

Here is an example haproxy config file:

 option  dontlognull
 option  abortonclose
 maxconn 1000
 contimeout      300000
 clitimeout      300000
 srvtimeout      300000
 option http-server-close
 #option forwarder

frontend ft_secure_sites_passthrough
 bind *:443
 mode tcp

 acl ssl_site_amazingsite_com           req.ssl_sni -i
 acl ssl_site_amazingsite_com_www       req.ssl_sni -i

 acl ssl_site_moreamazingsite_com       req.ssl_sni -i
 acl ssl_site_moreamazingsite_com_www   req.ssl_sni -i

 tcp-request inspect-delay 2s
 tcp-request content reject if !ssl_site_amazingsite_com !ssl_site_moreamazingsite_com !ssl_site_amazingsite_com_www !ssl_site_moreamazingsite_com_www

 use_backend bk_ssl_site_amazingsite_com     if ssl_site_amazingsite_com
 use_backend bk_ssl_site_amazingsite_com     if ssl_site_amazingsite_com_www

 use_backend bk_ssl_site_moreamazingsite_com if ssl_site_moreamazingsite_com
 use_backend bk_ssl_site_moreamazingsite_com if ssl_site_moreamazingsite_com_www

backend bk_ssl_site_amazingsite_com
 mode tcp
 server bk_ssl_site_amazingsite_com_01  wordpress_site_amazingsite_com:443 check sni req.ssl_sni

backend bk_ssl_site_moreamazingsite_com
 mode tcp
 server bk_ssl_site_moreamazingsite_com_01  wordpress_site_moreamazingsite_com:443 check sni req.ssl_sni

frontend ft_http_sites
 bind *:80
 mode http
 redirect scheme https code 301 if !{ ssl_fc }

In this case, each Wordpress server is running SSL locally and haproxy passes the HTTPS (SSL) request to the server. It is also possible (if you trust the connection to the servers to be private) to use haproxy to make the HTTPS connection and pass it as a HTTP to the servers.

Thank you very much for your detailed reply, Tom. I’m marginally familiar with HAproxy and load balancing. It looks like you are using it as an alternative to nginx. A quick search says there are differing views on the two approaches. Any particular reason to choose one over the other?

I think I might be able to work with your example compose file and use it as a model for my setup, so I’ll play with it and see. At the very least you’ve reinforced my basic approach to separate each wp site in its own container, and drive the nginx web server, php and mysql db each in their own containers supporting all of the wp sites. Thanks for the input.


nginx is a popular alternative to haproxy, particularly if the load balancing (or in this case routing based on requested website) is done at the http layer, rather than the tcp layer. nginx, used in the role of a load balancer/proxy, can perform all sorts of useful features like serving static content.

Because, in this case, the proxy is not doing much at the http layer, haproxy is a leaner proxy to use. It, also, when I checked had less known vulnerabilities than nginx. However, both are excellent and both will facilitate routing and load balancing to multiple backend servers per domain.


I was trying your script, and am getting the following errors

apache2: Could not open configuration file /etc/apache2/apache2.conf: No such file or directory
[ALERT] 169/000855 (1) : Cannot open configuration file/directory /usr/local/etc/haproxy/haproxy.cfg : No such file or directory

I understand that its indicating that the files are not in those directory’s, but I have moved my haproxy.cfg into the /etc/haproxy directory and installed apache2 and verified that the files are there, but am still getting the errors.

I have also cleared all images, containers, restarted docker, will no luck.

I’m a missing something?