16

Setting up a small web server on Google's Compute Engine — Part 2

qr-code for this page's url

Last time we learned how to get set up with the Google Compute Engine, how to bring up an instance and how to log into it. This time we need to configure the network so the instance can serve data and software so that there is something to serve data.

Setting up the network

By default, all access to your instance is blocked (except for ssh access to log in, of course). This is not very useful for a web server which should be contactable by clients to retrieve web pages.

When we started our instance it was assigned to the default network. Google's model is that you can have multiple networks; each network can contain multiple firewall rules and a machine is assigned to one of those networks which then determines what sort of web traffic can and cannot reach or leave our machine.

For our web server we will set up a dedicated network that will be more lenient and will allow incoming HTTP/HTTPS traffic. And since this is a new network, we also need to add the ssh exception that is in the default network so that we will be able to ssh into our server.

hdurer@home:~$ gcutil --project=myvps addnetwork webtraffic
INFO: Waiting for insert of network webtraffic. Sleeping for 3s.

Table of resources:

+------------+------------+----------+
| name       | addresses  | gateway  |
+------------+------------+----------+
| webtraffic | 10.0.0.0/8 | 10.0.0.1 |
+------------+------------+----------+

Table of operations:

+---------------------------------------------------------+--------+-------------------------------+----------------+
| name                                                    | status | insert-time                   | operation-type |
+---------------------------------------------------------+--------+-------------------------------+----------------+
| operation-xxxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxx-xxxxxxxx | DONE   | 2014-04-15T01:23:45.678-07:00 | insert         |
+---------------------------------------------------------+--------+-------------------------------+----------------+

hdurer@home:~$ gcutil --project=myvps addfirewall httptraffic --description="Allow incoming http" --allowed="tcp:http,tcp:https" --network=webtraffic
INFO: Waiting for insert of firewall httptraffic. Sleeping for 3s.

Table of resources:

+-------------+------------+
| name        | network    |
+-------------+------------+
| httptraffic | webtraffic |
+-------------+------------+

Table of operations:

+---------------------------------------------------------+--------+-------------------------------+----------------+
| name                                                    | status | insert-time                   | operation-type |
+---------------------------------------------------------+--------+-------------------------------+----------------+
| operation-xxxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxx-xxxxxxxx | DONE   | 2014-04-15T01:33:55.777-07:00 | insert         |
+---------------------------------------------------------+--------+-------------------------------+----------------+

hdurer@home:~$ gcutil --project=myvps addfirewall sshtraffic --description="Allow incoming ssh" --allowed="tcp:ssh" --network=webtraffic
INFO: Waiting for insert of firewall sshtraffic. Sleeping for 3s.

Table of resources:

+-------------+------------+
| name        | network    |
+-------------+------------+
| httptraffic | webtraffic |
+-------------+------------+

Table of operations:

+---------------------------------------------------------+--------+-------------------------------+----------------+
| name                                                    | status | insert-time                   | operation-type |
+---------------------------------------------------------+--------+-------------------------------+----------------+
| operation-xxxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxx-xxxxxxxx | DONE   | 2014-04-15T01:55:33.111-07:00 | insert         |
+---------------------------------------------------------+--------+-------------------------------+----------------+

At any point in time you can use gcutil getnetwork webtraffic and gcutil getfirewall httptraffic to check what you have configured.

Next we will have to get us a static ip address so that the server will remain with the same address even if we stop and restart it at some point in the future. This is not strictly necessary, I guess you could implement something that will update your DNS listings from within the instance or have some outside polling going on. But addresses that are in use don't cost anything so there is no loss in getting one.

Google calls static addresses "reserved". As usual, you should read the he docs to get the full picture. Note amongst other things that here we need to specify a region whereas we specified a zone when creating the instance. Zones and regions are different things, a region consists of multiple zones but overall you only have to look up in the docs when to give a zone and when a region. We created our instance in zone us-central1-a so we need to get an address in region us-central1.

hdurer@home:~$ gcutil --project=myvps reserveaddress --region=us-central1 webserveraddress
INFO: Waiting for insert of address webserveraddress. Sleeping for 3s.

Table of resources:

+------------------+-------------+----------+-----------------+
| name             | region      | status   | ip              |
+------------------+-------------+----------+-----------------+
| webserveraddress | us-central1 | RESERVED | 162.222.111.222 |
+------------------+-------------+----------+-----------------+

Table of operations:

+---------------------------------------------------------+--------+-------------------------------+----------------+
| name                                                    | status | insert-time                   | operation-type |
+---------------------------------------------------------+--------+-------------------------------+----------------+
| operation-xxxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxx-xxxxxxxx | DONE   | 2014-04-15T02:02:02.020-07:00 | insert         |
+---------------------------------------------------------+--------+-------------------------------+----------------+

Again, should you ever forget the details of your addresses, you can use gcutil listaddresses and gcutil getaddress <address>.

