My Very Own Droplet

My 2019 Cloud-Hosted Web Server

This is one of a series of computer configuration stories, in reverse chronological order. Others are accessible as follows:

  1. 2018 Desktop system apollo
  2. 2017 home server go3
  3. 2014 Predecessor home server go-ng
  4. 2009 home server gorilla
Or, return to the home page for this activity.

Project Motivation

Host a personal project to organize and display a growing collection of bird photographs, using Python, the Django framework, and an underlying SQLite database. Replace a prior site based on static HTML pages and JavaScript gallery libraries, which was limited in search functionality and other capabilities and had become generally "long in the tooth".


I'd recently taken and enjoyed HarvardX's most excellent CS50's Web Programming with Python and JavaScript course, which had augumented my background and practice with several technologies, and realized that the combination of Python, Django, and Bootstrap formatting could provide a powerful and flexible basis for organizing and displaying a collection of bird photographs. Rather than being continuously consumed by coding and other indoor pursuits, I like to get outdoors and enjoy opportunities to collect pictures; nonetheless, I also enjoy the complementary opportunity to integrate them into a development project.


I built the site as a self-contained Django application. A customized version of Django's management GUI provides a convenient means to upload photos and to manage the embedded SQLite database which references them. My customizations to the admin interface include application-specific capabilities like hashing files to support uniqueness checks, calling out to ImageMagick to generate display-sized and thumbnail-sized image versions to be served, and invoking the Python ExifRead library to extract camera-generated metadata. When I migrated my existing images from my predecessor site, the Django shell provided a convenient and powerful platform for scripting the operations needed to build corresponding objects within Django's database model.

On the user interface side, a user can query the database for entries with particular species and/or photos taken in particular years or months. The current query set is maintained in session context, and successive requests can narrow it. For example, an initial request for birds whose name contains the string "yellow" can be filtered to those photographed during months of April, or during April in a particular year. Once a selection is made, navigation buttons allow successive images within the selection to be displayed.

I'd previously discovered the extensive range of DigitalOcean tutorials describing system configuration operations, which helped to place them positively in my mind as I looked at cloud hosting options. DigitalOcean's minimal "droplet" (using their term for a cloud-based unit of computing power; given a meteorological analogy, it makes sense that clouds should be comprised of droplets), with 1GB of RAM and 25GB of storage for $5 (USD) per month, seemed perfect to hold an Ubuntu VM and to accumulate and serve my files. Unless my photos become virally popular (and perhaps not even then), it seems unlikely that I'll exceed the 1TB outbound data transfer limit above which additional charges apply.

I think I made a fine choice; my is now running happily with only about 11% of its available storage in use. DigitalOcean provides nice instrumentation and graph-based displays to monitor droplet resource usage.Even though the sysbench benchmark indicates performance about 8 times slower than my desktop, it seems wholly adequate to serve my small application. Should this become a significant limitation in future, it's possible to expand to a more powerful droplet.

In 2021, after learning from a couple of years' worth of continuing usage, I reopened the code to clean up some aspects of the data model and add a few features. I'd wanted to be able to change the photo within an existing record, as after recropping or other reprocessing. Also, I thought it would be nice to allow a "select more like this" button so that viewing a picture with a particular species could be the basis to enable a selection of other photos of that species. As I write, I've integrated both of these, and am adding a few more while I'm there. For one, a photo is now accompanied by its key shooting metadata. I was surprised to see that the the exif tag for f/stop yields it as a rational number, so that f/8 is the expected "8" but f/6.3 is '63/10". Of course, there's a Python library that converts such fractions. Is there any known computable function that's not computable within an available Python library?

Getting it Running

Using DigitalOcean's documentation where applicable (which covered most configuration needs), I was impressed with the speed with which I was able to configure Apache, Python, and Django to support my application. Once I'd transferred my code and data from my development desktop, revised Django settings to correspond to the file locations to which images are uploaded and served, and adjusted some file permissions, it basically worked. I avoided transferring admin GUI passwords in plaintext by following DigitalOcean's convenient instructions to set up auto-renewing Let's Encrypt certificates, though I found it a bit messy to get them working with an Apache virtual host so as to serve the https address form. Django's documentation seems to discourage serving media files from the same server that serves Django-rendered pages; while this is probably good practice for larger sites, the self-contained approach seems to be working fine at my modest scale.

Reviewing log files as an interested security person, I was "interested" to note the site being scanned starting only moments after its activation. I was glad to be able to apply a DigitalOcean project-level firewall outside the droplet itself to block ports other than http(s) and ssh, but still observe repeated attack attempts on those necessary ports, trying ssh passwords and, e.g., tries to access a long list of php admin files on this site where php isn't even used. I guess that's life for web-facing services today, and this observation left me doubly glad to have hosted my site on a location separate from my home server. I noted and took DigitalOcean's recommendation to use only key-based login access for ssh, disabling password-based logins.

Pros and cons

Pros and cons

Good things

Less good things

What didn't go so smoothly?

What did it cost?

My expenses were mostly in the form of time, well spent as I acquired interesting and valuable skills and knowledge in the project and in the course that led to it. I was glad to support edX with a certificate fee, and am fine paying for a domain registration and $5/month for cloud services to establish a suitable presence for my photos. I used only open source tools, and have been particularly pleased with the PyCharm Community Edition IDE.