Samir Parikh / Blog


Originally published on 17 April 2021

Last updated on 17 April 2021

I recently had to migrate my blog VPS off of Azure onto another service provider (I ultimately chose Digital Ocean [affiliate link]). One thing that kept me from making the move earlier was not being sure how to transfer my Let’s Encrypt HTTPS certificates. It took me a long time to enable HTTPS in the first place and the last thing I wanted to do was screw it up. With a deadline fast approaching, I finally decided it was time to move the VPS and figure out how to move my Let’s Encrypt certificates and configuration.

My new VPS is still running FreeBSD like before. Before migrating the Let’s Encrypt certificates, I did some initial setup and housekeeping of my VPS, including:

Once that was taken care of, it was time to tackle the Let’s Encrypt certificates.

The first thing I did was to locate where the critical Let’s Encrypt files, configuration and certificates were stored. I opened up /usr/local/etc/nginx/nginx.conf and found the following lines about half way down the configuration file:

listen 443 ssl; # managed by Certbot
ssl_certificate /usr/local/etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /usr/local/etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /usr/local/etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

That indicated that most, if not all, of what I needed to migrate over is located in the /usr/local/etc/letsencrypt directory. From the home directory of the normal SSH user (to ensure I would later have the right permissions to copy these files off to my local machine), I ran the following:

$ sudo su
# tar -zpcvf letsencrypt_backup_YYYYMMDD.gz /usr/local/etc/letsencrypt/
# tar -zpcvf nginxConfiguration_backup_YYYYMMDD.gz /usr/local/etc/nginx/nginx.conf

These two tar commands zip up the /usr/local/etc/letencrypt directory and the /usr/local/etc/nginx/nginx.conf file. Then, I copied those files to my local machine:

$ scp username@old_vps_ip:/home/username/letsencrypt_backup_20210416.gz .
$ scp username@old_vps_ip:/home/username/nginxConfiguration_backup_20210416.gz .

After which I copied them over to the home directory of the user on the new VPS (again, to ensure I would have the right permissions later on):

$ scp letsencrypt_backup_20210416.gz username@new_vps_ip:/usr/home/username
$ scp nginxConfiguration_backup_20210416.gz username@new_vps_ip:/usr/home/username

You could copy these files directly from VPS to VPS but I didn’t want to manage additional SSH keys between the two virtual servers.

Next, I logged in to the new VPS, and starting from the home directory of the SSH user, executed the following commands:

$ sudo su
# mv letsencrypt_backup_YYYYMMDD.gz /
# mv nginxConfiguration_backup_YYYYMMDD.gz /
# mv /usr/local/etc/nginx/nginx.conf /usr/local/etc/nginx/nginx.conf.bak
# cd /
# tar -xzvf letsencrypt_backup_YYYYMMDD.gz
# tar -xzvf nginxConfiguration_backup_YYYYMMDD.gz
# rm *.gz # clean up tar files
# service nginx restart

These commands make a backup of the existing nginx.conf file, unzip the letsencrypt directory and version of the nginx.conf file from the old server, and clean up the tar files. Finally, we restart the nginx service to allow the settings from our configuration files to take effect.

Once I confirmed that I was still able to connect via HTTPS, it was time to install Certbot to manage future renewals of the certificate. To do this, I installed Certbot via ports:

$ sudo portsnap fetch
$ sudo portsnap extract
$ cd /usr/ports/security/py-certbot-nginx
$ sudo make install clean

To test that Certbot can renew certificates, run the command:

$ sudo certbot renew --dry-run

If you get a successfull test, you can then add the command to your crontab to perform the renewals automatically:

$ sudo crontab -e

At the bottom of the list of cron jobs, you can add a new one:

0       14      *       *       *       /usr/local/bin/certbot renew

The only remaining steps to be executed include:

The DNS changes take about an hour to propagate through the various DNS servers on the internet. I was able to complete these steps without my site ever going offline.