Deploying Jekyll to a VPS
Part 2: Security, Monitoring, and Local Deployment
Continuing on part one of the series we’ll increase the server security by disabling password authentication for SSH, add Monit to oversee services, and deploy to the local Vagrant server with Capistrano.
SSH Security
It’s generally recommended that you disable password authentication for SSH to help prevent common brute force attacks. You could also add IP addresses to an allowlist, but key authentication is reasonable enough for us.
We already created and authorized a deploy
user in the previous article. If you’re already deploying remotely and using DigitalOcean you should have authorized your key for the root user, or received a root password. If you are using another provider, please ensure you have authorized your key or have a strong root password.
To disable password authentication we can add the sshd cookbook and customize SSH options in the node file. We just need to add it to our Cheffile
and install it with bundle exec librarian-chef install
.
Now we can add the recipe to the run list and disable password authentication. Note that I’m excluding the other settings from the previous articles.
And we can run the new recipe with the standard bundle exec knife solo cook
vagrant
process.
We can confirm that password authentication is not allowed by attempting to authentication with a password using ssh deploy:@vagrant
. If all went as planned we should see a Permission denied (publickey).
message.
Monitoring
While a Jekyll website may not be mission critical, monitoring is still important to keep it functioning when the unexpected happens. We’re going to use Monit for basic monitoring, a simple and popular solution for system monitoring and error recovery.
We can of course use an existing cookbook, the monit-ng cookbook, to add some basic checks. To start add it to the Cheffile
and install it with bundle
exec librarian-chef install
.
First we need to define our custom cookbook name and dependency.
And the default recipe will define basic process ID checks for the nginx
and sshd
services.
And we need to add our new recipe to the run list. We’re running it last to ensure the processes we’re monitoring are available.
After running the recurring bundle exec knife solo cook vagrant
command to install, we can double check that it’s monitoring properly. Just SSH into the server to stop the web server with sudo /etc/init.d/nginx stop
and it should restart automatically within about 30 seconds. The current status of monitored services are available by running sudo monit status
.
Deploying to Vagrant
We of course need a Jekyll website to be able to deploy. If you don’t already have one, you can generate one by running jekyll new jekyll-vps-website
, with the last argument being whatever name you would like.
Next we need to install Capistrano and a couple of dependencies. We also add jekyll
to install it on the server and therubyracer
for a JavaScript environment. At the time of writing Jekyll requires a JS environment for the CoffeeScript dependency, but it will no longer be a required dependency in the future.
After running bundle install
we can generate the Capistrano structure, including our local stage, with bundle exec cap install STAGES=local
.
Our other dependencies aren’t included by default, so we’ll require them in the Capfile
.
We should also exclude some files and folders from the Jekyll output to prevent them from being publicly accessible in the future.
Now we can customize the config/deploy.rb
file with our custom settings and actions for building and deploying the website. It’s a decent chunk of code, so I explain each section in comments.
Instead of having to commit to a branch, push to a remote, and then deploy a branch on a local server we’re just going to package and upload the directory content to the local server. It allows you to test changes in a “production” environment much faster. To do so we need to define a custom strategy. It’s a rather large class so I’ve commented the code heavily.
Lastly we’ll update our local stage to define the server, use the file strategy for deployment, and optionally include custom Jekyll configuration.
We should now be able to deploy by running cap local deploy
. It will take a minute the first time as it needs to install dependencies. After the website generation completes you should see your website at localhost:8080.
Summary
We now how the minimal components needed to deploy a Jekyll website to a Vagrant box. See the jekyll-vps-server repository for the complete Chef source code, with the part-2 branch being specific to this article. The website source code is available in the jekyll-vps-website repository, with the part-2 branch being relevant.
In the next part we’ll create and deploy to a DigitalOcean server to have a production version available. E-mail me if you have any tips, comments, or questions.