A Photo API in Python

I started a small project to clean up my personal photo hosting. I'm currently using an app written in PHP, but it's way over my head and does way more than I want or need. So, I'm taking this opportunity to roll my own backend API for photo storage and serving.

I'm building it in Flask and using the Flask-RESTful extension to help with routing, HTTP methods, and overall structure. I'm hoping that if I have a functional backend, I can learn a frontend framework like Vue in a more formal way.

It's nothing fancy, but the bones are starting to grow a little here and there. Right now, I have it returning all references in a database as well as querying by ID directly. Next, I'm going to add some methods to update the photo title and then I'll move on to uploading files directly.

Source code is in GitHub if you want to look. No pretty pictures because all it serves right now is data.

Server Hardening and SSL

Last night, I got [a self-hosted photo sharing site](https://photos.ohheybrian.com) up and running on my raspberry pi 3. You can see more about that process [here](https://blog.ohheybrian.com/2018/11/forget-the-mac-mini-bring-on-the-raspberry/).

Putting it on the real, live Internet is scary. Securing a server is no small task, so I took some steps based on [these tips](https://serverfault.com/questions/212269/tips-for-securing-a-lamp-server) to make sure I don't royally get myself into trouble.

(I have a stinking feeling that posting this exposes vulnerability even more, but _c'est la vie_.)

To start: new user password. Easy to do using `sudo raspi-config` and going through the menus. It's big, it's unique and no, I'm not giving any hints.

As for updating the OS, I have a cron job which runs as root to update and reboot every couple of days. Lychee is [active on GitHub](https://github.com/lycheeorg/lychee) and I've starred it so I'll get updates with releases, etc. I also took some steps to separate the Apache server from the OS.

Putting a self-hosted server online requires port forwarding. That involves opening specific ports to outside traffic. I only opened the public HTTP/HTTPS ports. Several sites say to open SSH ports, but I think that's where I feel very timid. I don't plan on running anything insanely heavy which would require in-the-moment updates from somewhere remote. (There's also the fact that my school network blocks SSH traffic entirely, so there's even less reason to enable it.)

Once the ports were open, I had to find my external IP address and update my DNS Zone records on [Reclaim Hosting](https://reclaimhosting.com). By default, Comcast assigns dynamic IP addresses so they can adjust network traffic. Most tutorials encourage users to request static IPs for home servers, but others say they've used a dynamic address for years without issue. I'll see if I can work myself up to calling.

Anyways, I logged into my cPanel and added an A record for a new subdomain: [photos.ohheybrian.com](https://photos.ohheybrian.com) that pointed to my public IP address. The router sees that traffic coming in and points it at the Raspberry Pi. I tested on my phone and, hey presto, it worked.

Opening HTTP/HTTPS ports came next. It's easy to get unencrypted traffic in and out. But, like the rest of my sites, I wanted to make sure they were all SSL by default. I could't assign a Let's Encrypt certificate through Reclaim because it wasn't hosted on their servers. [The Internet came through with another good tutorial](https://www.tecmint.com/install-free-lets-encrypt-ssl-certificate-for-apache-on-debian-and-ubuntu/) and I was off.

First, I had to enable the `ssl` package on the Apache server:

```
sudo a2enmod ssl
sudo a2ensite default-ssl.conf
sudo service apache2 restart
```

Once it can accept SSL traffic, it was time to install the Let's Encrypt package, which lives on GitHub:

```
sudo git clone https://github.com/letsencrypt/letsencrypt
```

I then had to install the Apache2 plugin:

```
sudo apt-get install python-certbot-apache
```

From there, the entire process is automated. I moved into the install directory and then ran:

```bash
cd /usr/local/letsencrypt
sudo ./letsencrypt-auto --apache -d photos.ohheybrian.com
```

It works by verifying you own the domain and then sending the verification to the Let's Encrypt servers to generate the certificate. The default life is three months, but you can also cron-job the renewal if nothing about the site is changing.

After I was given the certification, I went to https://photos.ohheybrian.com and got a 'could not connect' error, which was curious. After more DuckDuckGoing, I realized that SSL uses a different port (duh). So, Back to the router to update port forwarding and it was finished.

There are several steps I want to take, like disaggregating accounts (one for Apache, one for MySQL, one for phpMyAdmin) so if one _happens_ to be compromised, the whole thing isn't borked.

---

_Featured image is They Call It Camel Rock flickr photo by carfull...in Wyoming shared under a Creative Commons (BY-NC-ND) license _

Forget the Mac Mini, Bring on the Raspberry

This weekend I decided to try and tackle [turning a Mac Mini into a server to host my own photos](https://blog.ohheybrian.com/2018/11/reviving-the-mac-mini/). Well, that turned into a real mess and I abandoned the idea after I had to disassemble the computer to retrieve a stuck recovery DVD. We went all kinds of places together, but this Mac couldn't go the distance with me this time.

So, I grabbed the semi-used Raspberry Pi 3 that was working as a wireless musicbox on our stereo (kind of) and gave it an overhaul. I removed the [PiMusicbox OS](http://www.pimusicbox.com/) and went back to a fresh Raspbian image. (Actually, I only grabbed the Lite distribution because I won't need to go to the desktop. Ever.)

I wanted a basic LAMP (Linux - Apache - MySQL - PHP) stack to run the website, specifically because the end goal was to have [Lychee](https://github.com/LycheeOrg/Lychee) installed and running on a public space. I relied on two _really good_ tutorials to help me through the process.

The first, written by a guy named Richie, is a [full-blown, step-by-step guide](https://pchelp.ricmedia.com/setup-lamp-server-raspberry-pi-3-complete-diy-guide/) on all the software setup. He even uses WordPress as his thing-to-install-at-the-end, so that's a bonus. It's written for non-technical people and isn't just a wall of command line code to type in. He had explanations (why does he always use the `-y` flag on his install commands?) and screenshots of what to expect. Really superb. If you're looking to try setting up a local server (available only on your wifi network) or have students who want to try, this is the place to start.

Once everything was going, I went to the GitHub project and used a quick command download the package into the Pi:

`wget https://github.com/LycheeOrg/Lychee/archive/master.zip`

and then unzipped the project:

`unzip master.zip`

This put all of the source files into the `/var/www` directory on the Pi, which becomes the public space. For updates, I can just use `git pull` in the directory and I'll get those updates automatically. A cron job could even take care of that, so double bonus.

I was able to go to my internal IP address and see the setup prompt. I signed into my MySQL admin and I was off.

CC0 by Brian Bennett

Photos are organized by album and tags, so you can quickly search for items. I uploaded an old photo of my wife, just to see if it would accept files.

CC0 by Brian Bennett

There's another option I need to dig into that says "Upload from Link," but I'm not quite sure what that does yet. In the short term, I can start uploading photos here rather than Flickr.

The second article had some hints about how to get the server visible to the public. Your modem and router take a public IP address from your ISP and convert it into something you can use in the house. So, getting the Pi up with an IP address is easy to do and use, but only if you're at home. Making it publicly available requires two things:

- Some serious guts (this was the part I was most scared about)
- Some IP address and DNS work (potentially)

RaspberryPiGuy, who apparently works for RedHat, has a guide on [taking your server public](https://opensource.com/article/17/3/building-personal-web-server-raspberry-pi-3). I added a couple more packages to help with security, like fail2ban, which blocks an IP address after too many login attempts. I'm also going to split my network one more time so my home computers are sequestered from this little public slice. I found my public IP address on [this site](https://www.iplocation.net/find-ip-address) and then edited my router to forward traffic to the **public** IP (my house) to the **Pi** (the internal network IP).

I was able to use my phone on 4G to go directly to the public IP address and see public photos in my library, so mission accomplished for tonight. The next steps are to do some DNS forwarding so you don't have to memorize an IP address to see pictures. Some other considerations are to get a static IP so those DNS records don't get messed up, but I have to work up to that call to Comcast.

---

Featured image is Looking Through the Lens flickr photo by my friend, Alan Levine, shared into the public domain using Creative Commons Public Domain Dedication (CC0)

Reviving the Mac Mini

My wife bought a Mac Mini toward the end of college that has been sitting in our basement pretty much since we went to Korea in 2009. I've been wanting to do something with it for a while and with Flickr changing its accounts, now seemed like a good time.

I was looking for photo sharing alternatives to Flickr, mostly because I can't afford a pro membership and I'm already over the 1000 photo limit being imposed in January. I came across [Lychee](https://github.com/LycheeOrg/Lychee/), which is essentially single-user, self-hosted photo management. (Check out their [demo site](https://ld.electerious.com/) - it's pretty impressive). My home photo collection could also stand being backed up somewhere more consistently, so my goal is to convert the mini into a self-hosted photo sharing site so I can continue to post out on the web and have a backup at home.

*cracks knuckles*

I set up in the dining room and got started.

I have to say, it was pretty amazing plugging in this computer, which hasn't seen use in nearly a decade, and watching it boot up as if I had used it yesterday.

Macs have [long-had web hosting built right in](http://www.macinstruct.com/node/112). Apache and PHP are included by default and it's easy to install MySQL for databasing. I was hoping to go the easy route and just use the default tools. LOL.

Lychee requires PHP 5.5+. The mini (late 2006 model) has PHP 4.4 and Apache 1.3 installed. No good. I started searching for [ways to upgrade both](https://jeromejaglale.com/doc/mac/upgrade_php5_tiger), but the recommended site with ported versions for old copies doesn't exist anymore.

So, I grabbed another Mac for more efficient Googling. There was also beer.

The best option, I think, is to boot into Linux rather than OSX 10.4. So, I started researching Debian distributions that would work on older hardware. My plan was to wipe the entire hard drive and dedicate it to server resources. When I landed on the Debian wiki, they had a page specifically for older, Intel-based Macs. This line caught my eye:

The oldest Mini (macmini1,1) is typically the most problematic, due to bugs in its firmware. When booting off CD/DVD, if there is more than one El Torito boot record on the disc then the firmware gets confused. It tried to offer a choice of the boot options, but it locks up instead.

That's not good. I have two choices: I can partition the drive to prevent losing the entire machine or I can go for it and hope that the OSX recover DVD I have in the basement still works. (I'll probably partition, just to be safe.)

Luckily, two lines later, the Debian wiki notes that specific builds are now available which only include _one_ boot record, which solves the problem. [A quick 300MB download of the Mac-specific distribution](https://cdimage.debian.org/pub/debian-cd/current/amd64/iso-cd/) later and I'm ready to burn then disk image to a USB drive with [Etcher](https://github.com/balena-io/etcher).

Next steps are to actually do the Debian install.