Chapter 7. Networking

Even though a PaaS abstracts away much of the networking complexity, there is still a lot you can do with the network on OpenShift. In this chapter we will cover some of the networking you can do to either make your work easier or add capabilities to your application.

WebSockets

One of the hot new technologies in web applications is the WebSocket protocol. WebSockets allow the client to open a persistent connection to the server. In this way, the server can push information to the client, rather than always having the client pull information from the server. This has a whole host of interesting applications and is much more efficient than using long polling, an alternative technique that simulates two-way communication. Examples of applications this could be used for include:

  • Real-time chat applications
  • Fleet or vehicle tracking, or any stream of positions
  • Multiplayer gaming
  • Monitoring applications
  • Real-time auction sites

The prerequisites to using WebSockets are:

  • Your server supports WebSockets. Some examples are:

    • Node.js (JavaScript)
    • Twisted (Python)
    • Socky (Ruby)
    • Socket (PHP)
    • Tomcat7, Netty, and Vert.x (Java and more)
  • Using a browser that supports WebSockets, which appears to be all the current browsers.

From there, the basic flow of using WebSockets in your application is:

  • The client application makes an upgrade request from HTTP to the WebSocket protocol.
  • The server responds that it supports the protocol.
  • Away they go, talking over the WebSocket protocol rather than over HTTP.

Of course this is a simplification, but you get the basic idea. If you want to read a more complete tutorial of how it works there are plenty of good examples; Matt West has written a blog post covering the basics.

At the time of writing, OpenShift provided support for WebSockets but only at a beta level. This means that it works but you have to use alternative ports to 80 to make your WebSocket connections. Specifically, the URL you use to open a WebSocket connection has to go to port 8000 for WS (standard WebSocket) or 8443 for WSS (secure WebSocket). What this means in practice is that you cannot make your connection from the client like this:

//Standard WebSocket
var socket = new WebSocket('ws://insultapp-osbeginnerbook.rhcloud.com');

//Secure WebSocket
var socket = new WebSocket('wss://insultapp-osbeginnerbook.rhcloud.com');

Rather, you need to specify the port number:

//Standard WebSocket
var socket = new WebSocket('ws://insultapp-osbeginnerbook.rhcloud.com:8000');

//Secure WebSocket
var socket = new WebSocket('wss://insultapp-osbeginnerbook.rhcloud.com:8443');

Warning

Please note that when trying to use WebSockets with OpenShift you need to have a server that supports WebSockets. OpenShift currently uses Apache 2.2 to serve content for the default PHP, Python, Perl, and Ruby cartridges. This version of Apache does not support WebSockets, so for any of those languages you would have to create a DIY cartridge or your own language cartridge. Here is an example of an OpenShift DIY that uses Python 2.6 with Tornado (a WebSocket-capable server). There is also an advanced Ruby cartridge that allows you to use WebSockets with Ruby. The only cartridges that support WebSockets out of the box are Node.js, Tomcat 7, and the WildFly 8 Java application server. The version of the Apache HTTP server may change by the time you get this book, so please check on the OpenShift website for the latest information on WebSocket support.

Finally, each WebSocket connection you make to the server counts as a connection for the purposes of autoscaling of your application. Currently on OpenShift, when a scalable app has more than 16 connections on the gear it will trigger a scale-up event, causing OpenShift to spin up a new gear, install the application code on it, and plug it into the load balancer. That threshold includes any combination of HTTP and WebSocket connections.

SSH Port Forwarding

As explained in Chapter 1, all communication with your gear occurs over the Secure Shell (SSH) protocol. One of the great features of SSH is port forwarding, which allows you to securely communicate with your gear and make it appear as if the services on the gear are running on your own machine. The basic idea is that SSH takes ports on your local machines and tunnels them over a secure connection to a port on the remote machine. For example, you can use SSH to take port 9999 on your local machine and have it attach to port 5432 on your gear, which is the port that PostgreSQL listens on. Now when you connect to port 9999 on your local machine, all your traffic to that port will be sent directly to port 5432 on your gear.

Some potential uses of SSH port fowarding are:

  • Attaching your database admin software on your local machine to the DB in your OpenShift application
  • Desktop software such as Excel or QGIS directly using data on the server
  • Having your code on your local machine work with the database in your OpenShift application
  • Attaching the debugger on your local machine to the process running on OpenShift

