I have a friend who wanted to serve some simple PHP scripts over HTTPS from a Raspberry Pi. He’d seen some benchmarks showing that Apache was a bit of a hog so was trying to use Nginx but was having trouble because none of these apps are in the Raspbian repos.
I’m a total noob when it comes to Linux (I got my first Pi a week or so ago), but it didn’t seem like this should be a complicated setup, so I decided to see if I could quickly get it working. I have plenty of SD cards lying around and my Pi wasn’t doing anything important so there’s nothing to lose.
Goals
The main goal for me was to take a new install of Raspbian (I’m using Raspbian Jessie Lite, but standard Raspbian via NOOBS should be fine too) and render a PHP “Hello World” over HTTPS with a real cert trusted by browsers with minimal effort, while:
- Preferring NGINX or Lighttpd to Apache
- Preferring PHP 7 to anything older
- Getting free TLS certs from LetsEncrypt
- Scheduling renewal of TLS certs via cron
Replacements
If you’re going to use any of these scripts, there are two things littered throughout that you must replace with your own values:
/var/www/html
is the webroot. I’m using the standard location Lighttpd (and Apache!) use out-of-the-box.pi.dantup.com
is the public hostname for the site/cert. This is mine; replace it with your own!
Complications
- The LetsEncrypt client is not available in the Raspbian Jessie repositories (nor debian Jessie)
- PHP 7 is not available in the Raspbian Jessie repositories (nor Debian Jessie or Jessie Backports)
Getting Raspbian
Step 1 is to get a working Raspbian install. I chose to use Raspbian Jessie Lite from here because I tend to run my Pis headless. These instructions should all be the same for standard Raspbian (inc. via NOOBS).
Security Considerations
If you’re going to expose your Pi (or any other computer) to the web, you should consider the security. Someone breaching a device on your network could give them access to other devices inside your network! Some things you might wish to consider doing to your Pi if you’re going to expose it (especially if opening SSH):
- Create your own user and ditch the
Pi
user (at a minimum, change the password to something strong!) - Disable root login over SSH
- Change the SSH port
- Set up unattended security upgrades
I’ve been working on a script that does this (and more) for me when I set up a new Pi. I’m hoping to finish/tidy/blog it over the coming weeks.
Setting up Raspbian
First thing I do when setting up Raspbian is expand the filesystem (you won’t need to do this if using NOOBS, but will if you’ve written a Raspbian .img
) and ensure all packages are up-to-date.
Switch to root shell
Pretty much everything here requires root, so it’s easiest to switch to a root shell to avoid prefixing everything with sudo
.
Installing Lighttpd
This one is pretty painless. Install via apt
and replace the default page with our own Hello World.
At this point you should be able to visit http://raspberrypi/ (assuming you haven’t changed the hostname) and see your Hello World message. It’s a good start, but it’s not HTTPS!
Installing packages from Debian
Because neither PHP 7 nor the LetsEncrypt client are in the Raspbian repos, we need to fetch them from the Debian ones. Before apt
will download things from there, we need to trust them. You should probably confirm these keys (such as by skipping this step, letting the next step fail, and then getting the keys from the error message) rather than copy/paste them from some random guys blog (which wasn’t served over HTTPS) though!
The error you’ll get prior to trusting these keys looks like this:
I don’t know why there are two. Did I mention I’m a Linux noob?
Install the LetsEncrypt Client
The LetsEncrypt client is available from Jessie Backports. We’ll need to add the source to be able to install it from there. My script removes the source at the end (and re-updates the packages; I don’t know if that’s required) since we only want to borrow these packages and not use this for anything more.
Requesting TLS Certs
In order for the LetsEncrypt client to work, it needs to be able to connect to your Pi using the hostname you want the cert for (this is to verify you actually own this domain, or at least, control the web server it points at). This may mean setting up DNS records to point the domain at your Pi and/or forwarding ports from a router (you’ll need port 80 for this step, but may as well also map 443 while you’re at it to save coming back to it later).
Because there’s no automatic module to set up Lighttpd
we need to use the --webroot
method (this means the client will write files into your webroot and LetsEncrypt will connect back and read them). Pass each webroot with -w
and the domain with -d
. You can add multiple sets of these as required.
Remember to replace the webroot and domain with your own!
Setting up TLS in Lighttpd
Lighttpd expects certs to be combined, so we need to concatonate them before we can configure it. Remember to replace your domain in the path (note: this is in /etc/letsencrypt and not your webroot!).
Next we need to add TLS config for Lighttpd. We need to point at the cert we just combined as well as the full chain certificate that will be served up to the client browser. We also disable SSLv2 and SSLv3 for security.
Again, be sure to replace your domain in the certificate paths.
At this point, you should now be able to visit https://raspberrypi/ (assuming you haven’t changed the hostname) and see your Hello World message again. You’ll get a warning about the cert name not matching (since you’re not accessing it via the real domain), but that’s expected. Accessing it via the real domain may work depending on your setup. Hurrah! Encryption!
Installing PHP 7
Like the LetsEncrypt client, PHP 7 is not available in the Raspbian repos. Nor is it available in Debian Jessie Backports. However it is available in Stretch (the next version after Jessie),so we can do a similar thing and get it from there.
Next we need to enable fastcgi
and tell Lighttpd
where to find PHP.
Finally, let’s replace our boring old Hello World with a nice PHP one!
If you’ve done all this right, https://raspberrypi/ (assuming you haven’t changed the hostname) will now greet you from PHP! Almost done…
Automatic TLS Cert Renewal
Not renewing your certificates would be pretty embarassing, so we should make that automatic. We’ll do this via Cron. Cron sends emails with the output of commands, so if you’ve set up emails to be forwarded to a real mailbox (this will be covered in my Pi setup script which I hope to blog in the coming weeks) you’ll get a note each time this runs. We’ll set it to run weekly since by default it only renews certs that’ll expire in the next 30 days, so monthly could cause them to be missed.
Edit: Mike Scalora posted a better version of this that handles multiple domains neatly in the comments :)
That’s It!
I believe that’s everything! If you hit problems please post in the comments and I’ll try to fix them up. Please note that I’m a Linux noob, some (or all) of this might not be done in the best possible way. Again, I’ll make tweaks if people send corrections/improvements :-)