Securing Realm with Let’s Encrypt
So, you’ve developed an app with the Realm Platform, and you’re ready to go live. Before you hit the publish button though, consider the fact that it’s 2017—your users expect that their data is secure and not being snooped on. Imagine how much a privacy scandal would hurt the adoption of your app! The good news is that it takes only 10–15 minutes to setup proper encryption.
Let’s Encrypt is free and automated—no need to deal with email reminders, copying certificates, or paying fees. What’s not to like?
Before we begin
These instructions apply to setting up a Realm Object Server on a Ubuntu instance. For self-sufficiency’s sake, I’ll include all commands needed to make it work there, but will also link to the official docs if you have a different setup.
To obtain a certificate, you’ll need to have a domain name registered. If you’re hosting your server on a public cloud, Let’s Encrypt won’t let you register a certificate for a DNS with the cloud provider’s top-level domain (e.g.,
Finally, this guide will assume you have a very basic understanding of Linux. If you know what
ls does and how to quit vim, you’re good to go. (If you know how to recompile the kernel, then I’m afraid you’ll get bored with these instructions rather quickly.)
Installing the Realm Object Server
If your server is hosted in a cloud environment, you’ll probably need to open ports
9443; those are used by Realm for
https traffic respectively. Additionally, you’ll need to open
443, as it will be used by Let’s Encrypt to verify domain ownership. If you’re self-hosting, you may need to open them in the built-in firewall:
sudo ufw allow 9080/tcp sudo ufw allow 9443/tcp sudo ufw allow 443/tcp sudo ufw reload
Instructions for other Linux distributions can be found in the Realm Object Server documentation.
After this, setting up ROS is fairly straightforward:
# Setup Realm's PackageCloud repository curl -s https://packagecloud.io/install/repositories/realm/realm/script.deb.sh | sudo bash # Update the repositories sudo apt-get update # Install the Realm Object Server sudo apt-get install realm-object-server-developer # Enable and start the service sudo systemctl enable realm-object-server sudo systemctl start realm-object-server
Again, if you’re using a non-Ubuntu distribution, check the Realm Object Server documentation.
You should now be able to head to
http://ros.myserver.com:9080 and create an admin user.
Now that the server is installed, let’s configure it—fire up your favorite editor (which clearly is vim) and edit
/etc/realm/configuration.yml. There are a bunch of useful configuration options there, but what we care about is the
proxy:https section, which is roughly in the middle of the file. Let’s uncomment the settings and set the certificate paths:
https: # Obviously, we want it enabled enable: true # Paths to the keys we'll obtain from LetsEncrypt later certificate_path: '/etc/realm/keys/fullchain.pem' private_key_path: '/etc/realm/keys/privkey.pem' # Listen to all interfaces, not just localhost listen_address: '::' # 9443 is fine, no need to change that # listen_port: 9443
If you restart the service now, you’ll notice that it fails to start due to configuration errors—the certificate paths are invalid. We’ll fix them in a bit.
# install certbot sudo apt-get install software-properties-common sudo add-apt-repository ppa:certbot/certbot sudo apt-get update sudo apt-get install certbot # fire it up in certonly mode sudo certbot certonly
(Instructions for other Linux flavors can be found on the Certbot website.)
Now, you should be presented with a question—do you want to spin up a temporary server, or use webroot? Unless you already have a web server running on that box, you should probably choose the former.
Next you’ll be asked for domain name(s). Since Let’s Encrypt won’t issue wildcard certificates and you probably don’t want to host your website on that box, you can setup a DNS record for something like
ros.myserver.com and point it to your server. If everything goes well, certbot will negotiate with Let’s Encrypt and place your certificates in
Providing the certificates to the Object Server
Now we have ROS and our certificates, but there are a few more things to do before being able to relax and enjoy our secure communication. By default, certbot will apply severe restrictions on who can read the certificates folder—and that’s a good thing—but those restrictions will prevent ROS from accessing that folder, too. We don’t want to mess with certbot’s permissions structure, so instead we’ll copy relevant certificates to the
First, let’s create the directory:
sudo mkdir /etc/realm/keys sudo chown realm:realm /etc/realm/keys sudo chmod 500 /etc/realm/keys
This creates the folder, changes the owner to
realm (the user under which ROS runs), and sets the permissions to read and execute so ROS can access files within.
At this point we could copy the files manually inside the folder, but that’s not future-proofed—Let’s Encrypt certificates are relatively short-lived (90 days), so you’d need to not only renew sooner rather than later, you’d have to remember to copy the files, which is error-prone. Instead, we’ll prepare a certbot renew hook script that will be executed after successful renewal:
#!/bin/sh set -e for domain in $RENEWED_DOMAINS; do case $domain in ros.myserver.com) # <- Update this with your own server realm_cert_root=/etc/realm/keys # Make sure the certificate and private key files are # never world readable, even for an instant, while # we're copying them into realm_cert_root. umask 077 cp "$RENEWED_LINEAGE/fullchain.pem" "$realm_cert_root/fullchain.pem" cp "$RENEWED_LINEAGE/privkey.pem" "$realm_cert_root/privkey.pem" # Apply the proper file ownership and permissions for # Realm to read its certificate and key. chown realm:realm "$realm_cert_root/fullchain.pem" \ "$realm_cert_root/privkey.pem" chmod 400 "$realm_cert_root/fullchain.pem" \ "$realm_cert_root/privkey.pem" # restart ROS systemctl restart realm-object-server ;; esac done
Here’s the human-readable explanation of the various steps:
- Check that we’re copying the correct certificate (
ros.myserver.com) and avoid touching unrelated certificates.
- Copy the new certificates to
- Set the owner of the copied file to the
- Set permissions to “read” just for the file owner, and “none” for everyone else.
- Restart ROS to make sure it picks up the new certificate.
Drop that in a non-public folder (e.g.,
/etc/realm/keys/) and make sure to make it executable (
chmod 500 /etc/realm/keys/post-renew.sh).
Now, it’s time to make sure everything works as expected:
sudo certbot renew --renew-hook /etc/realm/keys/post-renew.sh --force-renewal
This will force renewal and, upon success, execution of the renewal script. If everything goes according to plan, we should see the new certificates in the
/etc/realm/keys folder, and restarting the ROS service should be able to pick them up. Head over to the browser and verify that you can open
The final step is to automate the renewal so we don’t have to worry about the certificate expiring. Since we’ve verified that our
post-renew script works as expected, we can safely setup a cron job to run the renew command:
sudo crontab -e # choose your favourite editor and paste this at the bottom of the file 0 4 * * * certbot renew --renew-hook /etc/realm/keys/post-renew.sh --quiet
Certbot will only renew certificates nearing expiration, so running it daily is perfectly fine.
That’s it. We now have a secured Realm Object Server instance that will renew and pick up new certificates without user interaction. It’s a one-time setup that is definitely worth the effort to ensure that your users’ data is not tampered with along the wire.