Building a WordPress Site using AWS ElasticBeanstalk and EFS

Hetul Sheth
8 min readJul 2, 2020

--

In today’s era, most of the popular websites need high availability, scalability as well as resiliency. Now, this is provided by the AWS Cloud Services and one must know how to use the tools and services available in AWS to Architect their environment for all these benefits. But what if you are more of a developer and just want to upload the code and somehow through magic all these things get automatically configured for them. Oh, wait a minute…... There is already a service available that is provided by AWS which allows you to upload your code and all architecting will be then managed by AWS itself so you don't need to worry about anything regarding the architecting of the environment. The service is AWS Elastic Beanstalk.

Today in this article I am going to show you how to build a WordPress site using this service known as ElasticBeanstalk and using EFS as our storage device.

Now there are many WordPress sites available and I am here considering the one which deals with uploading the images which will be shown to the user as a post as soon as they sign-in on the site using a browser.

You can follow the article to find out:

How to design the WordPress site code so all the uploaded images are stored on EFS( this is useful when you want to have common storage service for all instances/servers as they will be behind an Elastic LoadBalancer and user might not always connect to the same instance and so having common storage is beneficial as the user will not need to worry about the instance through which they connect as they are going to see the images which are stored in EFS(Elastic File System)).

So here is the file model which I am using as my WordPress code.

Figure 1

You can also follow on your code files even if they are different as we are going to configure this by creating a new folder named .ebextensions

In .ebextensions folder add the following config file and name it efs.config:


option_settings:
aws:elasticbeanstalk:application:environment:
FILE_SYSTEM_ID: YOUR_EFS_FILE_ID
MOUNT_DIRECTORY: '/efs'
packages:
yum:
amazon-efs-utils: []
commands:
01_mount:
command: "/tmp/mount-efs.sh"
files:
"/tmp/mount-efs.sh":
mode: "000755"
content : |
#!/bin/bash
EFS_MOUNT_DIR=$(/opt/elasticbeanstalk/bin/get-config environment -k MOUNT_DIRECTORY)
EFS_FILE_SYSTEM_ID=$(/opt/elasticbeanstalk/bin/get-config environment -k FILE_SYSTEM_ID)
echo "Mounting EFS filesystem ${EFS_FILE_SYSTEM_ID} to directory ${EFS_MOUNT_DIR} ..."echo 'Stopping NFS ID Mapper...'
service rpcidmapd status &> /dev/null
if [ $? -ne 0 ] ; then
echo 'rpc.idmapd is already stopped!'
else
service rpcidmapd stop
if [ $? -ne 0 ] ; then
echo 'ERROR: Failed to stop NFS ID Mapper!'
exit 1
fi
fi
echo 'Checking if EFS mount directory exists...'
if [ ! -d ${EFS_MOUNT_DIR} ]; then
echo "Creating directory ${EFS_MOUNT_DIR} ..."
mkdir -p ${EFS_MOUNT_DIR}
if [ $? -ne 0 ]; then
echo 'ERROR: Directory creation failed!'
exit 1
fi
else
echo "Directory ${EFS_MOUNT_DIR} already exists!"
fi
mountpoint -q ${EFS_MOUNT_DIR}
if [ $? -ne 0 ]; then
echo "mount -t efs -o tls ${EFS_FILE_SYSTEM_ID}:/ ${EFS_MOUNT_DIR}"
mount -t efs -o tls ${EFS_FILE_SYSTEM_ID}:/ ${EFS_MOUNT_DIR}
if [ $? -ne 0 ] ; then
echo 'ERROR: Mount command failed!'
exit 1
fi
chmod 777 ${EFS_MOUNT_DIR}
runuser -l ec2-user -c "touch ${EFS_MOUNT_DIR}/it_works"
if [[ $? -ne 0 ]]; then
echo 'ERROR: Permission Error!'
exit 1
else
runuser -l ec2-user -c "rm -f ${EFS_MOUNT_DIR}/it_works"
fi
else
echo "Directory ${EFS_MOUNT_DIR} is already a valid mountpoint!"
fi
echo 'EFS mount complete.'echo "creating folders (uploads)"
mkdir -p /efs/uploads
chown webapp:webapp /efs/uploads
container_commands: 01-rm-wp-content-uploads:
command: rm -rf /var/app/ondeck/wp-content/uploads
02-symlink-uploads:
command: ln -snf /efs/uploads /var/app/ondeck/wp-content/uploads

Now let's understand the above code and where you need to do changes. On the third line, you can see the FILE_SYSTEM_ID: YOUR_EFS_FILE_ID’.

Here replace ‘YOUR_EFS_FILE_IDwith the File Id of your EFS which you have in your AWS account and which you want to attach to your servers/instances. If you want to know how to create EFS File in AWS please refer to this documentation of AWS.

Now don't do any other changes in code until you come across container_commands. Now what container_commands is trying to do is to create a symlink between yourwp-content/uploadsand the uploads folder created in the EFS i.e. /efs/uploads( This file is created by the command mkdir -p /efs/uploadsin the above code) and then delete the uploads folder in wp-content. Now what the symlink is so basically it will create a hard link between your wp-content/uploads folder and the uploads folder in EFS i.e. /efs/uploads. Now those who have this code folders as mentioned in Figure 1, know that basically when one will try to upload the file it will be stored in the wp-content/uploads. So now when we create a symlink it will create a link that will transfer all the files that are uploaded to this destination to the destination in EFS i.e. in our case /efs/uploads.

