How I Built This
13 September 2020
This document attempts to capture the various bits of configuration I went through to get this site into the state it’s currently in.
Server Space
My server is maintained by NearlyFreeSpeech. They do “pay as you go” hosting, meaning that each served request, email sent, or DB query, costs you a certain amount. This works well for me, since I’m sure that for a long time I’m going to have very minimal traffic. An advantage of NFS for me is that they’re very well documented, and while you could in principle just use the FAQ and then go to any provider you like, I think it’s only fair to reward them for this service.
HTTP Server
This site is built with Apache in mind, but for portability I
think that the dependence on HTTP server should be minimal and
explicit. Currently, .htaccess
(which is the only
Apache-specific feature) is used to do two things:
- Set various security headers (described below).
- Remove the filetype suffix, to obtain prettier URLs.
The site will function without these pieces of functionality. This is particularly important for local testing - if you want to run up the stack to check that some CSS change works as you expect, you don’t have to have an Apache daemon running to serve it. You can instead use something lightweight like http.server.
For links to work, it is important that all relative paths on
the site point to filenames and not the pretty URLs. So
you should link to
/notes/website-documentation.html
, and not
/notes/website-documentation
.
Source Code
The full source for this site, including the Markdown source for any of the articles compiled into the site, is freely available on GitHub. I use GitHub currently out of intertia, and at some point will probably switch to a self-hosted Git server. For further details, check out the README.
DNS
I bought this domain through GoDaddy, and my DNS is managed by NearlyFreeSpeech. I think I was required to use NFS, but I can’t remember why.
There is a privacy concern here. When you register a domain name, you must provide an email address and your real address. By default, these are publicly visible in WHOIS records. Your domain provider may be more conscientious than that, though, and redact some of this information. For example, GoDaddy redacts my email address, but keeps my approximate location:
$ whois danielittlewood.xyz
Registrar: Go Daddy, LLC
Registrar IANA ID: 146
Registrant Organization:
Registrant State/Province: London
Registrant Country: GB
Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.
Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.
Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.
Registrar Abuse Contact Email: abuse@godaddy.com
Registrar Abuse Contact Phone: +1.4805058800
You can pay money to get even more privacy, for example RespectMyPrivacy (from NearlyFreeSpeech) will give you completely anonymous forwarding details. This site isn’t really anonymous (my name is all over it), so I’m not going to bother switching at this time.
Email Forwarding
If you want to get in touch with me, the address
admin@danielittlewood.xyz
at the top of the page
will be forwarded
to my personal email. I’ve done this to avoid getting
inundated with spam, or by opportunistic robots trying to check
which services I’m subscribed to. Gmail has a feature which lets
you direct dummy accounts to a single inbox, but that ties you
into their service (whereas I can use any private email provider
I like with this setup).
HTTPS
For information about getting a certificate for HTTPS, visit Let’s Encrypt. The usual situation is that they will give you a “challenge” file which you must put onto your server to prove you own it. My provider has an automatic script which sets up TLS for you, and it is run automatically.
Meta Tags and Templating
Site-wide meta tags are built into pages automatically. This
is done using pandoc’s templating
feature. There are several “ways in” to using pandoc
templates to set metadata variables. To see their default HTML
template, run pandoc -D html
, and find examples in
this site’s source code in the Makefile, as well as in the notes
directory.
Pandoc’s markdown-in-html-blocks
extension allows for convenient inclusion of html features not
native to markdown. For example, you can use the HTML5
<details>
tag like so:
<details>
<summary> This section contains [Markdown] syntax. </summary>
## Examples
You can use all the features of Markdown you like in here.</details>
See the source for more examples.
Security Headers
Check out Security
Headers to see if your site has appropriate headers set.
There are a variety of ways to set them, and I think it’s a
property of your HTTP server. Mine is Apache, so I configure it
with .htaccess
. Check out the
source to see how mine is set up.
Server: This header reveals the type of server your website uses. It can reveal just the engine, or the exact version of the HTTP server. Some people argue that these should be removed, because if an attacker knows your server version then they can exploit vulnerabilities targeted at that particular version. This sounds like security by obscurity, so I don’t find it very convincing. Moreover, in my case it only reveals “Apache”, and removing the header in Apache is disabled by design. So I choose to leave this header as-is.
X-Content-Type-Options: It seems that everyone in the world expects this header to be set to
nosniff
. MIME type sniffing appears to be a feature, but because it exposes some users to malware I guess this feature should be permanently overridden using this header.Referrer-Policy: When hyperlinks on your page link somewhere else, they might send the destination server a Referer header which explains that the link was clicked from your domain. You have a choice of how much to reveal, and I don’t see a good reason to reveal anything. Since this is potentially a privacy concern for users, I set this to
no-referrer
.Content-Security-Policy: This whitelists external sources from which content may be loaded. Since I don’t currently load any content from anywhere, I set every resource type to
self
(i.e. no external sources). Scott Helme has a good explanation of the various values.X-Frame-Options: This determines whether your site can be referenced in an iframe on an external site. If misused, these iframes can be used for clickjacking. I’m not interested in being used as an iframe target, so
DENY
.Permissions-Policy (previously Feature-Policy: Controls a bunch of extra features, and I don’t want any of them. So deny all.
Forced HTTPS redirect: This was harder than I expected. My current understanding is that not only does this redirection depend on your HTTP server, but also on some implementation details, like whether you use a load balancer, to ensure that appropriate headers are set. I could not find anything in the NFS FAQ regarding this, and the standard answers on the web forced me into a redirect loop. Luckily, trying to debug this took me to a StackOverflow thread which contained a solution that worked for me, namely checking the
X-Forwarded-Proto
header.Edit: It turns out that this setting can be configured in my NFS control panel. This was answered in the FAQ (I didn’t see it first time, because the signed out FAQ is smaller than the signed in one). Check with your server provider, if you have one.
Strict-Transport-Security: Using an HTTPS redirect is good, but each time a user connects to you over HTTP, their first request is vulnerable to being intercepted by a man in the middle. This header informs the user’s browser to only connect via HTTPS, and (after the first request) to never ever try HTTP again, until the header expires. This is problematic if your site is only accessible over HTTP. If a user who has received this header tries to access your site, they will be forbidden.
You can pre-empt even this circumstance by telling browsers that you are HTTPS-only. You do this by first enabling the header, and then requesting to be added to the HSTS preload list.
Expect-CT: This is a header which declares whether your (presumed HTTPS) site’s certificate is part of the public Certificate Transparency log. This appears to be a blockchain-type cryptographic tree which can be used to verify that Certificate Authorities are properly issuing certs. As far as I can tell, at the time of writing, all certificates should have this property by default. I do enforce this, with a lifetime of 24 hours. But I don’t specify a URL to report violations to, because I don’t know where to send them.