To give an example, we are going to port forward for all the running servers on our gear and then connect from the local laptop to our PostgreSQL instance on the gear using the psql command-line tool. Even though psql will be running on our local machine, with access to local SQL files, it will actually be talking to the PostgreSQL instance on OpenShift. You could use this same technique to have a development web application on your local machine talking to your OpenShift PostgreSQL instance before you deploy the web application to OpenShift.

Before we begin, you are going to need your username and password for your OpenShift database. If you don’t have this information written down, you can retrieve it with the rhc show command:

[me@localhost insultapp]$ rhc app show
insultapp @ http://insultapp-osbeginnerbook.rhcloud.com/
(uuid: 6e7672676e61676976757570)
-------------------------------------------------------------------------------
  Domain:     osbeginnerbook
  Created:    Mar 14  1:59 PM
  Gears:      1 (defaults to small)
  Git URL:    ssh://6e7672676e61676976757570@insultapp-osbeginnerbook.rhcloud
  .com/~/git/insultapp.git/
  SSH:        6e7672676e61676976757570@insultapp-osbeginnerbook.rhcloud.com
  Deployment: auto (on git push)

  python-2.7 (Python 2.7)
  -----------------------
    Gears: Located with postgresql-9.2, cron-1.4

  postgresql-9.2 (PostgreSQL 9.2)
  -------------------------------
    Gears:          Located with python-2.7, cron-1.4
    Connection URL: postgresql://$OPENSHIFT_POSTGRESQL_DB_HOST:
    $OPENSHIFT_POSTGRESQL_DB_PORT
    Database Name:  insultapp
->  Password:       SLat4aTfsSt1
->  Username:       adminm4rvN42

  cron-1.4 (Cron 1.4)
  -------------------
    Gears: Located with python-2.7, postgresql-9.2

We marked the two lines containing the username and password with a ->. Make note of these because you will need to use them when you connect to your database.

Next we use the rhc port-forward command to have the command-line tools port forward all listening ports over SSH:


[me@localhost insultapp]$ rhc port-forward
Forwarding ports ...
Address already in use - bind(2) while forwarding port 5432. Trying
local port 5433

To connect to a service running on OpenShift, use the Local address

Service    Local               OpenShift
---------- -------------- ---- ----------------
httpd      127.0.0.1:8080  =>  19.66.2.6:8080
postgresql 127.0.0.1:5433  =>  19.66.2.7:5432

Press CTRL-C to terminate port forwarding

You can see from this output that there is a local PostgreSQL server running bound to port 5432, forcing the port-forward command to bind to 5433. Now on a local machine, when we connect to the local loopback address (127.0.0.1) on port 5433 we will actually be connecting to PostgreSQL on the gear. Let’s go ahead and connect:

[me@localhost insultapp]$ psql -h 127.0.0.1 -p 5433 -U adminm4rvN42 insultapp
Password for user adminm4rvN42:
psql (9.3.2, server 9.2.4)
Type "help" for help.

insultapp=# \dt
                List of relations
 Schema |      Name       | Type  |    Owner
--------+-----------------+-------+--------------
 public | long_adjective  | table | adminm4rvN42
 public | noun            | table | adminm4rvN42
 public | short_adjective | table | adminm4rvN42
(3 rows)

insultapp=#

There is no option to enter the password with the command, but it did prompt for one on the second line. We entered SLat4aTfsSt1, and then we were at the PostgreSQL command prompt talking to our server. We executed the \dt command, which lists all the tables in the database, just to show that we are actually talking to the database running on our gear.

Custom URLs

While it is convenient that OpenShift gives you a predefined URL that works out of the box, you may want to use your own URL. This is actually quite easy to accomplish on OpenShift. Before we get to that, though we need to understand a little about DNS names. There are at least two types of DNS records that deal with URLs—A records and CNAME records. An A record can reference any URL, such as insultapp.com or www.insultapp.com, and can take this name and point it at an IP address, like Red Hat does with redhat.com, which points to 10.4.127.150. You have to have an IP address to be able to use an A record. The benefit of an A record is that you can use the root or apex name for your web application, such as http://insultapp.com.

CNAME records are used to take one name, such as www.insultapp.com, and point it to a canonical (authoritative) name, such as insultapp-osbeginnerbook.rhcloud.com. For all your OpenShift applications, the URL provided by default when you create your application is the canonical URL. You would use CNAME records where a provider doesn’t actually give you an IP address; this usually occurs with a content delivery network (CDN) such as Akamai or Edgenet, or with a PaaS such as OpenShift. The drawback to CNAME records is that they can never map a root record to another name. For example, you cannot take insultapp.com and point it to insultapp-osbeginnerbook.rhcloud.com. This has nothing to do with the limitations of OpenShift or your CDN—this is per Internet Engineering Task Force (IETF) specifications.

