Building an environment end-to-end using Application Gateway as single entry point for Web Apps
You know that but never is too much remember that concept; Azure could be seen as a giant puzzle composed by hundreds of small and big waves of peace in which customers can put some of those together to create an ideal scenario for a given application (I really like to see cloud platforms that way). Why do I remember that? Because this post, once again, all about brings peaces together. In this case, we will create a high-scalable, reliable and secure environment for Wordpress (but, it would be whatever application you may need) by gathering Application Gateway (AG), Web Apps, Azure CDN, Azure Redis Cache, and MySQL Database.
This is not going to be a complicated process (I mean, build this environment), however, as you'll see later on some small configurations will make a massive difference towards to provide the expected behavior of your application.
During this text, I'm going to use different approaches (Powershell, CLI and Azure Portal) to build up and interact with our environment. I'm doing that purposely as one of my side intentions is to show Azure's flexibility on that regard.
Pre-work 1: Getting a free custom domain name
This is not an Azure thing so, why am I doing this? Because I want to simulate as closely as possible a real-life scenario and most of the real-life situations we work on use custom domains, so will we.
There are very nice options (you can read websites) through which you could get a free and temporary custom domain name. The one I have mostly been using is freenom.com. By given a click on this link you'll be redirected to the website's main page. Just verify the availability of the desired custom name (see figure below). Grab it by doing a simple and free registration, and that's all. You now have already gotten your custom domain.
As you can see, my custom domain is wordpress-fabricio.tk.
Next, we'll generate a SSL certificate to match our newly created custom domain. Why? Because real web applications are protected by encrypted communication over HTTPS and considering we want to simulate a real-life scenario, we will need to have it. So, let's do it.
Pre work 2: Building up a free non-commercial SSL certificate
Fortunately, if you need to create either a dev/test environment or perhaps a troubleshooting scenario to go through some specific situation (a super common scenario for CSAs like me) you can take advantage of tools like Let's Encrypt to build up valid SSL certificates for your testing application. Please, give a click here to see full documentation to the solution locally.
Once using Let's Encrypt, the most common way to get yourself settled towards to get your certificate is by using a shell. This approach requires you to install an agent called Certbot, which will be the element in your local machine communicating with the online service and generating the certificate under-the-hood. It has the ability to automate certificate issuance and installation with no downtime. Pretty cool, ha? Both the installation and configuration process very well documented and publicly available through this link.
Because I'm in a Windows machine right now, I opted by using Linux Sub-system with Ubuntu 16.04. Certbot is a Linux tool, so you're in a similar situation, I may need to recur to the same resource.
From now on I'm assuming that you have already settled the two conditions below.
- Registered your custom domain and access to your custom domain's DNS edit zone;
- Installed and configured Certbot in your environment;
If it is not your case, please, go back and fix it. You will not be able to move by not having everything in place here.
Because my Wordpress will run in a Linux Web App on Azure on top of Apache, I will "make my certificate aware of this configuration" executing the command below (as elevated permission user).
sudo certbot --apache
Now, to generate the certificate, please execute the command line below. Please note that "{temporary domain}" needs to be replaced by your custom domain. In my case, I replaced that with wordpress-fabricio.tk.
sudo certbot -d {temporary domain} --manual --preferred-challenges dns certonly
As the next step, Certbot agent will ask you about an authorization to log your machine public IP in the remote controller server as certificate requester (please, see picture below). Just type "Y" and press enter.
Now you need to add a TXT record to your domain's DNS zone. Certbot will pass the generated information to send to the controller server towards to validate the if the requested domain exists and if it is up and running. Just copy/paste the generated values into your DNS zone, as shown by the figure below.
Back to Linux, just press enter to complete the validation process. You should see a success message, just like that one presented by the picture below. You should save the information given here once we'll use it soon.
Great. Now we do have both the certificate itself and the private key already in place. Now, to make it suitable for Azure, we need to overcome three additional steps. Let's dive into it.
First, we need to generate a new private key with a password and also a passphrase, once Azure is going to require that later on. By default certbot doesn't generate a password secured by a password so if you need it, you need to accomplish that by yourself. Assuming you're already in " /etc/letsencrypt/live/your_custom_domain/", execute the command-line below to create a passphrase.
openssl rsa -aes192 -in privkey.pem -out yournewprivatekey.pem
Now, based upon the file we just built let's create a new PFX with the desired password. You can do that by executing the following command-line.
openssl pkcs12 -inkey yournewprivatekey.pem -in cert.pem -export -out your-pfx-name.pfx -passout pass:yourpassword
As result of these two operations, you should have two new files under the "/etc/letsencrypt/live/your_custom_domain/" directory; a new .pem with a passphrase (in my case wordpress-fabricio-pk.pem) and a new secured by password .pfx file (in my case wordpress-fabricio.pfx).
Finally, because the AG requires a .cer file into their HTTPS settings, we need to generate this new version of the certificate. I'm doing this executing the command-line below.
openssl x509 -inform PEM -in cert.pem -outform DER -out yourcertfilename.cer
Done. Now, because I'm using a Linux-subsystem and I want to keep up everything tied at my Windows file system through the command-line below I'm moving these three new files.
mv -t DESTINATION yournewprivatekey.pem your-pfx-name.pfx yourcertfilename.cer
General vision about the solution
Before to start building things, let's clearly understand what effectively we're making on top of Azure. We'll be creating a high-scalable and secure environment for Wordpress, one of the widely used Contents Management System (CMS) around the World. The proposed architecture could be seen below.
Generally speaking, we'll have:
- We will have a single entry point to our environment, and it will be Application Gateway.
- All the good requests reaching the AG will be directed to a Web App (used here as backend pool) which will split up those requests all across the instances up and running under-the-hood.
- Then, a MySQL database will be used to host the data of our application (Wordpress).
- Azure CDN will be used to deliver static content (CSS, Javascript, Images, and so forth). Azure Redis Cache will be used to host temporary Wordpress' temporary data instead to keep it in regular memory.
Step 1: Creating a new MySQL Server and database
From now on, I'm assuming you already have an Azure subscription up and running. I'm also assuming that you're already logged in to its existing subscription. If you aren't familiar with Azure and are not sure in how to get yourself settled in, please, follow up this link and see how to get started.
Every resource in Azure lives in a resource group (RG) so first of all, I'm going to create a new RG to group on the plenty of Azure services will need to put this architecture together. I'm doing this by executing the following command-line.
az group create -n wordpress-fabricio -l westus2
Next, I'm going to create a new MySQL server. There are different options to create MySQL databases on Azure. I will build up a new one top of Azure Database for MySQL. To know more about this service, please, give a click to this link. To create it, I will use Azure CLI. To see instructions on how to install and configure Azure CLI in your environment, please, follow up this link.
az mysql server create -g wordpress-fabricio -n mysql-server-fabricio --sku-name B_Gen5_2 -l westus2 -u your_username -p your_password
Don't forget to add a rule to service's firewall allowing both Azure services and external services to access it. The command-line below shows up how to get there. In a production environment you should be careful about who has access to your environment. Because we're in a test environment, I'm allowing all the access is coming in.
az mysql server firewall-rule create -g wordpress-fabricio -s mysql-server-fabricio -n AllowAll --start-ip-address 0.0.0.0 --end-ip-address 255.255.255.255
Great. Now we need to create a new database inside the server. You could do it using a third-party tool like MySQL Workbench, for example. Because I'm already using Azure CLI and there is a simple way to accomplish that into it, I'll proceed that way. Please, see the command-line below.
az mysql db create -n wordpressfabriciodb -g wordpress-fabricio -s mysql-server-fabricio
Done. We have created our MySQL environment. If for some reason you need to update that environment, do it. You could easily do that both through the Azure Portal, Powershell, and CLI. Flexibility is the key.
Step 2: Creating the Web App to host the Wordpress
Now that we have our database already in place, we can move forward and create the Web App to host our application. If you would like to know more about Web Apps (one of the services available at App Services portfolio on Azure, please, follow this link out. To get there, I went through "Add new resource" -> "Selected Web App" -> "Create". Then, I fulfilled the form as below.
By doing this, I've created a new Web App. Then, I took advantage of the FTP connection data provided by the Web App itself, and after adjust out the wp-config.php file with the database connection info, I sent the bunch of files which composes Wordpress to the server. The result (working Wordpress) can be seen at the image below by calling the Web App FQDN through the browser.
Step 4: Attaching a custom domain to the Web App
To make our environment customized, we need to attach the custom domain we created through the earlier steps to the Web App. We need to do it because it will be used as a key for both the Application Gateway configuration and Azure CDN. It will become clear later on.
You will be able to found out two very nice articles in Azure's documentation showing the procedure to do this custom domain configuration. Because I don't want to reinvent the wheel, I'm listing these links below.
- Map an existing custom DNS name to Azure Web Apps: https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-custom-domain.
- Migrate an active DNS name to Azure App Service: https://docs.microsoft.com/en-us/azure/app-service/app-service-custom-domain-name-migrate.
After doing this, as you can see through the image below, I have my Web App being reached through the custom domain wordpress-fabricio.tk.
Step 4: Adding a SSL binding to the Web App
We want to make our environment as secure as possible. Because of it, we need to add an SSL binding to this Web App. This way, we will be able to guarantee the communication flowing encrypted all over the resources. There is a very nice explanation on how to do it on top of Web Apps at Azure documentation. The link is listed below.
- Configure an SSL certificate for Azure App Service: https://docs.microsoft.com/en-us/azure/app-service/web-sites-purchase-ssl-web-site.
After following up the steps described above, I've got my Web App correctly configured, as you can see below.
Step 5: Converting Wordpress to work with SSL
Wordpress supports SSL naturally. However, this is not an automatic thing. You need to manually do some internal configurations to get the platform up and running under that setup.
There are several ways to accomplish that. However, the easiest one will require the installation + configuration of a plugin called Really Simple SSL. It will sweep out the environment doing the necessary changes to get Wordpress up and running under HTTPS. It is pretty cool, actually. Here is what you'll need to do to overcome this process.
- Log in into your Wordpress with administrative credentials.
- Go to "Plugins" -> "Add new".
- Look up for "Really Simple SSL" plugin, install and activate it.
- Go to the plugin's configuration and start the configuration process by giving a click at "Go ahead, activate SSL!" (see the image below).
By doing this, after a couple of seconds running some internal routines, the plugin will notify you that your Wordpress environment was successfully converted, as you can see through the image below.
Done. Now we have our Wordpress fully functional in our Web App and responding under SSL with a valid certificate and custom domain. Next step? Azure CDN.
Note: Right after this process, remember to download the file wp-config.php to your local machine again once that as result of this process, some rules are written on that file.
Step 6: Creating a Azure CDN Profile and Endpoint
Content Delivery Network (CDN) is an essential piece of whatever web application which needs to be performative as the number of static files within these apps (like Wordpress) increases considerably towards to make them visible attractive to final users, and so forth. This is why we're going to need an Azure CDN Profile + Endpoint.
In Azure, by design, you can have multiple CDN profiles and, inside of each one of them, you can have as many Endpoints (Azure will use these channels to deliver the static files you might have) as you need. This way, we're going to create first a CDN Profile and after that, a public endpoint to connect our application to.
The following command-line will enable you to create a new CDN profile using Akamai as a CDN provider. You could choose either Microsoft or Verizon as providers as well.
az cdn profile create -n cdn-fabricio -g wordpress-fabricio --sku Standard_Akamai
Pretty simple. Now, let's add a new endpoint into it. The below's command-line shows us how to do that.
az cdn endpoint create -g wordpress-fabricio -n wordpress-fabricio-endpoint --profile-name cdn-fabricio --origin wordpress-fabricio.tk
By executing these steps, you'll be receiving the and endpoint like this: "*.azureedge.net". In my case, it will be "wordpress-fabricio.azureedge.net". So, we're good to go to the next step. Both CDN profile and Endpoint are already in place.
Step 7: Configuring Azure CDN inside Wordpress
As most of the customization we often do on top of Wordpress, to get support to Azure CDN into it we need to take advantage of some specialized plugin for it. There are several working options whereby it could be done. My choice is going to be "WP Super Cache" as it is widely used by the Wordpress community recognized by its efficiency.
Once you have, it installed and active, go to its configuration area to surpass three simple steps, described below.
- At "Easy" tab, turn on the option "Caching On (Recommended)".
- At the "CDN" tab, at the very top, check the box with message "Enable CDN Support".
- At the "CDN" tab, either add or type the CDN endpoint we've created on the above step at the field marked up with the label "Off-line URL", as you can see through the image below. Then, give a click to the button "Save changes".
After a couple of minutes, the static content localized under "wp-content" and "wp-includes" will be delivered by the endpoint we just configured (in my case, wordpress-fabricio.azureedge.net). The result could be seen below (by executing the developer tools of your preferred browser).
Step 8: Creating and configuring Azure Redis Cache
Redis Cache is one of these widely used cache services for web applications trying to get itself concerning reliability and performance. Fortunately, Azure does offer a managed service for Redis Cache and we will take advantage of it in our environment.
Azure's documentation has already a very nice tutorial explaining how to create a new instance of Redis, so I'll assume that you're following that steps to get it done before to move on here. The tutorial is available through this link.
Please note that, because Wordpress plugin doesn't support SSL connections to Redis Cache service by the time being, you should enable NON-SSL connections through the Azure Portal.
Note that the Redis Cache service can take up 15 minutes to get itself deployed on Azure. Now is an excellent time to grab a coffee.
Step 9: Configuring Redis Cache inside Wordpress
Now that we have our Redis Cache instance already in place, we should be able to direct our Wordpress to use it properly. Once again, we're going to accomplish that by using a specialized plugin designed for it.
My choice here is going to be "Redis Object Cache" for the same reason I've got WP Super Cache. It is widely used by the community and is recognized by being one of the most efficient plugins for Redis. From now on, I'm assuming you have already installed it in your environment.
To enable it, we need to overcome two simple steps, described below.
- We do need to edit the "wp-config.php" config file and add out the following snippet code immediately below the database connection information.
define('WP_REDIS_SCHEME', 'tcp');
define('WP_REDIS_HOST', '<your redis account name>.redis.cache.windows.net');
define('WP_REDIS_PORT', '6379');
define('WP_REDIS_DATABASE', '0');
define('WP_REDIS_PASSWORD', '<your primary access key>');
You should replace the featured information (both "Redis account name" and "Your primary access key") by the ones related to your Redis Cache account just created. As next step, send the updated file back to its original place through FTP.
2. Back to Wordpress admin area, go to "Plugins" -> "Installed Plugins" -> "Redis Object Cache Settings". Then, give a click to "Enable Object Cache" button. By accomplishing this, you are seeing a screen like that one presented by the image below.
Done. Now our Wordpress is connected to Azure Redis Cache, and we will be able to use it to persist data outside the app server.
Step 10: Adding and configuring Application Gateway
At this point, you should have 90% of your environment up and running, and so its time for us to define a single entry point for our application. As you can recover from the architectural design showed up early on, we're going to use Application Gateway to act both as a load balancer, reverse proxy, and SSL off-loader.
Here is what we are going to do to have our application gateway in place doing that work for us:
- Create a new Virtual Network (VNet);
- Create a public IP (PIP) to be used by the AG;
- Create a new AG and tie it to the existing VNet and PIP;
- Configure the Web App we currently have to act as backend pool for Application Gateway;
- Configure both HTTP and HTTPS listeners for our environment;
- Create an AG rule which will be able to redirect the HTTP incoming traffic to HTTPS (once we want to do an end-to-end HTTPS solution);
- Create an HTTPS setting to support the internal communication from our AG to the backend pool;
- Create a custom probe to meet the requirements we want to implement for our environment;
- Point out the DNS from the Web App to the Application Gateway FQDN;
If this is the first time you're touching Azure Application Gateway, before to move on in this text, I would strongly recommend you to take a look in this link. The concepts explained here will be critical for you to implement the best configuration for your application. Also, from now on, I will be using a mix between Powershell Core with the new Az module and Azure Portal as my primary tools to build up the AG's configuration.
Step 10-1: Building a new Virtual Network
The very first thing we need to do towards to get our AG in place is to set up a dedicated subnet in Azure for the AG. Once we don't have one already in place and considering that a subnet always lives inside a network, I'm going to create a new virtual network and then, to define a subnet to our AG. I built it following the instructions available through this tutorial.
Step 10-2: Creating a Public IP
Another prior requirement for our Application Gateway is a public IP (PIP). To create it I'm using the following Powershell's command-line.
New-AzPublicIpAddress -AllocationMethod Dynamic -IpAddressVersion IPv4 -Name ag-pip -Location westus2 -Sku Basic -ResourceGroupName wordpress-fabricio
Step 10-3: Creating the Application Gateway
At this point, we do have everything we need to put our Application Gateway together. Because the creation of our AG will require a considerable amount of configurations, I'm going to go through it using the Azure Portal. It is going to make this process easy to understand.
What am I doing here? Nothing special. Only setting up the basics of the service (as you can see through the list below).
- Giving a name to the AG;
- Selecting the tier for the service (in this case I'm selecting the Standard one);
- Informing the number of instances that are going to support the load on my Application Gateway (in this case I'm selecting two);
- Picking up a SKU (in this case, Medium);
- Selecting the subscription where the service will be setting in;
- Picking up the Resource Group name where I will be grouping the AG into;
- Selecting the location where the service will be deployed to;
Yes, now we can see (and actually understand a bit more how AG works) some interesting configurations. Below you'll found an explanation on that regard.
- The very first thing I'm doing here is tie the virtual network we've created in a earlier step (in my case a VNet called "vnet-wordpress-fabricio") to my AG.
- Then, I picking up the subnet which is already available inside my VNet to support my AG. This subnet will not be able to be used for any further device.
- The next step consists in to tie the public IP we've also created for our AG. In my case, it is called "ag-pip", reason by each it was picked up.
- Next, I'm defining a listener HTTPS for the AG. This configuration will allow the AG manage HTTPS income requests properly. As you can see, I'm uploading the SSL certificate here as well. It needs to be in PFX format and it has to carry a password. Later on we will go through an additional configuration to redirect HTTP to HTTPS.
- Then, we're "telling" to the AG that, at this time, we don't want do enable HTTP2 neither WAF. We'll do it later on, though.
The next step is all about review the configuration just make and confirm it by giving a click on "Create". Fifteen to twenty minutes later you should be able to see the AG up and running through the Azure portal.
Step 10-4: Configuring the Application Gateway
Finally, we can do the configuration needed to have the AG routing the requests all over the Web App's instances on top of HTTPS. The command lines with its respective explanations can be seen below.
$webappFQDN = "wordpress-fabricio.azurewebsites.net"
Because I'm going to use the Web App's FQDN later on I'm starting putting it into a variable.
$gw = Get-AzApplicationGateway -Name gateway-wordpress-fabricio -ResourceGroupName wordpress-fabricio
Then, considering that I'm going to update an existing Application Gateway, I'm taking this object out and keeping into a variable to be used later on.
$match=New-AzApplicationGatewayProbeHealthResponseMatch -StatusCode 200-401
As next step, I'm defining a new variable which stores a custom health probe to be used later on by the HTTP Setting inside the AG.
Add-AzApplicationGatewayProbeConfig -name httpsProbe -ApplicationGateway $gw -Protocol Https -Path / -Interval 30 -Timeout 120 -UnhealthyThreshold 3 -PickHostNameFromBackendHttpSettings -Match $match
Next, I'm creating a new configuration to tie the probe we just created. There is a key element being settled here. It is the "-PickHostNameFromBackendHttpSettings". This parameter was built to let the AG knows who needs to be pointed out when a redirection to Web App's backend needs to happen. Without it, the communication would be broken.
$probe = Get-AzureRmApplicationGatewayProbeConfig -name httpsProbe -ApplicationGateway $gw
Just keeping the probe configuration at the memory for later usage.
Set-AzApplicationGatewayBackendHttpSettings -Name appGatewayBackendHttpSettings -ApplicationGateway $gw -HostName "wordpress-fabricio.tk" -Port 443 -Protocol https -CookieBasedAffinity Disabled -RequestTimeout 30 -Probe $probe
Creates a new HTTP setting attaching both the probe configuration and Web App's hostname to the Application Gateway. Remembering that the HTTP Setting is "the guy" to is going to manage the communication from the AG towards the backend pool.
Set-AzApplicationGatewayBackendAddressPool -Name appGatewayBackendPool -ApplicationGateway $gw -BackendFqdns $webappFQDN
Tying up the Web App's FQDN to the AG's backend pool so it can be sure to where direct the request under HTTP setting's supervision.
Set-AzApplicationGateway -ApplicationGateway $gw
Applies off all those configuration (so updates) to the existing AG. As result, by calling out either AG's IP or FQDN you should be able to see the Wordpress being presented, as the below's image shows up.
Step 10-5: Creating a new HTTP listener and redirect rule
By the configuration we have so far, there is only one listener (HTTPS) configured. That means regular income requests (port 80) are not being handled. HTTPS-wise environment tells us that we need to deal with it.
What I'm going to do on that regard is to create both a new HTTP listener and after, tie a new redirection rule to it in such way that for each new income request on that port will automatically be redirected to HTTPS (or 443 port). The below's figure shows up the new listener's configuration.
Now, on top of this listener, I'm going to add the redirect rule (as you can see below).
Done. Now our rule is redirecting from the port 80 to the 443.
Hope it helps in your future projects.
Leading companies forward with digital transformation
5 年Great article! Can you please explain how you restricted the webapp to speak to the firewall only and keep CDN updating?