Read on to find out how to make a highly available WordPress site, or group of WordPress sites, using Amazon Elastic Beanstalk, ECS (Elastic Container Service), RDS, and EFS!
Elastic Beanstalk: Create an application
To get started, you’ll need to create an application in Elastic Beanstalk. For this, I selected a multi-container Docker environment.
On the Elastic Beanstalk page, click Create New Application.
Then under Actions, choose Create New Environment > Multi-container Docker.
.ebextensions
Elastic Beanstalk makes use of the .ebextensions folder within your project to set certain settings or run commands on the instances when launched. This folder will be hidden if you’re using a Mac, so you may need to enable hidden files in the Finder.
For this project, I used ebextensions to set up the SFTP service, automatically add instances to a security group that can access the RDS and EFS servers, set up directories for and mount the EFS via NFS, copy config templates for nginx and set environment variables for connecting to RDS. Examples can be found in the GitHub related to this post.
Docker Images
dustysun/php-fpm-mysql-sendmail-wp
For this project, I created a Docker image based off of php:fpm with support for mysql, zend opcache and sendmail to support WordPress. It’s called dustysun/php-fpm-mysql-sendmail-wp and can be found on Docker Hub.
jwilder/nginx-proxy
This image is used with a custom nginx.tmpl to support having multiple WP installations in one Dockerfile.
jrcs/letsencrypt-nginx-proxy-companion
Automatically sets up Let’sEncrypt certificates for any sites liked in the LETSENCRYPT_HOST environment variable in thedustysun/php-fpm-mysql-sendmail-wp container.
atmoz/sftp:alpine
Allows you to access your web server files via SFTP. Allows you to specify users with a specific UID or GID so that you can map the user accounts to have the same permissions as the www-data user for the HTML files.
Not shown
You’ll need to create a file system in EFS and a database in RDS. You’ll also need to modify the security group permissions so the instances created by the following Dockerrun.aws.js file can access EFS and RDS.
Need Help? Questions? Comments?
I hope this has been a helpful post – please let me know if you’ve tried the same or need any help with the above!
Here’s my Dockerrun.aws.js file:
{ "AWSEBDockerrunVersion": 2, "containerDefinitions": [ { "dockerLabels": { "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy": "true" }, "essential": true, "memoryReservation": 128, "image": "jwilder/nginx-proxy", "mountPoints": [ { "containerPath": "/etc/nginx/conf.d", "sourceVolume": "Nginx-Proxy-Conf_D" }, { "containerPath": "/etc/nginx/vhost.d", "sourceVolume": "Nginx-Proxy-Vhost_D" }, { "containerPath": "/usr/share/nginx/html", "sourceVolume": "Nginx-Proxy-Html" }, { "containerPath": "/etc/nginx/certs", "sourceVolume": "Nginx-Proxy-Certs" }, { "containerPath": "/tmp/docker.sock", "sourceVolume": "VarRunDocker_Sock" }, { "containerPath": "/app/nginx.tmpl", "sourceVolume": "Nginx-Proxy-Nginx_Tmpl" }, { "containerPath": "/var/log/nginx", "sourceVolume": "Nginx-Logs" }, { "containerPath": "/etc/nginx/fastcgi.conf", "sourceVolume": "Nginx-Proxy-Fastcgi_Conf" }, { "sourceVolume": "efs_websites", "containerPath": "/var/www/html" } ], "name": "nginx", "portMappings": [ { "containerPort": 80, "hostPort": 80 }, { "containerPort": 443, "hostPort": 443 } ] }, { "essential": true, "memoryReservation": 64, "image": "jrcs/letsencrypt-nginx-proxy-companion", "links": [ "nginx" ], "mountPoints": [ { "containerPath": "/etc/nginx/conf.d", "sourceVolume": "Nginx-Proxy-Conf_D" }, { "containerPath": "/etc/nginx/vhost.d", "sourceVolume": "Nginx-Proxy-Vhost_D" }, { "containerPath": "/usr/share/nginx/html", "sourceVolume": "Nginx-Proxy-Html" }, { "containerPath": "/etc/nginx/certs", "sourceVolume": "Nginx-Proxy-Certs" }, { "containerPath": "/var/run/docker.sock", "sourceVolume": "VarRunDocker_Sock" } ], "name": "nginx-letsencrypt" }, { "name": "ds_sftp", "image": "atmoz/sftp:alpine", "essential": true, "memoryReservation": 32, "portMappings": [ { "hostPort": 2222, "containerPort": 22 } ], "mountPoints": [ { "sourceVolume": "ssh_host_ed25519_key", "containerPath": "/etc/ssh/ssh_host_ed25519_key" }, { "sourceVolume": "ssh_host_rsa_key", "containerPath": "/etc/ssh/ssh_host_rsa_key" }, { "sourceVolume": "sftp_users_conf", "containerPath": "/etc/sftp/users.conf" }, { "sourceVolume": "efs_websites", "containerPath": "/home/webupload/web" }, { "sourceVolume": "Nginx-Logs", "containerPath": "/home/webupload/logs" } ] }, { "hostname": "example.dustysun.com", "name": "example-dustysun", "image": "dustysun/php-fpm-mysql-sendmail-wp", "links": [ "nginx" ], "environment": [ { "name" : "VIRTUAL_HOST", "value": "example.dustysun.com, wp-site1.com, wp-site2.com" }, { "name" : "VIRTUAL_ROOT", "value": "/var/www/html" }, { "name" : "VIRTUAL_PORT", "value": "9000" }, { "name" : "VIRTUAL_PROTO", "value": "fastcgi" }, { "name" : "LETSENCRYPT_HOST", "value": "example.dustysun.com, wp-site1.com, wp-site2.com" }, { "name" : "LETSENCRYPT_EMAIL", "value": "email@example.com" }, { "name" : "example_dustysun_com_DB_NAME", "value": "wp-example" }, { "name" : "example_dustysun_com_DB_USER", "value": "admin" }, { "name" : "example_dustysun_com_DB_PASSWORD", "value": "pass123" }, { "name" : "example_dustysun_com_TABLE_PREFIX", "value": "dt_" }, { "name" : "wp_site1_com_DB_NAME", "value": "wp-site1" }, { "name" : "wp_site1_com_DB_USER", "value": "admin" }, { "name" : "wp_site1_com_DB_PASSWORD", "value": "pass123" }, { "name" : "wp_site1_com_TABLE_PREFIX", "value": "xp_" }, { "name" : "wp_site2_com_DB_NAME", "value": "wp-site1" }, { "name" : "wp_site2_com_DB_USER", "value": "admin" }, { "name" : "wp_site2_com_DB_PASSWORD", "value": "pass123" }, { "name" : "wp_site2_com_TABLE_PREFIX", "value": "rf_" } ], "essential": true, "memoryReservation": 128, "portMappings": [ { "hostPort": 9000, "containerPort": 9000 } ], "mountPoints": [ { "sourceVolume": "efs_websites", "containerPath": "/var/www/html" } ] } ], "volumes": [ { "name": "Nginx-Proxy-Conf_D", "host": { "sourcePath": "/efs-mount/nginx-proxy/conf.d" } }, { "name": "Nginx-Proxy-Vhost_D", "host": { "sourcePath": "/efs-mount/nginx-proxy/vhost.d" } }, { "name": "Nginx-Proxy-Html", "host": { "sourcePath": "/efs-mount/nginx-proxy/html" } }, { "name": "Nginx-Proxy-Certs", "host": { "sourcePath": "/efs-mount/nginx-proxy/certs" } }, { "name": "VarRunDocker_Sock", "host": { "sourcePath": "/var/run/docker.sock" } }, { "name": "Nginx-Proxy-Fastcgi_Conf", "host": { "sourcePath": "/efs-mount/nginx-proxy/fastcgi.conf" } }, { "name": "Nginx-Proxy-Nginx_Tmpl", "host": { "sourcePath": "/efs-mount/nginx-proxy/nginx.tmpl" } }, { "name": "Nginx-Logs", "host": { "sourcePath": "/efs-mount/nginx-logs" } }, { "name": "efs_websites", "host": { "sourcePath": "/efs-mount/vhosts" } }, { "name": "ssh_host_ed25519_key", "host": { "sourcePath": "/efs-mount/sftp/ssh/ssh_host_ed25519_key" } }, { "name": "ssh_host_rsa_key", "host": { "sourcePath": "/efs-mount/sftp/ssh/ssh_host_rsa_key" } }, { "name": "sftp_users_conf", "host": { "sourcePath": "/efs-mount/sftp/users.conf" } } ] }
Additional:
- How To: Add Coupons with Zapier (and Klaviyo) - December 31, 2021
- How To: Use SendPulse to Create a Personalized Coupon in WooCommerce - March 1, 2019
- SendPulse Support! New for Urgency Coupons for Mailing Lists - March 1, 2019
This article has been very helpful for something I’ve been setting up! Could you please share more about your custom nginx template? Are you able to add new sites on the fly? Keep up the fine docker work!
Hey Devin, glad this could help! I’ve been working on revising this somewhat because I wasn’t exactly happy with how the template was working. I do have it so that if you use the dustysun/php-fpm-mysql-sendmail-wp image and specify some environment variables, the custom template will set up new sites automatically within the same container. I’ll work on getting it fixed up for release.
What kind of setup are you using? Are you working with EB? Thanks!
We’re using EB to provide websites to our customers. We use our own website templating system instead of wordpress, but the concept is the same. PHP, nginx-proxy, let’s encrypt is the platform. Been having troubles getting the multiple website using SSL working, which sounds like you’ve had some success. I’ll try pulling down your image, is the Dockerfile public, or just the image? Trouble I’m having is the debugging is a bit of a nightmare.
Any help is greatly appreciated, thanks!
The image won’t help you because it’s specific to WordPress, and I’m also revising it anyway.
I put my nginx.tmpl file in a gist, here: https://gist.github.com/srtalley/eaba7c9ed5ce9c757addbb8d36cb1762
The modifications to the standard jwilder/nginx-proxy nginx.tmpl are all marked with the comment {{/* Dusty Sun Mod */}} so you can search and see what’s different. Again though, I’m kind of moving away from that, and I don’t think anything in there specifically made it so that letsencrypt would work. I think the standard nginx.tmpl file from the jwilder docker image should work.
Aside from that, in your Docker file config, are you setting lines like these?
{ “name” : “VIRTUAL_HOST”, “value”: “example.dustysun.com, wp-site1.com, wp-site2.com” },
{ “name” : “LETSENCRYPT_HOST”, “value”: “example.dustysun.com, wp-site1.com, wp-site2.com” },
I assume you are – if you’ve got the hosts separated by commas it should allow you work for the same container. Should… because yes it’s hard to debug! Take a look at the eb logs for your letsencrypt container. There’s probably an error message in there that will help you track things down.
Let me know if I can be anymore help!
Thanks! I’ll take a look at this tonight! I’m actually trying to avoid the config variables altogether, and add the lets encrypt domains from a separate web-based PHP process using the docker.sock to communicate between containers. This is similar to how lets encrypt talks across containers to the nginx-proxy. Thanks again, I’ll see what I can do here. If I have some success, I’ll provide an update 🙂
What happened to the “Examples can be found in the GitHub related to this post.” for .ebextensions? Can’t find any github related to this post.