sebastiano.tronto.net

Source files and build scripts for my personal website
git clone https://git.tronto.net/sebastiano.tronto.net
Download | Log | Files | Refs | README

commit 1b69fbdce80f4ee2d46be63be34b4cfb4e4e11d7
parent b473f7ce3895eccaf7691f6fc9296cb3c695a189
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Thu, 24 Nov 2022 00:01:47 +0100

Added blog post(s)

Diffstat:
Asrc/blog/2022-10-19-email-setup/email-setup.md | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/blog/2022-11-23-git-host/git-host.md | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/blog/blog.md | 2++
Msrc/blog/feed.xml | 14++++++++++++++
4 files changed, 516 insertions(+), 0 deletions(-)

diff --git a/src/blog/2022-10-19-email-setup/email-setup.md b/src/blog/2022-10-19-email-setup/email-setup.md @@ -0,0 +1,201 @@ +# Keeping my email sorted (the hard way) + +I have recently made some changes to my email setup. In this post I'll +explain the motivation behind these changes and what I did in practice. + +## Self-hosting? + +When I got my virtual machine up and running at +[openbsd.amsterdam](https://openbsd.amsterdam/) - the one where this +website is hosted - I originally planned to host my private email +server there too. I knew this was probably a hard task, but you know, +everything is hard until you learn how to do it. + +I wanted to do this for a couple of reasons. The main one was to use my +`@tronto.net` email address, but I also liked the idea of staying away +from large internet companies (my main email address was connected to my +Google account). Not that there is anything inherently wrong with using +services from this big companies, but I like the idea of not being too +dependent on them. + +After reading +[a nice tutorial at poolp.org](https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/) +I was a bit discouraged. The guide was well-written, all the steps seemed +doable if taken one by one, and I was happy to have dug into this topic +because I learned a lot. However, an email server apparently consists of +a lot of moving pieces: an smtp server, spam filter, DNS, DKIM... it is +a lot to keep track of. Even assuming that I would be able to set this +thing up AND to keep in mind what each of these pieces does, as soon as a +problem of any kind arises - config-breaking updates? domain registration +expiring? me messing up with my VM and making it unreachable? - I knew I +had to be one to fix the mistake. And I cannot afford to be immediately +available whenever something bad happens. Sometimes I might just have a +full week were I don't have time to fiddle around with smtpd and whatnot, +and I can't afford being unreachable via email for a week. + +## My old setup (until September 2022) + +Having abandoned the idea of self-hosting, I looked for alternatives. I +figured that if my goals were just to use my own domain and stay away +from Google, I could sign up for a smaller email provider that offers +custom domains. It turns out there are a lot of them. After some careful +considerations I decided to go with [mailbox.org](https://mailbox.org). I +like their transparency and privacy focus and the fact that they are +based in the EU. I pay 3€ per month (the 1€ tier does not offer +custom domains) and I am happy with their service. + +Setting up the server side was quite simle. Using custom domains +requires a tiny bit of work, but it was all well explained in the +[FAQs](https://kb.mailbox.org/en/private/custom-domains). + +On my local machine I used (and still use) the amazing +[mblaze](https://github.com/leahneukirchen/mblaze), which is essentially +[MH](https://en.wikipedia.org/wiki/MH_Message_Handling_System) +for [Maildir](https://en.wikipedia.org/wiki/Maildir) folders. +In practice, mblaze is a set of commands to manage emails directly +from the command line, without using a graphical environment or a +[TUI](https://en.wikipedia.org/wiki/Text-based_user_interface) like +[Mutt](https://en.wikipedia.org/wiki/Mutt_(email_client)). This system +is incredibly flexible, check it out if you don't know it! + +Being just a mail user agent, mblaze cannot retrieve or send +email. These tasks can be accomplished by other small pieces of +software: I used [msmtp](https://marlam.de/msmtp) for sending +email and [mpop](https://marlam.de/mpop) for downloading it +from mailbox.org's server. As the name suggests, mpop uses the +[POP3](https://en.wikipedia.org/wiki/Post_Office_Protocol) +protocol instead of the more common +[IMAP](https://en.wikipedia.org/wiki/Internet_Message_Access_Protocol). +The main difference is that POP3 simply retrieves your email, while +IMAP keeps the server and client folders synchronized. There are many +advantages and disadvantages to this choice, I won't go into detail on +them in this post. + +As for my other devices, my local mailfolder is kept in sync with my +server using [syncthing](https://syncthing.net). I also use an amail +client on my phone with IMAP, connected directly to the mail server. + +## Nitpicking + +Since I am subscribed to a couple of high-traffic mailing lists that +I read just for curiosity, it is necessary for me to have an easy way +to download and view regular emails separately from that coming from +mailing lists. + +This was kinda easy to set up with mpop's filters, but my configuration +was a bit of a hack. One disadvantage of this soution was that it +only solved the problem on my laptop(s). On my webmail and on my phone, +my inbox was a complete mess of mailing lists, newsletter and a few +important emails. + +After thinking about it for a while I figured that an elegant solution +would be to set up alternative email addresses for receiving mailing +list emails, like `list@tronto.net`. Then I would manage those different +mailboxes separately. + +Setting the aliases up on mailbox.org was easy, but unfortunately all my +`@tronto.net` address used the same inbox, so I did not solve any problem +at all. I could add some sub-folders and set up filters so that incoming +mail gets sorted out, but the app on my phone could not read sub-folders +and mailbox did not allow top-level folders (or I could not find a way to +create them). Besides, tinkering with IMAP folders was not something +that I found particularly exciting. + +But there was another solution... + +## My current setup (since September 2022) + +I decided to try and redirect the mailing list emails to my personal +server. Configuring OpenBSD's smtp to receive emails from one specific +outside source (my mailbox.org account) and sort them into some local +folders is order of magnitudes easier than setting up a full-fledged +email server. No problems with DKIM, no incoming spam, no nothing. + +It took me a few hours to figure our how to do this, but in the +end it is just a matter of configuring a few filters on mailbox.org +and adding a couple of lines to `/etc/mail/stmp.conf`. + +### mailbox.org filters + +On my mailbox.org webmail I simply set up a filter to redirect any email +sent to `list@example.com` (a made-up name for the mailing list I am +subscribed to) to my private server. No copy of these emails is kept on +the server, so they don't clutter my normal (IMAP) inbox. I risk missing +a few of these emails if my server goes down, but it is a public mailing +list and I can always check the archives online. + +I could not just send these emails to `something@tronto.net`, otherwise +they would simply be taken care of by mailbox - the MX records for my +domain point to their servers. But it turns out you can send mail to +a server using its IP address, as long as the server is configured to +accept such mail. So I set up the redirects to `list@[46.23.91.214]` - +where `46.23.91.214` is the IP address of my server. + +### smtpd.conf + +The second step is configuring smtpd, OpenBSD's default mail server +daemon, to deal with incoming email. + +First of all we need to list the virtual user `list` in +`/etc/mail/aliases` so that any mail sent to it is interpreted as being +sent to my regular user. + +``` +# cat 'list: sebastiano' >> /etc/mail/aliases +``` + +Then we have to change the line `listen on lo0` to `listen on all` +in `/etc/smtp.conf`. + +Then we need to add an `action` and a `match` lines to the same file: + +``` +# cat << EOF >> /etc/mail/smtpd.conf +> action "list" maildir "~/mail/list" alias <aliases> +> match from any for rcpt-to "list@[46.23.91.214]" action "list" +> EOF +``` + +And finally restart smtpd with `rcctl restart smtpd`. + +This does the trick: now all email I receive from the `list@example.com` +mailing list is redirected by my mailbox account to my private server, +where smtpd takes care of sending it to the mail directory `~/mail/list`. + +### No mpop needed + +Once the mail is delivered to `~/mail/list`, I can get it from there +to my laptop in any way I like - for example using syncthing, like I +do for all my important files. In this way the mailing list emails are +regularly downloaded and kept in sync, and I don't need to use mpop to +retrieve them. + +This is quite convenient, one less piece of software to keep track of! +In fact, I can do the same for all other email I receive. I just need +to set up the appropriate rules on mailbox: this time I want the mail +to be sent to `sebastiano@[46.23.91.214]` and *a copy to be kept on the +mailbox.org server*, so that I can easily access it from my phone's app as +well. Then I add two slightly different lines to `/etc/mail/smtpd.conf`: + +``` +# cat << EOF >> /etc/mail/smtpd.conf +> action "seb" maildir "~/mail/inbox" user sebastiano +> match from any for rcpt-to "sebastiano@[46.23.91.214]" action "seb" +> EOF +``` + +And the new setup is ready! + +### Sending email + +I did not change the way I send email: I still use msmtp. + +## Happy now? + +Yes, this new setup works and I am always happy when things work. +Of course, one might make the case that things worked before as well... + +I am happy that I could work my way around a basic smtpd configuration. +Besides being useful knowledge on its own, it may make a second attempt +at self-hosting my email less daunting. I don't know if I am ever going +to try that, though. diff --git a/src/blog/2022-11-23-git-host/git-host.md b/src/blog/2022-11-23-git-host/git-host.md @@ -0,0 +1,299 @@ +# Self-hosted git pages with stagit (featuring ed, the standard editor) + +This is a follow-up to my earlier blog entry +[How I update my website](../2022-08-14-website). + +If you work on one or more personal software projects as a hobby, +chances are you are using `git`. To publish your project online +you may be using a website like GitHub, or perhaps a more +open source friendly alternative such as +[GitLab](https://about.gitlab.com/) or [sourcehut](https://sourcehut.org/). + +But have you considered hosting your repositories, and serving them +via web pages, on your personal server? In this post I am going to show +you how I do it, in the usual minimalist and +not-using-what-I-do-not-understand style. + +You can see the final result on my [git pages](https://git.tronto.net). +The scripts and other files I use to set this up are accessible +[here](https://git.tronto.net/git-hooks). + +## Hosting git repositories on your own server + +This step is quite simple, and you can just follow +[Roman Zolotarev's tutorial](https://rgz.ee/git.html) like I did - adapting +the first few steps to your OS if you are not running OpenBSD. + +To sum it up, you need to: + +1. Create a dedicate `git` account on your server (optional, if you know + what you are doing). + +2. Add your public SSH key to the `~/.ssh/authorized_keys` file of your newly + created remote account. + +3. Initialize a git repository on your server with `git init REPOSITORY`. + +4. Clone it via SSH with `git clone git@SERVER:REPOSITORY`. + +And you are done! If you want to use multiple remotes, for example your private +server and GitHub, you can do so by adding a push-only URL with +`git remote set-url --add --push origin URL`. But don't trust me on this +exact command, I always have to look it up +- you should do the same before running it. + +Now your repositories are online, but how can you make them browsable via web? + +## stagit + +The tool I use to serve my git repositories as static web pages is +[stagit](https://codemadness.org/stagit.html). It is very easy to describe what +stagit does: running it on a git reporitory produces some directories with +a bunch of html files that you can simply move to your www hosting directory. + +After generating the pages you can personalize them by copying your logo, +[favicon](https://en.wikipedia.org/wiki/Favicon) or CSS style sheet. You can +use `stagit-index` to generate +[an index page for your repositories](https://git.tronto.net/). Since everything +consists of html files, you can simply edit them to personalize your git pages +even further - and below you'll see some examples. + +But you definitely do not want to do this by hand every time you push a commit. +Since the pages stagit generates are *static*, they do not update +automatically: you'll have to run stagit again every time. You can automate +this for example by running stagit periodically with cron, but there is an +easier way: +[git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). + +## Git hooks + +By saving suitably named executable files inside your project's +`.git/hooks` directory you can automate any process you want during +certain stages of your git workflow. For example you can use a `pre-commit` +script to run commands before you commit changes, or a `pre-push` script +to do something before pushing a commit. + +The hooks are divided in client-side and server-side. We are interested in +the server-side `post-receive` hook, which is executed on the remote every +time a commit is received. This is the last ingredient we need for our setup: +a simple `post-receive` hook that runs stagit and copies the files it +generates to the appropriate folder will do the trick. + +## My setup + +Throughout the rest of the post I will use the following variables, to be +set at the beginning of the script: + +``` +yourname="Sebastiano Tronto" # Author's name +repo="$PWD" # The full path of the repository +name="$(basename $repo .git)" # The name of the repository +baseurl="https://git.tronto.net" # The base URL for the repository +basedir="/var/www/htdocs/git.tronto.net" # The base directory for www files +htdir="$basedir/$name" # The www directory for the repository +``` + +### Basic stagit usage + +The first thing we want to do is to set up some basic information in the +`owner` and `url` files that stagit is going to use. The hook is run in the +repository's directory, so it is not necessary to specify a full path: + +``` +echo "$yourname" > owner +echo "$baseurl/$name" > url +``` + +Next we prepare the target directory by removing old files and creating +it if necessary: + +``` +rm -rf "$htdir" +mkdir -p "$basedir" +``` + +To make the repository clonable by anyone from the same URL used to +view it, we need to copy the whole directory to the +www directory we have just created: + +``` +cp -r "$repo" "$htdir" +``` + +And finally we can run stagit: + +``` +cd "$htdir" +stagit -l 100 "$repo" +``` + +The `-l` option is used to specify how many commits should be visibile +in the log page. + +For some basic personalization we can choose a different default page (index +file). I like to have the file list: + +``` +cp "$htdir/files.html" "$htdir/index.html" +``` + +And we can use our css style sheet, logo and icon: + +``` +cp $filesdir/favicon.png ./ +cp $filesdir/logo.png ./ +cp $filesdir/style.css ./ +``` + +### Bells and whistles + +I like stagit's simplicity, but there are a couple of things that I want to +add or change: + +* I would like every page to show a simple footer at the bottom of + each page. +* I would like to have a download button so that people who don't use git + can still download my files. This makes sense especially for those + repos that are mostly documents, such as my + [lecture notes](https://git.tronto.net/mathsoftware) or my + [FMC tutorial](https://git.tronto.net/fmctutorial). +* I would like to convert README.md files to html. + +If I were calling stagit by hand after each `git push`, I +could simply make these changes with a text editor. But I want to automate +this! How can we edit files in a shell script? + +Enter `ed`, [the standard editor](https://www.gnu.org/fun/jokes/ed-msg.html). +`ed` is a [line text editor](https://en.wikipedia.org/wiki/Line_editor) +initially released with UNIX Version 1. I am going to talk about it more +extensively in the next episode of my +[man page reading club](../2022-05-29-man/) +series. Without going into detail, `ed` does not show you the text you +are editing in a 2-dimensional windows: instead, it offers you a command +line prompt that you can use to run editing commands, such as `a` to add +text or `p` to print one or more lines of the file. + +This might seems like a totally cumbersome way of editing a file, but +there is one nice side-effect: `ed` is completely scriptable. This means +that if you know exactly what the file you want to edit looks like, +you can write the commands you want to run in advance and feed them to +the editor via standard input, instead of typing them interactively. +This is exactly what we want to do! + +Going back to my stagit setup, say we have a file `bottom.html` that +looks like this: + +``` +<hr class="line"> +<footer> <table> +<tr> <td class="contact"> + Back to <a href="https://sebastiano.tronto.net"> sebastiano.tronto.net </a> +</td> +<td class="hosted"> + Generated with <a href="https://codemadness.org/stagit.html">stagit</a> +</td> </tr> +</table> </footer> +``` + +and we want to insert its content in the file `file.html`, before +the line that contains the closing tag `</body>`. We can use the +following one-liner: + +``` +printf '%s\n' "/<\/body>" i "$(cat bottom.html)" . w | ed -s file.html +``` + +Here the `printf` command is used to feed the tokens `/<\/body>`, `i`, +`$(cat bottom.html)`, `.` and `w` to `ed`. These are going to +be interpreted as: "search for the closing tag `</body>`; +insert the following text until you encounter a single dot on a line: +[contents of the file `bottom.html`] single dot; save." +If this seems obscure, I suggest you read +[`ed`'s manual page](https://man.openbsd.org/OpenBSD-7.2/ed), or wait +for my next blog post! + +The command for adding the download button is similar, after we +generate a zip archive of the repository using `git archive`: + +``` +git archive HEAD -o "$basedir/$name.zip" +printf '%s\n' \ + "/log\.html\">Log<\/a>" i \ + "<a href=\"$baseurl/$name.zip\">Download</a> |" . w \ +| ed -s file.html +``` + +Here I am using backlashes to ignore the newline character, so that +I can use more lines for readability. + +The two code snippets above have to be run for every html file generated +by stagit. To loop over all these files, you can use `find`: + +``` +for f in $(find "$htdir" -name "*.html"); do + [stuff...] +done +``` + +The command to turn README.md files into a formatted html page is a bit +more complicated, but I will try to keep the explanation short, since +this post is already quite long. Feel free to send me an email if you +have questions! + +To have an idea of what the README.md.html file generated by +stagit looks like, you can check out the html of +[this page](https://codemadness.org/git/stagit/file/README.html), +for example (right click and "View page source" or something similar in +most browsers, or `curl [URL]` if you are cool). + +First, since I am using bare git repositories, I need to actually "create" +the original README.md file - instead of using its rendered-as-plain-text +html version generated by stagit - using `git show`. Then we need to +remove from README.md.html all the lines that +are part of the code listing, i.e. all those that contain a `class="line"` +string. The `ed` command to do this is `g/class=\"line\"/d`. Then we +need to remove a couple more lines and finally we can insert the result +of the command `lowdown file/README.md`, which converts the markdown +file to html, into the correct place. The final result is: + +``` +git show master:README.md > file/README.md +printf '%s\n' \ + g/class=\"line\"/d \ + "/<pre id=\"blob\">" d d i "$(lowdown file/README.md)" . w \ +| ed -s file/README.md.html > /dev/null +``` + +### stagit-index + +Just a quick mention to how I use stagit-index, the command used to +generate the index page. +The only change I make from the default configuration is to change +the links to each repository to point to the file list instead +of the log page. stagit-index writes its result to standard output, so +I can simply use `sed`: + +``` +stagit-index /home/git/*.git | sed 's|/log\.html||g' > "$basedir/index.html" +``` + +And that's it. Well, I also copy the style files and add a bottom bar, +and change the title from a `<span class="desc">` to an `<h1>` element, +again using `ed`. If you want to see the details you can check them out +[here](https://git.tronto.net/git-hooks/file/post-receive-stagit.html). + +## Conclusions + +stagit is the perfect minimalist tool to publish your git repository +with a simple, static web interface. It requires nothing more than +an http server capable of serving html files. Static files are also +very simple to customize and tune to your needs. + +I have wanted to make this post for quite some time now, mainly +as an excuse to clean up and document my scripts. I finally had some +time to work on this - even if scattered around multiple days. + +As always, I have tried but failed to keep my post short - I am too +eager to explain everything I know as clearly as possbile! +I hope you enjoyed or found it useful. If you have questions or comments, +feel free to send me an [email](mailto:sebastiano@tronto.net). diff --git a/src/blog/blog.md b/src/blog/blog.md @@ -2,6 +2,8 @@ [RSS Feed](feed.xml) +* 2022-11-23 [Self-hosted git pages with stagit (featuring ed, the standard editor)](2022-11-23-git-host) +* 2022-10-19 [Keeping my email sorted (the hard way)](2022-10-19-email-setup) * 2022-10-01 [The man page reading club: tetris(6)](2022-10-01-tetris) * 2022-09-20 [The man page reading club: sh(1) - part 2: commands and builtins](2022-09-20-sh-2) * 2022-09-13 [The man page reading club: sh(1) - part 1: shell grammar](2022-09-13-sh-1) diff --git a/src/blog/feed.xml b/src/blog/feed.xml @@ -9,6 +9,20 @@ Thoughts about software, computers and whatever I feel like sharing </description> <item> +<title>Self-hosted git pages with stagit (featuring ed, the standard editor)</title> +<link>https://sebastiano.tronto.net/blog/2022-11-23-git-host</link> +<description>Self-hosted git pages with stagit (featuring ed, the standard editor)</description> +<pubDate>2022-11-23</pubDate> +</item> + +<item> +<title>Keeping my email sorted (the hard way)</title> +<link>https://sebastiano.tronto.net/blog/2022-10-19-email-setup</link> +<description>Keeping my email sorted (the hard way)</description> +<pubDate>2022-10-19</pubDate> +</item> + +<item> <title>The man page reading club: tetris(6)</title> <link>https://sebastiano.tronto.net/blog/2022-10-01-tetris</link> <description>The man page reading club: tetris(6)</description>