summaryrefslogtreecommitdiffstats
path: root/content/post/how-this-blog-works/index.org
blob: 9cbd4425a18fe9b9e6711b70b320d762569b305d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#+TITLE: Creating Self-Hosted Hugo Blog with OpenBSD
#+DATE: 2020-06-17T21:03:26-04:00
#+DRAFT: true
#+DESCRIPTION:
#+TAGS[]: hugo openbsd
#+KEYWORDS[]:
#+SLUG:
#+SUMMARY:

When creating this blog, there were a couple of factors I kept in mind
while trying to figure out how I was going to set it up. Here's an
approximate list:

- Simple
- Version controlled
- Easy to host on OpenBSD
- Minimal maintenance
- Good integration with Emacs

That's how I came up with what I currently use. Let's walk through how
it works.

* Framework

  The blog engine is [[https://gohugo.io/][hugo]], a static site generator. I chose this over
  something dynamic like wordpress for several reasons.

  First of all, it's very easy to manage, blog posts are just simple
  files written in one of the markup languages hugo supports. Being
  statically generated is also a massive advantage in terms of
  maintenance. With something like wordpress, you have to be careful to
  keep your site and plugins up to date.

  Since there's no dynamic content generation or database involved with
  hugo, the attack surface is dramatically decreased. No possibility for
  SQL injection, PHP RATs, accidental shell access, or hacked
  credentials. The entire site is generated using a single command after
  a new post is created, and then moved to the web server's root
  directory.

  Being all flat files also means the entire thing can very easily be
  tracked using =git= (or maybe [[https://gameoftrees.org/][got]], eventually), in fact that's the
  recommended way to use hugo. There's no fear I'll accidentally delete
  something, as I can always go back to a previous commit and restore
  it.

  Since hugo is written in go, it's trivial to compile on OpenBSD, and
  is actually available directly from the OpenBSD package manager right
  out of the gate.

  Maybe the most important thing to be however, is that hugo natively
  supports org-mode markup. I write all my notes, both personal and work
  related, in org-mode. It makes converting my notes into blog posts
  really easy. It also lets me leverage my existing Emacs setup, which
  comes in handy often. While it's not very well documented, since
  org-mode markup is a bit of a second class citizen in the hugo world,
  it's pretty easy to figure out.

* Prerequisites

  This can be hosted on a very cheap VPS since it only has to serve
  static pages. For OpenBSD hosting I would recommend either [[https://www.vultr.com/][Vultr]] or
  [[https://openbsd.amsterdam/][OpenBSD Amsterdam]].

** Server
  The only thing that's required on the host server is =git=, although
  you could even get away without that if you chose to host your git
  repository elsewhere, like on github.

  #+BEGIN_SRC shell
  pkg_add git
  #+END_SRC

** Local machine
  On the local machine you'll need both =git= and =rsync=. Both might
  already be installed depending on the system you're on. If not,
  check your package manager for details on how to install them. In
  the case of Ubuntu or Debian it would be

  #+BEGIN_SRC shell
  sudo apt install git rsync
  #+END_SRC

  or for Fedora

  #+BEGIN_SRC shell
  sudo dnf install git rsync
  #+END_SRC

* Version Control

  I wanted to try to keep things as simple as possible for this. The
  "origin" for the blog is simply a bare git repository in the =blog=
  user's home directory.

** Setting up the blog user

   First I set up the blog user
   #+BEGIN_SRC shell
   useradd -m blog
   #+END_SRC

   I then placed my public SSH key in its =authorized_keys= file

   #+BEGIN_SRC shell
   mkdir -m 700 /home/blog/.ssh
   cp /root/.ssh/authorized_keys /home/blog/.ssh/
   chown -R blog:blog /home/blog
   #+END_SRC

   I then logged in as the blog user and initialize the bare git
   repository.

   #+BEGIN_SRC shell
   su blog
   cd        # cd with no arguments goes to home directory
   git init --bare blog.git
   #+END_SRC

** Cloning the repository

   Cloning the repository onto my local machine is very easy at this
   point. As long as my private keys are in the =blog= user's
   =authorized_keys=, git will take care of the rest.

   #+BEGIN_SRC shell
   # on my local machine
   git clone blog@lambda.cx:blog.git
   #+END_SRC

   I can now work on the blog as I would any other git repository,
   pulling with =git pull= and pushing with =git push=.

* Web Server

  Since this blog is going to be hosted on OpenBSD, we don't need to
  install a web server, as it already comes with one built in.

  Setting up =httpd= couldn't be easier, the configuration syntax is
  very straight forward. If you would like to see a full breakdown of
  the options available, check out the man page with =man
  httpd.conf=. The example configuration in =/etc/examples/httpd.conf=
  is also a good starting point.

  In this case the simplest configuration would be as follows

  # js chosen for prism.js syntax highlighting
  #+BEGIN_SRC js
  server "blog.lambda.cx" {
      listen on * port 80
      root "/htdocs/blog.lambda.cx"
  }
  #+END_SRC

  Despite how it looks, the =htdocs= folder doesn't reside in the
  system root (=/=) directory. It actually lives in =/var/www/htdocs=,
  and only appears that way because =httpd= gets automatically
  =chroot='ed in =/var/www/= for security reasons.

  For more information about how to set up SSL with Let's Encrypt,
  check out [[{{< ref "post/letsencrypt-on-openbsd" >}}][this post]].

* Using Hugo

  There's not much to say here. Hugo's [[https://gohugo.io/][website]] has good documentation
  on how to get started creating a blog. I'll be covering the
  intricacies of using org-mode with hugo in the future.

* Deployment

  The system used to deploy this blog is incredibly simple, involving
  only =rsync=, =hugo=, and a small shell script.

** Server
  First you have to allow the =blog= user to write to the website
  root. We'll do this by making it the owner of
  =/var/www/htdocs/blog.lambda.cx=.

  #+BEGIN_SRC shell
  chown -R blog /var/www/htdocs/blog.lambda.cx
  #+END_SRC

** Local machine

   This is the script used to deploy the website. It's placed in the
   root of the hugo git repository.

   #+BEGIN_SRC shell
   #!/bin/sh
   set -e

   cd '$(dirname "$0")'
   hugo
   rsync -va --progress --rsync-path="/usr/bin/openrsync" public/ blog@lambda.cx:/var/www/htdocs/lambda.cx/blog
   #+END_SRC

   Going through it line by line:

   - ~set -e~ Tells the shell to exit if any commands fail instead of
     continuing execution. If ~hugo~ has a problem and exits with an
     error, don't sync with the server.
   - ~cd '$(dirname "$0")'~ Changes to the script's directory. This is
     used in case you're running it from somewhere else.
   - ~hugo~ Compile the website into static files located in the
     =public= directory.
   - ~rsync -va --progress --rsync-path="/usr/bin/openrsync" public/
     blog@lambda.cx:/var/www/htdocs/lambda.cx/blog~ This one is bigger
     so I'll break it down.
     - =rsync= A command that synchronizes files between two directories
     - =-v= Be verbose, this is optional but I like it
     - =-a= Stands for "archive": copy recursively, keep
       permissions, etc. See the =rsync= man page if you're curious.
     - =--progress= Show progress, also optional
     - ~--rsync-path="/usr/bin/openrsync"~ This line is very important
       for OpenBSD servers. OpenBSD has its own =rsync= implementation
       called =openrsync=. Without this argument, =rsync= will connect
       to the server, see that the =rsync= command doesn't exist, and
       fail.
     - =public/= Specify which folder we want to sync. The trailing
       =/= is important. Without it =rsync= will copy the folder
       instead of the folder's contents, which is what we want.
     - =blog@lambda.cx:/var/www/htdocs/lambda.cx/blog= Login to user
       =blog= on server =lambda.cx=, syncing files with the
       =/var/www/htdocs/lambda.cx/blog= directory.

   The reason to use =rsync= here instead of something like =scp= is
   that =rsync= won't upload files it doesn't need to, so if 3/4 of
   the files didn't change when you updated the blog, it won't waste
   time re-uploading them.