Blogging with Emacs
This new year I took the resolution to produce more content on the Internet,
Always being a passive content consumer is often somewhat frustrating.
I've always been shy to share some of my knowledge thinking it's not worth it as people already know everything.
The truth is everybody starts at different levels and people are glad to find these articles helping them to advance where they're at.
Why I should write
- I started my developer career as a webmaster, I would like to toy with websites again
- Some people believe writing improves memory, I think that maintaining a daily org-roam journal helps structure my daily thoughts
- Like everybody I lookup the internet whenever I don't know something, maybe I should start giving back
- My online presence is very limited, people find homonyms when they look me up it's a bit awkward
Selecting a tool
The landscape evolved a lot since I started my career in 2007,
back in the days people mostly used a CMS involving a scripting language like PHP and storing their data on a SQL database,
hence the LAMP combo made perfect sense.
But very quickly blog articles became trendy, publishers suffered from the HN/Slashdot effects and struggled to keep it online.
Then we found out that running a website using a scripting language exposed the websites to many vulnerabilities and exploits,
you can still as of today find many blogs defaced and left abandoned serving malware.
Requirements
Self Hosted
Content publishing platforms provide interesting functionalities and social features,
the drawback is that somehow, content is not yours, you don't have control over it, the design nor the code.
These platforms enforce tracking with third parties using non free software, I don't want that for my potential viewers
Simple setup
I currently own a small server running nixos. I use it to host matrix synapse and centralize some data using SSH,
it already has some configuration to run a web server only for federation purposes, I could extend its usage for this purpose.
I don't want the articles to be stored in any opaque database, backups should be as easy as copying the files.
In my daily routine I don't keep any file on my local system, all my work is stored on a "dev pod" hosted on a server,
I access it over ssh using TRAMP, either from my local network or the internet very transparently.
If I'm traveling I can very easily snapshot it run it locally when I don't have a good internet connection.
I like this system because it isolates my work from my private life files,
the environment is standard and precisely tailored to my requirements using GuixSD
I would like my blog articles to be stored there as well just like another of my projects.
Ubiquitous access
I would like the software that publishes it to require little to no setup,
the artifacts and any program need to be either part of what I'm already using or very easily accessible.
I want to be able to use it in any place where I have my computer and not having to synchronize the data whatsover.
Performance
I would like something that both publishes my content quickly and generates lightweight html
Extensibility
I want to be able to use something easily extendable, that would fit very easily if I have further use cases
Content Centric
I need something that allows me to focus on the content and not the tool but still use something worth hacking.
Security
The tool shall expose a very limited attack surface, I think that good security starts with limiting your exposure
Why Emacs?
Emacs is ubiquitous, it's available on every OS, you can install it using any package manager, you could find it by default on MacOS.
At least I don't have to install it to try it out.
Emacs is much more than an editor, you can use it to check your emails, communicate over IRC, Matrix…
You could see it more as a platform with its package systems and distributions.
I already use Emacs org mode to produce my documentation at work, I always found the format to be easily editable/readable and provide excellent export
capabilities whenever I need to share it with a non developer audience.
Emacs provides a built-in publishing mecanism https://orgmode.org/manual/Publishing.html, it seems very easy to use,
you just need to define some configuration through a project list.
I set it up like this, I don't know very well elisp so feel free to suggest any improvement to this code, at least it works on my computers:
(defun setup-blogging () (setq org-html-htmlize-output-type 'css) (defun make-project-list () (let* ((src-directory "~/dev/blog/") (staging-directory "/ssh:...:/var/www/gbuisson.com/staging/") (prod-directory "/ssh:...:/var/www/gbuisson.com/") (head-extra (concat "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n" "<link rel=\"stylesheet\" type=\"text/css\" href=\"/org.css\"/>")) (shared-asset-opts `("shared-assets" :base-directory ,src-directory :base-extension "css\\|js\\|png" :publishing-function org-publish-attachment :recursive t)) (shared-opts `("shared" :base-directory ,src-directory :base-extension "org" :recursive t :auto-sitemap t :sitemap-filename "index.org" :sitemap-style list :sitemap-title "gbuisson.com" :author "Guillaume Buisson" :email "guillaume@gbuisson.com" :with-creator nil :headline-levels 4 :section-numbers nil :with-toc nil :with-drawers t :with-author t :html-link-home "/" :html-head-include-default-style nil :html-head-include-scripts nil :html-head-extra ,head-extra :publishing-function org-html-publish-to-html :sitemap-filename "index.org"))) `(,(cons "staging" ,(append (cdr ,shared-opts) `(:publishing-directory ,staging-directory))) ,(cons "staging-assets" ,(append (cdr ,shared-asset-opts) `(:publishing-directory ,staging-directory))) ,(cons "prod" ,(append (cdr ,shared-opts) `(:publishing-directory ,prod-directory))) ,(cons "prod-assets" ,(append (cdr ,shared-asset-opts) `(:publishing-directory ,prod-directory)))))) (setq org-publish-project-alist (make-project-list)) (defun gb/publish (env) (org-publish-remove-all-timestamps) (org-publish env t)) (defun gb/publish-blog-staging () (interactive) (gb/publish "staging") (gb/publish "staging-assets")) (defun gb/publish-blog-prod () (interactive) (gb/publish "prod") (gb/publish "prod-assets")))
I first build a common config map that allows me to derive a specific configuration for both a preview and a PROD environment.
I then set org-publish-project-alist
to define each.
I set some shortcut functions gb/publish-blog-staging
and gb/publish-blog-prod
, they include a workaround for a bug in the caching system,
for some reason it doesn't pickup changes when I edit the articles, it's fine like this but I'll probably get to the bottom of it later.
for both environments I set it to read my article files from my dev pod through SSH with TRAMP and export over SSH again to my very simple webserver running nginx,
its configuration is fairly straightforward:
services.nginx = { enable = true; virtualHosts = { "gbuisson.com" = { locations."/"= { root = "/var/www/gbuisson.com"; }; }; recommendedGzipSettings = true; recommendedOptimisation = true; };
Wrapping up
As you can see the setup is very limited which ticks my "Simple setup" requirement checkbox.
The configuration allows me to override pretty much anything especialy the generation function, that ticks my "Extensibility" checkbox.
The generated HTML is barebone, it has no CSS and loads up very fast, the articles are plain HTML files, so it covers my requirements over performance and security.
Editing plain org mode files allows me to focus on the text extensively so this solution is really content centric.
Finally my system is fully self hosted, I can publish using any emacs instance, it is ubiquitous.