At this point it might be a good idea to create a DNS entry for your server. This is obviously out of the scope of this tutorial as it depends on how/where you manage your DNS. For the moment I created the name webserver.hdurer.net to point to the address assigned to me.

Now network related things should be set up and we are ready to restart our server with the correct network and ip address. Note that you have to give the actual ip address instead of using the name of the address.

hdurer@home:~$ gcutil \
    --project="myvps" \
    addinstance "webserver" \
    --authorized_ssh_keys="wwwuser:$HOME/cloud/gcekey.pub" \
    --zone="us-central1-a" \
    --machine_type="f1-micro" \
    --network="webtraffic" \
    --external_ip_address="162.222.111.222" \
    --disk="webserver,mode=rw,boot" \
    --noauto_delete_boot_disk
INFO: Waiting for insert of instance webserver. Sleeping for 3s.

Table of resources:

+-----------+----------------+-----------------+---------------+---------+
| name      | network-ip     | external-ip     | zone          | status  |
+-----------+----------------+-----------------+---------------+---------+
| webserver | 10.170.xxx.xxx | 162.222.111.222 | us-central1-a | RUNNING |
+-----------+----------------+-----------------+---------------+---------+

Table of operations:

+---------------------------------------------------------+--------+-------------------------------+----------------+
| name                                                    | status | insert-time                   | operation-type |
+---------------------------------------------------------+--------+-------------------------------+----------------+
| operation-xxxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxx-xxxxxxxx | DONE   | 2014-04-15T02:02:03.040-07:00 | insert         |
+---------------------------------------------------------+--------+-------------------------------+----------------+

Getting the software ready

From now on we need to work on the server:

hdurer@home:~$ gcutil ssh --ssh_user=wwwuser --private_key_file=$HOME/cloud/gcekey webserver
INFO: Zone for webserver detected as us-central1-a.
INFO: Running command line: ssh -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -o StrictHostKeyChecking=no -i /home/hdurer/cloud/gcekey -A -p 22 wwwuser@162.222.111.222 --
Warning: Permanently added '162.222.111.222' (ECDSA) to the list of known hosts.
X11 forwarding request failed on channel 0
Linux webserver 3.2.0-4-amd64 #1 SMP Debian 3.2.54-2 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Apr 15 07:42:04 2014 from 74.125.61.150
wwwuser@webserver:~$ 

All we will need for a minimum viable server is a web server. I personally am used to nginx so let's use that:

wwwuser@webserver:~$ sudo apt-get install nginx-light
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  libpcre3 nginx-common
The following NEW packages will be installed:
  libpcre3 nginx-common nginx-light
0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 634 kB of archives.
After this operation, 1271 kB of additional disk space will be used.
Do you want to continue [Y/n]? 
Get:1 http://gce_debian_mirror.storage.googleapis.com/ wheezy/main libpcre3 amd64 1:8.30-5 [242 kB]
Get:2 http://gce_debian_mirror.storage.googleapis.com/ wheezy/main nginx-common all 1.2.1-2.2+wheezy2 [73.2 kB]
Get:3 http://gce_debian_mirror.storage.googleapis.com/ wheezy/main nginx-light amd64 1.2.1-2.2+wheezy2 [319 kB]
# a few boring lines omitted
Setting up libpcre3:amd64 (1:8.30-5) ...
Setting up nginx-common (1.2.1-2.2+wheezy2) ...
Setting up nginx-light (1.2.1-2.2+wheezy2) ...

Create /etc/nginx/sites-available/webserver with the following content:

server {
        server_name  webserver.hdurer.net;

        access_log  /var/log/nginx/webserver.access.log;

        location / {
                alias    /home/wwwuser/www/;
                autoindex on;
                charset utf-8;
                expires 5d;
                add_header Pragma public;
                add_header Cache-Control "public";
        }

        error_page  500 502 503 504  /50x.html;
        location = /50x.html {
                root   /var/www/nginx-default;
        }
}

Finally, let nginx know about that new configuration and add some contents:

# link that into the enabled sites 
wwwuser@webserver:~$ sudo ln -s ../sites-available/webserver /etc/nginx/sites-enabled/webserver=

# create the directory
wwwuser@webserver:~$ mkdir $HOME/www

# and add simple =index.html= file.
wwwuser@webserver:~$ cat > $HOME/www/index.html <<EOF
<html>
<head>
<title>Testing</title>
</head>
<body>
<h1>It worked!</h1>
<p>My web page running on Google's Cloud Engine!
</body>
</html>
EOF

# and make sure everything is world readable 
wwwuser@webserver:~$ chmod -R a+rX $HOME/www

# finally, reload the server configurations:
wwwuser@webserver:~$ sudo service nginx reload
Reloading nginx configuration: nginx.

On your own desktop/laptop/phone you can now surf to you new server (in my case http://webserver.hdurer.net/ as that was the name I assigned the ip address) and see that sample page created.

Voilà! We're done! I won't bore you with the exact details of how I set up my blogs, but given that they are all static sites, things are very similar to that little test page.