The line chown webapp:webapp /efs/uploads is giving the rights to the web users who are going to upload the images. By default when you will see the rights of this folder it would be ec2-user. You can check the rights of your folder using ls -ltr . If you don't have these webapp rights you will face a problem that when users will upload the image using the browser the image won’t get uploaded. So remember to have webapp rights for the /efs/uploads . Although here our above code will take care of all of that so no need to worry if you are using the above code for your config file.

But CAUTION: If you have some images already in your wp-content > uploads and you want to transfer those to /efs/uploads, do so using the below code and ignore the above code. The above code is for those who are starting from fresh. Here we are going to delete this uploads folder in wp-content so before deleting do copy all images to efs.

option_settings:
aws:elasticbeanstalk:application:environment:
FILE_SYSTEM_ID: YOUR_EFS_FILE_ID
MOUNT_DIRECTORY: '/efs'
packages:
yum:
amazon-efs-utils: []
commands:
01_mount:
command: "/tmp/mount-efs.sh"
files:
"/tmp/mount-efs.sh":
mode: "000755"
content : |
#!/bin/bash
EFS_MOUNT_DIR=$(/opt/elasticbeanstalk/bin/get-config environment -k MOUNT_DIRECTORY)
EFS_FILE_SYSTEM_ID=$(/opt/elasticbeanstalk/bin/get-config environment -k FILE_SYSTEM_ID)
echo "Mounting EFS filesystem ${EFS_FILE_SYSTEM_ID} to directory ${EFS_MOUNT_DIR} ..."echo 'Stopping NFS ID Mapper...'
service rpcidmapd status &> /dev/null
if [ $? -ne 0 ] ; then
echo 'rpc.idmapd is already stopped!'
else
service rpcidmapd stop
if [ $? -ne 0 ] ; then
echo 'ERROR: Failed to stop NFS ID Mapper!'
exit 1
fi
fi
echo 'Checking if EFS mount directory exists...'
if [ ! -d ${EFS_MOUNT_DIR} ]; then
echo "Creating directory ${EFS_MOUNT_DIR} ..."
mkdir -p ${EFS_MOUNT_DIR}
if [ $? -ne 0 ]; then
echo 'ERROR: Directory creation failed!'
exit 1
fi
else
echo "Directory ${EFS_MOUNT_DIR} already exists!"
fi
mountpoint -q ${EFS_MOUNT_DIR}
if [ $? -ne 0 ]; then
echo "mount -t efs -o tls ${EFS_FILE_SYSTEM_ID}:/ ${EFS_MOUNT_DIR}"
mount -t efs -o tls ${EFS_FILE_SYSTEM_ID}:/ ${EFS_MOUNT_DIR}
if [ $? -ne 0 ] ; then
echo 'ERROR: Mount command failed!'
exit 1
fi
chmod 777 ${EFS_MOUNT_DIR}
runuser -l ec2-user -c "touch ${EFS_MOUNT_DIR}/it_works"
if [[ $? -ne 0 ]]; then
echo 'ERROR: Permission Error!'
exit 1
else
runuser -l ec2-user -c "rm -f ${EFS_MOUNT_DIR}/it_works"
fi
else
echo "Directory ${EFS_MOUNT_DIR} is already a valid mountpoint!"
fi
echo 'EFS mount complete.'echo "creating folders (uploads)"
mkdir -p /efs/uploads
chown webapp:webapp /efs/uploads
container_commands:
01-cp-wp-content-uploads:
command: cp -r /var/app/ondeck/wp-content/uploads /efs/uploads
02-rm-wp-content-uploads:
command: rm -rf /var/app/ondeck/wp-content/uploads
03-symlink-uploads:
command: ln -snf /efs/uploads /var/app/ondeck/wp-content/uploads

After you did symlink using any of the above code according to your requirement when you SSH into your instance you might see that the wp-content > uploads folder will be of a different color(in my case light blue) than the other folders present there which means symlink is a success.

Also, I would like to share that above some of you might come across a thought that even I came through while I was doing for the first time is that we are looking into /var/app/current/wp-content but we are using /var/app/ondeck/wp-content in the above config file. Why so are we using ondeck instead of current? Even when you try to replace ondeck with current in the above config code it will work and ElasticBeanstalk will show the success of all commands executed but then when you will SSH into the server you won’t see the uploads symlink created which is our main purpose. This is because when we deploy an application it is first done to /var/app/ondeck and after which all our container commands are run on it. Only after everything is ready, the files are moved to /var/app/current. So, basically running commands on current won't help at this stage at all as that folder contains the previous version of the app.

Now, whenever the user will upload the images it will be stored on the EFS instead of instance storage.

Now we understood the code so let’s upload our files to ElasticBeanstalk. Remember to keep the above-created config file in the folder named .ebextensions which will be at the root location. Zip these files and upload them to AWS ElasticBeanstalk. Follow these steps to upload:

Create an application on Elastic Beanstalk and give the name according to your desire or requirement.

Create an environment in that application and instead of selecting sample application choose to upload file and upload your zip file we created earlier. You can change the configuration according to your convenience by selecting configure more options button beside create environment at the bottom.

Once deployed successfully you can see the EC2 instances being spun automatically after sometime and if you have minimum 2 instances in auto scaling then open both on the browser using their public IP. Login and Upload image on one of the instance and when uploaded open the second server on the browser using its respective public IP and after login, you can see that same file which we just uploaded on different server. So as we can see the image on both the instances we can say that our EFS is working and we are seeing these images from our EFS. The same will happen even if there would be more than 2 instances behind load-balancer.

So now we can say that we have successfully created a Beanstalk environment where EFS file will be mounted to our instances and so we are good to go!!

--

--

Hetul Sheth
Hetul Sheth

Written by Hetul Sheth

AWS Certified Solutions Architect, Developer and SysOps Admin Associate | Azure Certified

No responses yet