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:

 

Steve Talley

Pin It on Pinterest

Share This