One of the most frequent questions we get, given this restriction, is, “How do I get insultapp.com to point to insultapp-osbeginnerbook.rhcloud.com?” There are several ways to do this, each with its own trade-offs, but we are going to cover the most common method—using an HTTP redirect to handle getting the user to your web application. With some DNS providers this is called “naked domain hosting.” Let’s cover the basic idea with Insult App:

  1. Go to your DNS provider and make a CNAME record to point www.insultapp.com to insultapp-osbeginnerbook.rhcloud.com.
  2. Do an HTTP redirect from insultapp.com to www.insultapp.com. This can be achieved by:

    1. Hosting your own web server and placing a redirect as the response page at http://insultapp.com.
    2. Finding a DNS provider that does naked domain hosting (also called apex domain hosting). In this case the DNS provider runs a web server for you and does the redirect on its servers.

To finish up the whole custom URL process you need to go to your command-line tools or the Web Console and define what URLs you have pointed to the canonical URL on OpenShift. The process is as simple as:

$ rhc alias add <application> <alias>

For our example, you would enter:

$ rhc alias add insultapp www.insultapp.com

Since this is a very frequently asked question, we are going to list the steps one more time for the whole process:

  1. Purchase a DNS name.
  2. Register a CNAME record with your DNS provider that points a subdomain you just bought (e.g., www.abc.com) to the canonical URL you got from OpenShift.
  3. If you want to point to a primary domain, make sure your DNS provider offers naked domain hosting and point your primary domain at the canonical URL.
  4. Finally, register each URL for which you created a CNAME with an OpenShift alias.

Warning

Although you may be tempted to take the IP address that comes back when you do a dig or nslookup on your OpenShift URL and use it for your A record, resist! OpenShift may change the IP address for your app as part of normal maintenance or other operations. When this happens your DNS entry will be wrong and nobody will be able to get to your site using the A record URL, turning you into a sad panda. Nobody likes a sad panda, so don’t do it.

SSL Certificates

Another common request from developers is to use HTTPS with their applications. By default, all applications on OpenShift can piggyback off the certificate provided for free. OpenShift Online provides a valid certificate for all *.rhcloud.com URLs. This means that if we wanted to point users to https://insultapp-osbeginnerbook.rhcloud.com, the SSL certificate would be valid and the browser would show the connection as SSL secured.

However, as we discussed earlier, you may want to use your own domain name on OpenShift. In this case, the browser would see the URL as https://www.insultapp.com but the certificate would only be valid for *.rhcloud.com URLs, causing the browser to alert the user that there was something wrong with the HTTPS session. The traffic would still be encrypted and the data secure, but the user would see an error with the HTTPS session.

OpenShift provides the ability for you to add your own SSL certs that match the custom domain names. This capability is provided when you enter the paid tier. At that level of service, you can add your own certificates and private key files for any aliases you have.

We are going to assume you have already obtained a Base64 PEM-encoded certificate file (it usually has a .crt or .pem extension). Be sure to obtain a file from a legitimate certificate provider with a signature recognized by most browsers, to avoid warning pop-ups. The private keys to go with the certificate must be in a separate file. If the private key is encrypted you will also need to have the password available.

Once you have all that in hand you can use the RHC command-line tools to upload the certificates. The general form of the command is:

rhc alias update-cert application alias --certificate mycert.pem
--private-key myprivatekey

The reason you have to give both the application and the alias is that an application may have multiple aliases, each of which would require its own cert. From then on, whenever a user hits your web application with an HTTPS URL and one of your aliases, there will be no error in the browser.

Please note that at the time of writing, the custom certificates will not work with the OpenShift secure WebSocket solution. In this situation, the browser will show an error for a secure WebSocket and the user will have to manually accept the certificate.

Talking to Other Services

While there are a lot of services provided out of the box with OpenShift, it also has a robust partner ecosystem for adding even more functionality to your application. You can add things such as caching solutions, monitoring solutions, Mobile Backend as a Service (MBaaS), or Big Data as a Service (BDaaS). One of the services most commonly used with OpenShift is an email service such as SendGrid. Given that the Online servers are hosted on Amazon Web Services, any email sent from the servers will be coming from an Amazon IP, which are blacklisted by most SMTP servers. For this reason, quite a few OpenShift users use SendGrid to send email in their applications.

