Ghost is pretty great. Simple markdown language for posts, lightweight, and self-hosting allows me to keep costs down and lets me customize some things. However, it also feels a bit goofy when you try to customize some things. One of these was adding a security.txt file.

Per the latest draft:

security.txt is a text file that SHOULD be located under the /.well-known/ path ("/.well-known/security.txt") [RFC5785] for web properties. If it is not possible to place the security.txt file in the /.well-known/ path or setup a redirect, web-based services MAY place the file in the top-level path as a fall back option.

I wanted to place it under both the root and /.well-known/, as I feel like not everyone checks, or knows to check, /.well-known/, yet that is where it should be.

There's a few caveats to doing this on a self-hosted version of ghost.

  1. The /.well-known/ and root web directories are under completely different trees in the file system.
  2. Symlinks are not allowed in the root web directories
  3. Each Ghost update creates a new web directory.

First, the easy one. /.well-known/ is static and can be found at /var/www/ghost/system/nginx-root/.well-known/. Unlike the root directories, this one won't be changed or modified. Simply place your security.txt file (and anything else, such as your gpg key) in this location.

Now for the slightly trickier one. The root of the web directory is going to reside under /var/www/ghost/versions/1.23.1/content/themes/casper/ with 1.23.1 being the current Ghost version as of this writing. When the next update comes along, the root of the web folder will change to 1.23.2, or 1.24.0, or whatever other version they jump to. I would prefer to use symlinks for this area, so if I update the version in /.well-known/, it will automatically update here. However, Ghost will throw an error if there are symlinks in this location.

My solution was to write a quick script to loop through these directories and provision my security.txt file into any version directory that exists. This can then be run whenever you update versions, on a cron job, or whatever other method you prefer. Note that the code below does have some output so I know it's going into the correct folders. Comment this out if it's running unattended.

#!/bin/bash

for f in /var/www/ghost/versions/*; do
	if [ -d ${f} ]; then
		#echo $f
		dir="$f/content/themes/casper"
		echo "Provising security.txt files in $dir"
		
		# I'd use symlinks, but Ghost doesn't like them and will refuse to start...
		# "Theme errors Symlinks in themes are not allowed"

		cp /var/www/ghost/system/nginx-root/.well-known/acknowledgements.txt $dir/acknowledgements.txt
		cp /var/www/ghost/system/nginx-root/.well-known/gpg-key.txt $dir/gpg-key.txt
		cp /var/www/ghost/system/nginx-root/.well-known/security-policy.txt $dir/security-policy.txt
		cp /var/www/ghost/system/nginx-root/.well-known/security.txt $dir/security.txt
	fi
done

And tada! There are now a security.txt and other associated files running under:
https://nullsec.us/security.txt and https://nullsec.us/.well-known/security.txt