So you’ve got an application running in IBM Cloud. It’s made up of two components — each a Docker container, each listening on a given port and IP address. These components might be a backend that talks to a database, and a frontend that serves a website and talks to the backend. They could run on the same virtual server, or you might want to split them across different instances.
Either way, you may want these two components to appear as though they’re coming from the same endpoint, and have something route the traffic for you in a clever way. For example, you could route traffic calling any /api/
endpoint to the backend component, and any other traffic to the frontend component. It’s easy to do this using a reverse proxy like Nginx, and this tutorial shows you how.
Even easier, you’ll run it in IBM Cloud as a Cloud Foundry application. This way, deployment is trivial (as much of the detail of how or where to run it is abstracted away) and you gain two things for free:
- A simple domain name, instead of an IP address
- HTTPS pre-configured using an IBM Cloud certificate
Learning objectives
This tutorial shows you how to configure and deploy an Nginx server configured as a reverse proxy, running in IBM Cloud as a Cloud Foundry application.
Along the way, you’ll learn how to configure and deploy an application into an IBM Cloud Hyper Protect Virtual Server instance (following a code pattern) before deploying the Nginx reverse proxy.
Prerequisites
To complete this tutorial, you’ll need:
- An IBM Cloud account
- The source code for the code pattern Build and deploy a disaster donations website with end-to-end encryption
- An IBM Cloud Hyper Protect Virtual Server instance
- A terminal to run
ibmcloud
commands
Estimated time
It should take you less than 1 hour to complete this tutorial.
Components of the solution
First, I’ll show you how to configure and deploy a multi-component application, to demonstrate the use of the Nginx reverse proxy. I’ve already created a suitable one, so you’ll just use the disaster donations code pattern website (linked above). However, you don’t need to follow all the documentation for that code pattern; just running the Docker containers it provides will be enough.
Install the disaster donations site on an IBM Cloud Hyper Protect Virtual Server instance
Download the zip file for the above code pattern, then upload and extract it to your virtual server, and build the Docker images.
First, copy the zip file to your virtual server:
scp disaster-donations-website-master.zip root@your_hpvs_public_ip:
Then, install unzip
and docker
on the server:
ssh root@your_hpvs_public_ip
apt-get install -y unzip docker.io
Finally, extract and build the frontend and backend component applications:
unzip disaster-donations-website-master.zip
cd disaster-donations-website-master
docker build -t disaster-frontend frontend/
docker build -t disaster-backend backend/
Now you can run the applications, listening on different ports:
docker run -d -p8080:8080 disaster-frontend
docker run -dp 5000:5000 -e PASSWORD='your_password' \
-e USERNAME='your_username' \
-e DBNAME='admin' \
-e ENDPOINT='hostname:28000' \
-e REPLICASET='replicaset' disaster-backend
Note that for this tutorial and example, you don’t need to populate the above environment variables. After doing this, you’ll have two components of the application, listening on different ports, confirmed by running docker ps
:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea354a3bfb4e disaster-backend "python3 run-app.py" 2 seconds ago Up 1 second 0.0.0.0:5000->5000/tcp determined_ritchie
58715da9b934 disaster-frontend "docker-entrypoint.s…" 2 hours ago Up 2 hours 0.0.0.0:8080->8080/tcp, 8443/tcp nostalgic_kepler
To confirm this is working, use a web browser to navigate to http://your_hpvs_ip_address:8080 and you’ll see the disaster donations website.
Now, navigate to http://your_hpvs_ip_address:5000/api to have the backend component respond:
{
"apiVersion": "v1.0",
"message": "Welcome to the Disaster Funding API",
"status": "200"
}
(Your web browser might attempt to make this look pretty, and not just show the raw JSON.)
Configure Cloud Foundry in IBM Cloud
At this point, you have two components listening on different ports (and possibly different machines and IP addresses entirely), and you want to present them as though they’re coming from the same system. You want to route all API requests to the backend, and anything else to the frontend website.
Proxy servers are used in many different places, often acting to take one resource or endpoint on the public internet and providing this (cached) to multiple backend machines. For example, in the case of a corporate private network, a large file stored somewhere on the public internet that many people want to download might be cached by the proxy server to reduce bandwidth bills. When the proxy server sees requests coming to it from inside the private network (multiple people, presumably), it fetches the file once, then provides it from its cache to other requests it receives.
A reverse proxy ostensibly looks the same, but the flow of requests is reversed. There’s still one endpoint on the public internet in this picture, and two or more endpoints on the private network — but the request is coming from the public internet endpoint. This reverse proxy, in turn, routes that request intelligently to the endpoints it knows about on the private network. To the public internet endpoint, this is transparent, and it appears as though all requests are coming from the same machine, when that might not actually be the case.
Nginx is the reverse proxy that you’ll deploy to achieve this result, and you will make use of it as a Cloud Foundry application. To do this, you need to ensure that Cloud Foundry is configured.
Using a web browser that’s logged in to your IBM Cloud account, go to your Cloud Foundry Orgs page. Here, you can create an org, and within an org, a space. By default, you’ll find that you have an org whose name matches your IBM Cloud username (which may be your email address). Under that, you’ll find a default space called dev
.
To choose these for your target environment for your Nginx reverse proxy, run the following in a terminal.
First, determine your region, which might be derived from where you created your IBM Cloud account:
ibmcloud login
ibmcloud regions
For me, this returns the following list (at the time of writing this tutorial):
Listing regions...
Name Display name
au-syd Sydney
jp-tok Tokyo
kr-seo Seoul
eu-de Frankfurt
eu-gb London
us-south Dallas
us-east Washington DC
By clicking on my org name on the above Cloud Foundry Orgs page, I can see that it lists my dev
space as being in the United Kingdom region:
Based on this, I can use the IBM Cloud CLI to interactively select the org and space where I will deploy my Nginx reverse proxy, in this region:
ibmcloud target --cf -r eu-gb
If you only have one defined org and space, the default for a free IBM Cloud account, these will be selected for you.
Configure your Nginx reverse proxy
Now that we’ve set up Cloud Foundry, we can define the Nginx application. Create a directory, with two files inside. Copy and paste the following file contents:
manifest.yaml
:
applications:
- name: hyper-protect-nginx-proxy
memory: 32M
disk_quota: 32M
path: .
buildpacks:
- https://github.com/cloudfoundry/nginx-buildpack.git
nginx.conf
:
# write errors to stderr where Cloud Foundry can grab them
error_log stderr;
# leave as default for now
events { worker_connections 1024; }
http {
server {
# get the port number from Cloud Foundry
listen {{port}};
if ($http_x_forwarded_proto != "https") {
rewrite ^ https://$host$uri permanent;
}
location / {
proxy_pass http://your_hpvs_public_ip:8080;
}
location /api {
proxy_pass https://your_hpvs_public_ip:5000;
}
}
}
The manifest file simply describes the application to Cloud Foundry. Crucially, the name key will be used when defining the subdomain it gives you. (For example, you might end up with a domain like name.mybluemix.net. The domain is configurable from the IBM Cloud interface; you’ll see how later.) You then define some memory (32MB is fine for this) and tell it to use the Nginx buildpack.
Change the name of the application in
manifest.yaml
to something unique to you.Now, open the Nginx configuration file. This is a file particular to Nginx: When you deploy the application, it will be copied across to IBM Cloud to define how it should operate. The syntax
listen {{port}}
allows Cloud Foundry to choose its own port for use (so you don’t have to) and substitute it here for Nginx to listen on. Leave it as it is.Next, the configuration file will ensure that HTTPS is being used on the route into Nginx. If not, the request will be rewritten.
Finally, the interesting lines:
location / { proxy_pass http://your_hpvs_public_ip:8080; } location /api { proxy_pass http://your_hpvs_public_ip:5000; }
The
location
block matches on the incoming request to Nginx. More complicated patterns (full regular expression support) are available, but here you can keep it simple. The first block will match any request, which you can assume means they want the frontend component, the website. Thus, you can forward the request on to the Docker container that is listening on port8080
on the server. Note that the path is matched by thelocation
directive, but it doesn’t have to be specified on theproxy_pass
line; the path and any parameters will simply be forwarded on to the server.Next, you’ll match
/api
path requests coming into the Nginx reverse proxy. If someone has made this kind of request, you can assume they want to talk to the backend component whose Docker container is listening on port5000
. Again, the path is matched but doesn’t have to be specified toproxy_pass
, so a request toyour_reverse_proxy.mybluemix.net/api/foobar
will be forwarded on tohttp://your_hpvs_public_ip:5000/api/foobar
.Substitute
your_hpvs_public_ip
for the IP address of your IBM Cloud Hyper Protect Virtual Server instance.
Putting it all together
Given that you’ve already configured a Cloud Foundry org and space from the command line, you can easily deploy this reverse proxy application:
ibmcloud cf push
Once this has finished successfully, it will tell you the domain name that’s been used:
routes: hyper-protect-nginx-proxy.eu-gb.mybluemix.net
Use your web browser again to load that domain (with whatever prefix you chose as the name in your manifest file). You’ll find that it selects and enforces HTTPS, using a certificate from IBM Cloud, and displays the disaster donations website.
Now, add /api
to the end of the domain (for example, https://hyper-protect-nginx-proxy.eu-gb.mybluemix.net/api
). You’ll find your browser now correctly returns the earlier JSON payload…
{
"apiVersion": "v1.0",
"message": "Welcome to the Disaster Funding API",
"status": "200"
}
…and keeps the TLS certificate as it’s still being served over HTTPS; one domain name, multiple backend servers or components responding to your requests.
Earlier, I mentioned being able to customise the domain name that’s defined for this reverse proxy in IBM Cloud. Follow these steps to change it:
Use a web browser to log in to IBM Cloud.
From your dashboard, choose Cloud Foundry apps.
Find the Nginx reverse proxy (by its name) that you just deployed, and click its name:
Click the Routes button, then Edit routes:
Choose or define a different domain to use:
Summary
In this tutorial, you’ve learned what a reverse proxy is, how Nginx can be configured to operate as one, and how to deploy it to IBM Cloud. As an interactive exercise, you created an IBM Cloud Hyper Protect Virtual Server instance and deployed two component applications onto it, before joining it up with the Nginx reverse proxy.
To learn more about the concepts and technologies presented in this tutorial, check out the Related links below and the Resources in the upper right nav.