The first two things you will need to setup your blog is a domain name and a server (either self-hosted or a vps). I'm not going to go into depth on setting those up in the blog entry as there are many ways to do it, but I chose to buy jkeyne.dev
from Namecheap and I got a server from Linode.
Once you have those setup, you'll want to install nginx
and certbot
. Nginx is the service that will actually serve webpages, and certbot allows you to get SSL certificates from Let's Encrypt.
Once you have nginx
installed, most of your configuration will be done inside of /etc/nginx/sites-available/
. There's a default
site in there feel free to copy that or modify it, but I just made a new one (I called it blog
but you can call it anything). Make your config file look something like this:
server {
server_name jkeyne.dev 139.162.116.200;
root /var/www/blog;
index index.html;
try_files $uri /index.html;
listen 80;
}
Edit the server_name to be your domain name and ip address. Set the root to the folder you want to store the webpage in. And, set the index to whatever file you want opened by default.
Once you have this basic config set, you have to enable it by running (replace blog with whatever you called it):
# ln -s /etc/sites-available/blog /etc/sites-enabled/
Now you have to reload nginx by running
# systemctl restart nginx
You can test if you have everything setup correctly by opening your site in a web browser. If you happened to already have started your index file then you should see that. Otherwise you should get a 404 error. If you get either of those results you can move onto the next step.
Now that you have your server working, you can get a SSL certificate easily by using certbot
. Make sure you install python-certbot-nginx
to be able to use the nginx
plugin that will automate most of the work.
Then you can just run certbot --nginx
and get a screen similar to:
# certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: jkeyne.dev
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1
Then you'll select if you want to redirect HTTP to HTTPS (I generally select yes)
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
When your done you should see something similar to:
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/jkeyne.dev/fullchain.pem. Your cert will
expire on 2020-09-23. To obtain a new or tweaked version of this
certificate in the future, simply run certbot again with the
"certonly" option. To non-interactively renew *all* of your
certificates, run "certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Now you can test going to your site again and you should notice that you've been redirected to the https version of your site and in Firefox or Chrome you should see a lock icon indicating that the site is using encryption.
You should also add a cronjob for renewing the cert automatically. This can be done simply by running crontabe -e
and adding this line which will automatically renew any certs at 1:01 AM on the first day of every month:
1 1 1 * * certbot renew
There are many tools you can use to make a blog. Here's a list a of a few before I go into the choice I made.
Of those tools I've only actually used pelican before, and while it worked well, I wanted to try something different this time. I also tried hugo but didn't get it to work out of the box, so I didn't use it.
I ended up going with a random tool called cobalt. It's a very simple static site generator written in rust.
All of the actual setup is done on your local machine, at the end I'll show you how to upload it to your server. Also this is basically just a summary of the official quick start guide so feel free to check there if this becomes outdated. Also check the docs if you want to learn more.
First things first, you have to install cobalt.
cargo install cobalt-bin
This will take a while since cargo compiles it from scratch. You can also check the releases from GitHub or run this oneliner from their site
curl -LSfs https://japaric.github.io/trust/install.sh | sh -s -- --git cobalt-org/cobalt.rs --crate cobalt
Once installed, just make a new directory, cd
to it, and run
cobalt init
This makes a few new files and folders in the directory:
_cobalt.yml _defaults/ index.md _layouts/ posts/
_cobalt.yml
is the config file_defaults/
is where templates for new pages and posts are stored_layouts/
is where you store the liquid HTML templates are storedindex.md
is the main page which will link to the postsposts/
is where posts are storedSince cobalt initializes with some example content, you can run:
cobalt serve
This will compile the markdown files into HTML, check for new changes to recompile, and serve a local web server to preview it. Just point your browser to localhost:3000
to preview it.
To make new content we will use the cobalt new
command. However, where you are in the structure determines what type of content the new
command will generate. If you are in the root of the directory (where index.md
and the config files are), then it will make a new page
. If you are in the posts/
directory, it will make a new post
. Posts are a special type of page. Posts can be stored as drafts and can be more easily referenced from other pages.
I would recommend only having the index.md
page, and having any new content be posts. To make a new post, you have two options
cd posts/; cobalt new 'Title of the post'
or
cobalt new 'Title of the post' -f ./posts/
Then you can open the markdown file in your editor of choice and write your content. But, by default new posts are saved as drafts and won't appear in the preview you setup earlier. In order for posts to show up in the preview run:
cobalt serve --drafts
You can also look into using data files to store data as yaml, json, and toml files and then reference them in your posts and pages.
Once you're happy with the content, you publish it via:
cobalt publish posts/title-of-the-post.md
This will add two things, one the current date and time as the published date, and will mark it as not a draft. It will also change the file name to include the published date.
In order to customize the layout of your blog, you will have to edit the liquid templates in _layouts/
. There are many options you can use to customize the layout. I would highly recommend looking at the liquid docs and at the cobalt variables you can use.
You can also add CSS files and other so called assets by placing them in the root directory. They will automatically be copied to the root of the website.
This is really a matter of personal taste, so I won't provide much input here (also I can't embed liquid in this doc without cobalt building it). But here's a few tips:
page.categories | join: " "
in order for it to display correctly instead of just page.categories
This page documents some ways of deploying your files to a server, but I'll cover how I do it as well.
First make sure that you've published your content, are happy with the themeing, and that you've freshly built it to make sure it will work (cobalt serve
will also constantly build it, so building it may be redundant in some cases)
cobalt build
Then you have to upload it to your server. I use rsync
to accomplish this:
rsync -aPv --delete ./_site/ root@jkeyne.dev:/var/www/blog
A few things to note about this command:
_site/
as the trailing slash, otherwise you copy the folder _site
and not the contents. In other commands you would refer to the contents like _site/*
, but with rsync
you just use _site/
--delete
means it will delete any files on the remote server that don't exist locally, this could be non-ideal so feel free to remove it, and make sure to use -n
or --dry-run
first to make sure it will operate as expectedYou can automate this pretty easily with a Makefile:
ARGS=-aPv --delete
EXCLUDE=Makefile
SRC_DIR=./_site/
SSH_HOST=jkeyne.dev
SSH_USER=root
TARGET_DIR=/var/www/blog
all:
cobalt build
rsync $(ARGS) --exclude="$(EXCLUDE)" $(SRC_DIR) $(SSH_USER)@$(SSH_HOST):$(TARGET_DIR)
Now you should have your blog all setup for the world to see.
One last thing I want to point out is that cobalt
also manages an RSS feed for your blog. You can find it at /rss.xml
, eg. https://jkeyne.dev/rss.xml.
edit (2020-06-26):
I found a very easy way to get some basic view counts for static websites without adding any javascript. goaccess is a very simple tool you can install on your server. Once installed you can simply run it and point it to an access log file and it will break down view counts per page on your server (the -c
option will prompt you to select a log format).
# goaccess /var/log/nginx/access.log -c
You can also generate html reports either as one time reports, or as an updating report
# goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED
# goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED --real-time-html