Your Homepage on Google AppEngine

A while ago I ranted and raved on how free email services look unprofessional. I recommend Google Apps as a very inexpensive solution. You get a professional looking email address, Gmail, Google Calendar and free home page hosting via Google sites for as little as $10 a year (or free if you already own a domain).

Of course since then I realized that using Google Sites to create your homepage also looks unprofessional to a degree. It’s cool that you have your own domain that ends in your last name, but as soon as someone sees the “Powered by Google Sites” blurb on the bottom of your page, all the respect you might have gained fades away. At least if you at some point claimed to know a thing or two about web design. If you are looking for a job in or around web related technologies you probably shouldn’t use a free service that forces you to build simple static pages using WYSIWYG interface. You just don’t do that.

So let’s review:

  1. You already own a nice domain
  2. You have already signed up for Google Apps like I told you
  3. Now you want a nice looking personal home page that is not powered by Google Sites
  4. If possible, you still want to host it on the Google Cloud and for free

Pretty tough set of requirements to meet, but I do have a solution for you. It’s called Google App Engine which as you may or may not remember is one of my favorite things on the interwebs.

But Luke, isn’t App Engine only for… You know… Apps? Yes, it is. But I have skimmed through their terms of service and I couldn’t see any language that would suggest that you are NOT allowed to use it for personal home pages. Besides, you could argue that a home page could be considered as an app with a limited scope – ie. one that dynamically serves information about you to the readers.

App Engine is in fact perfect environment for simple semi-static home pages since you get:

  1. Cloud hosting which is fast and very scalable
  2. Python back end scripting
  3. Django templates
  4. A simple database back end

Which means you can use server side includes or create nice looking template, and then just inject content into it. In other words, you can make this page the right way, make it as simple or as complex as you please and you will have plenty of space to grow and add features. For example at a later date you can actually decide to host a simple forum or a blog there. You get much more bang for a buckthan on Sites.

I will show you how to get started. First, register an app and call it something. It doesn’t really matter what you call it because your readers won’t ever see that name once you link it up to your Apps domain.

Next, download the development environment. Now you are ready to create an app. You can go for something really simple, or leverage Python and Django to build something more robust. If you just want a simple static home page, head on over to Charles Engelke’s blog to see how to set it up.

I decided to create something a little bit more complex, that will allow me to grow and expand my home page much more easily. Besides, I am firm believer that you can’t really design a good looking web page without using includes. It just doesn’t work. So even when when I have no server side includes I cheat and use Javascript to simulate them.

Anyway, to start you need to create a app.yaml file – here is mine:

application: your-app-name
version: 1
runtime: python
api_version: 1
 
handlers:
- url: /static
  static_dir: static 
 
- url: /.*
  script: main.py

First line is where you put the app name you defined during registration. The rest of that paragraph is standard boilerplate. I also define two handlers. One is for static directory where I will keep static files such as style sheets, images and etc. The second will define the file main.py as the main handler for my application… Er.. Homepage.

Now let’s define main.py:

import os
import re
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
 
class MainPage(webapp.RequestHandler):
   def get(self):
 
      p = self.request.get('p');
 
      if re.match("^[A-Za-z0-9_-]*$", p):
         if p:
            page = p + ".html"
         else:
            page = "main.html"
 
         if not os.path.exists(page):
            page = "404.html"
 
         if p = "index":
            page = "404.html"
 
      else:
            page = "404.html"
 
      template_values = {
         "page" : page,
      };
 
      path = os.path.join(os.path.dirname(__file__), 'index.html')
      self.response.out.write(template.render(path, template_values))
 
application = webapp.WSGIApplication([('/', MainPage)],debug=True)
 
def main():
   run_wsgi_app(application)
 
if __name__ == "__main__":
   main()

Hold your horses, I shall explain this in a second. First let’s just create a simple Django template:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <meta http-equiv="content-type" content="text/html; charset=utf-8" />
   <title><!-- put title here --></title>
   <link href="/static/style.css" rel="stylesheet" type="text/css" media="screen" />
</head>
<body>
   <div id="header">
      <!-- put your header here -->
   </div>
 
   <div id="content">
      <!-- this is where content will be loaded -->
 
      {% if page %}
         {% include page %}
      {% else %}
         {% include "main.html" %}
      {% endif %}
 
   </div>
 
   <div id="sidebar">
      <!-- put sidebar stuff here -->
   </div>
 
   <div id="footer">
      <!-- put footer stuff here -->
   </div>
</body>
</html>

As you can see, there is a hole in the middle of the template where dynamic content will be loaded. The content is determined at run time, by evaluating the “p” variable passed via GET request in the main.py handler. If I visit the page without passing in anything via GET the template will import the file “main.html” which should be in the same directory as the template and the python script (ie. not the static directory – you actually don’t want these things web-readable).

If I use URL like http://yourdomain.com/?p=about then my script will attempt to locate about.html and import it. If it doesn’t find it, it will display 404.html instead. Incredibly simple and yet functional. It allows you to add as many static HTML pages as you need without ever having to redefine the handlers or ever changing the template.