For example, if we wanted to send insults to people through our app (which would probably break a whole bunch of spam laws), we could do it using this service. Since we like our freedom, we will only talk you through how you would use the service in our application. Since it is so simple, there is actually not much to say: you would just add code like the example SendGrid Python snippet. In that snippet, you are using the SendGrid SMTP servers just like you would use any other SMTP server. There are also examples on that page showing how to use the SendGrid Python library and the SendGrid web APIs to send emails.

We could also use a service for in-application analytics such as Keen IO. It basically lets you send arbitrary JSON to its service, store it, and use an API to analyze it, and then gives you a nice JavaScript API to make visualizations using your data. It has a full set of docs and a simple Python API. By using a partner like this with OpenShift, you can quickly add new functionality without having to learn it all from scratch. This gives you more time to focus on making your application usable and awesome. Don’t forget to see Environment Variables for the preferred method for storing your API key or username and password using the rhc env command.

Addressable Ports

Some OpenShift partner services, other services you might want to use, or other external servers you want to connect to may not talk over HTTP or another standard port like 25 (for SMTP). In these cases, such as when talking to an IRC server, you need to make sure you can connect from your OpenShift gear on an outbound port to your desired external endpoint. OpenShift uses SELinux to control the ability of your app to make outbound connections.

Tip

SELinux stands for Security Enhanced Linux and is a Linux kernel module used to provide a much more secure operating system (OS). You define rules that you want to enforce, such as what processes a user can see or, in this case, which ports a user can bind to. A separate part of the kernel then enforces the rules. Using it properly can produce an incredibly secure OS; misconfigure it and you may have a barely usable system.

SELinux uses a whitelist policy for allowable ports, meaning everything is denied except for explicitly permitted ports. Fortunately, SELinux deals with labels (such as smtp_port) rather than port numbers, so OpenShift operators are able to use, for example, generic_port, which then opens quite a few ports.

At the time of writing, the SELinux policy on OpenShift Online allowed the following named SELinux labels for outbound connections:

mssql_port
mysqld_port
postgresql_port
git_port
oracle_port
flash_port
http_port
ftp_port
virt_migration_port
ssh_port
jacorb_port
jboss_management_port
jboss_debug_port
jboss_messaging_port
memcache_port
http_cache_port
amqp_port
generic_port
mongod_port
munin_port
pop_port
pulseaudio_port
smtp_port
whois_port
jabber_client_port
ircd_port
soundd_port
pki_ca_port
pki_ra_port
commplex_port

If you ever want to test if a port is available for an outbound connection, you can use the telnet command. We will combine it with the timeout command so we are not stuck if it connects to a service and we don’t know how to exit out of the session. We are going to use timeout with the following syntax:

$ timeout -s 9 1 command

This tells timeout to run the following command for up to one second and then run kill 9 on the command if it hasn’t returned back to the console.

Here is an example of running the full command we want over some common ports:

[insultapp-osbeginnerbook.rhcloud.com 6e7672676e61676976757570]\> timeout -s
9 1 telnet 127.0.0.1 6667
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused
[insultapp-osbeginnerbook.rhcloud.com 6e7672676e61676976757570]\> timeout -s
9 1 telnet 127.0.0.1 10
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Permission denied
[insultapp-osbeginnerbook.rhcloud.com 6e7672676e61676976757570]\> timeout -s
9 1 telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Killed

The first command is trying to connect to the localhost IP, which is different from the IP of our gear, over port 6667 (commonly used for IRC). At the end it says “Connection refused,” which means the outbound connection was allowed but the server didn’t accept the connection. This means on OpenShift Online you can go out over port 6667. The next attempt tries to go out over port 10 and gets a “Permission denied” error, which indicates you cannot go out on port 10. Finally, we try to go out on port 80; it is allowed, and we connect to something running that accepts the connection. After one second the Telnet process is killed by timeout.

Warning

Running this command too many times in quick succession is sure to get your application flagged and shut down by OpenShift’s security scripts. Users are protected from developers who put in port-scanning applications trying to hack other people’s applications. These commands are a manual means of port scanning, so if you use them too often, OpenShift will think your application has been hacked. Don’t be naughty.

In the end you can see that while OpenShift restricts some of the networking functionality to protect your application and other users, there is still quite a bit you can do with the network on the platform. Most of the functionality allowed either lets you add new capabilities to your application or enhance your development experience.