Yes, there are probably better ways to do this, but this took me 5 minutes to set up and it works reasonably well and allows me to have a page with multiple sub pages, all using the same template and the same handler.

Last thing you need to do, is to connect your App Engine site with your Google Apps account. You can do it directly from the App Engine control panel. Google have a very detailed setup instructions with screenshots available so I don’t think I need to repeat that stuff here. It’s easy, and it will take you 2 minutes, tops. Once you are done, you will be all set. Your AppEngine app will now show up on your Google Apps Dashboard. Btw, Google really needs to do some re-branding – Google Apps and Google AppEngine are just way to similar names for these two very different services.

You can see this very setup in action by visiting my personal page. Also note that it loads like 200% faster than this very blog and it is hosted for free on App Engine. Thanks for nothing Dreamhost!

Yes, this is much more complicated that setting up Google Sites web page. But it does give you more credibility, and does allow you to show off your web design/scripting skills and have a much more interactive website. It also allows you to add more dynamic features, widgets and all kinds of bells and whistles to your site later on.

This entry was posted in programming and tagged , . Bookmark the permalink.



15 Responses to Your Homepage on Google AppEngine

  1. mcai8sh4 UNITED KINGDOM Opera Linux Terminalist says:

    Excellent post!! I love learning new stuff like this. Unfortunately I don’t have any need for web presence – I have my own little server in my living room hosting a quick gallery2 site – thats all I need. Coupled with a no-ip.org address, I’m sorted.

    I’ll certainly keep this in mind – looks like a fun project… once I’ve finished with my Nerdkit (if you already haven’t… check it out).

    Once again, thanks for the top post!!

    Reply  |  Quote
  2. Luke Maciak UNITED STATES Mozilla Firefox Ubuntu Linux Terminalist says:

    [quote post=”2877″]I’ll certainly keep this in mind – looks like a fun project… once I’ve finished with my Nerdkit (if you already haven’t… check it out).[/quote]

    Ok, I’d love to but… What exactly is Nerdkit and how do I check it out?

    Reply  |  Quote
  3. Luke Maciak UNITED STATES Mozilla Firefox Ubuntu Linux Terminalist says:

    @mcai8sh4: Oops, never mind. You mean these things, right?

    Pretty cool stuff, I may need to check these out indeed!

    Reply  |  Quote
  4. Nice tutorial.

    But you should really add some validation to the “p” param, since the code above allows to load any arbitrary *.html file.
    E.g., add a regular expression to only allow letters and numbers in the name.

    Reply  |  Quote
  5. mcai8sh4 UNITED KINGDOM Opera Linux Terminalist says:

    yeah, thats what i meant :) I should have linked it, but people seem to forget just how lazy I am.
    I’ve been playing around with it for a week now – good fun and GREAT support! I thought it’d be a good excuse to re-learn my c programming.

    Anyway, back to topic…

    Reply  |  Quote
  6. Luke Maciak UNITED STATES Mozilla Firefox Ubuntu Linux Terminalist says:

    @Daniel Hahler: Good suggestion. See the updated code above. How is that?

    Your tip also allowed me to get rid of a nasty recursion use case which happened when p=index. Phew!

    Anyway, any suggestions to improve this code are greatly appreciated.

    Reply  |  Quote
  7. I’d use “+” as modifier (instead of “*”), since you want at least one character before “.html”.

    For the “index” recursion, I’d default to main.html though for “index”. But OTOH, that would be to pages with the same content – not good. After all, it’s fine.

    (btw: it sucks that you have to enable JS for posting comments)

    Reply  |  Quote
  8. Pingback: Terminally Incoherent » Blog Archive » Running a Blog on Google Appengine UNITED STATES WordPress

  9. Hi, thanks for this post!

    I used another way to get dynamically named pages, using the path attribute of the request object as following :


    page_name = self.request.path.split('/')[-1]

    An example of call is :


    http://myapp.appspot.com/pages/my_page_id

    and retrieve information about my_page_id’s page from the DB. This way you dont need to have physically your pages on your file system.

    Hope this help others fellows,

    Cheers

    Thierry

    Reply  |  Quote
  10. Michele ITALY Mozilla Firefox Windows says:

    Very inspiring post!
    One question..can you explain how did you configured your domain http://www.maciak.net/ to point your application on google app engine ?
    Are you using google apps?

    thanks
    Michele

    Reply  |  Quote
  11. Ashwin INDIA Google Chrome Windows says:

    how can I call my personal web page from google blogger? If I get input from user, where I will store my data?

    Reply  |  Quote
  12. Sam2 NETHERLANDS Google Chrome Windows says:

    i followed your tutorial until i got to where i have to start doing codes in the python sdk.
    i need some help in setting it up properly.
    i have registered app in google.

    Reply  |  Quote
  13. Thanks for your post. I am new at python and this will be a big help.

    Reply  |  Quote
  14. Samsul INDONESIA Mozilla Firefox Windows says:

    Thanks for the post, I’m planning to host my blog on Google App Engine. Trying my first shot with Bloog :-)

    Reply  |  Quote
  15. How do you handle redirecting maciak.net over to http://www.maciak.net? Is that something you set up in godaddy?

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>