Compare commits

..

No commits in common. '990cc575e819e8bc33929c60919445ebc0a8c131' and '1677eaeaecb482c581024318ea27a58d4f7915e1' have entirely different histories.

@ -10,11 +10,11 @@ keywords: ["", ""]
summary: "Hosting your own cooklang server is (mostly) easy with the help of systemd and some intermediate-level service configuration." summary: "Hosting your own cooklang server is (mostly) easy with the help of systemd and some intermediate-level service configuration."
showFullContent: false showFullContent: false
tags: tags:
- systemd - systemd
- cooklang - cooklang
--- ---
## Cooklang ## Cooklang
Recently I became aware that [cooklang](https://cooklang.org)'s CLI has a built in `server` [subcommand](https://cooklang.org/cli/help/#server), giving you a web interface for viewing your recipes and generating shopping lists. Recently I became aware that [cooklang](https://cooklang.org)'s CLI has a built in `server` [subcommand](https://cooklang.org/cli/help/#server), giving you a web interface for viewing your recipes and generating shopping lists.
Up until now, I've kept my recipes in [Obsidian](https://obsidian.md) which is great but Markdown has its limitations. The value-add for using Cooklang and its builtin web server is that I can easily build shopping lists for recipes and share them with friends and loved ones with a simple direct link. Up until now, I've kept my recipes in [Obsidian](https://obsidian.md) which is great but Markdown has its limitations. The value-add for using Cooklang and its builtin web server is that I can easily build shopping lists for recipes and share them with friends and loved ones with a simple direct link.
## The systemd unit ## The systemd unit
@ -22,7 +22,7 @@ Starting the cooklang server is very straightforward: `cook server`, or `cook se
`systemd` uses [unit files](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html) to configure resources it's responsible for. There's a lot going on in unit files so I've added as many comments as I could to explain what each lines does. Here, we're configuring a [service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html) which specifically describes a *process* that systemd is responsible for maintaining. `systemd` uses [unit files](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html) to configure resources it's responsible for. There's a lot going on in unit files so I've added as many comments as I could to explain what each lines does. Here, we're configuring a [service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html) which specifically describes a *process* that systemd is responsible for maintaining.
{{< highlight ini >}} ```
[Unit] [Unit]
# Describe your unit. This is displayed in various system utilities for human administrators to understand what they're looking at. # Describe your unit. This is displayed in various system utilities for human administrators to understand what they're looking at.
Description="cooklang web server" Description="cooklang web server"
@ -51,22 +51,22 @@ Restart=always
[Install] [Install]
# WantedBy is part of systemd's dependency-chain configuration. multi-user.target is marked as available when the kernel/OS pass from single-user mode to multi-user mode, effectively meaning that the system is ready to start doing stuff other than bootstrapping the hardware and kernel. In short, "when the machine boots up, start me". # WantedBy is part of systemd's dependency-chain configuration. multi-user.target is marked as available when the kernel/OS pass from single-user mode to multi-user mode, effectively meaning that the system is ready to start doing stuff other than bootstrapping the hardware and kernel. In short, "when the machine boots up, start me".
WantedBy=multi-user.target WantedBy=multi-user.target
{{< /highlight >}} ```
With this unit file in place, my [recipes site](https://cook.ndumas.com) comes to life, with the help of a new block in my caddyfile: With this unit file in place, my [recipes site](https://cook.ndumas.com) comes to life, with the help of a new block in my caddyfile:
{{< highlight Caddyfile >}} ```
cook.ndumas.com { cook.ndumas.com {
encode gzip encode gzip
reverse_proxy localhost:9080 reverse_proxy localhost:9080
} }
{{< /highlight >}} ```
### Cooklang can't handle new recipe files ### Cooklang can't handle new recipe files
Unfortunately, there's a catch. It looks like the cooklang server can't gracefully handle the addition of new recipes; the UI will display the recipe name but throw an error about invalid JSON when you attempt to navigate to that recipe's page. This seems like a pretty egregious bug/oversight but luckily, systemd is exceedingly clever and already has [a solution](https://www.freedesktop.org/software/systemd/man/latest/systemd.path.html) for this baked in. Using systemd path units, you can tell systemd to perform actions based on the existence or modification/deletion of specified files or directories. Unfortunately, there's a catch. It looks like the cooklang server can't gracefully handle the addition of new recipes; the UI will display the recipe name but throw an error about invalid JSON when you attempt to navigate to that recipe's page. This seems like a pretty egregious bug/oversight but luckily, systemd is exceedingly clever and already has [a solution](https://www.freedesktop.org/software/systemd/man/latest/systemd.path.html) for this baked in. Using systemd path units, you can tell systemd to perform actions based on the existence or modification/deletion of specified files or directories.
The full solution involves creating two additional unit-files: `cooklang-watcher.service` and `cooklang-watcher.path`. As above, I'll annotate the (new) directives to explain their functionality. The full solution involves creating two additional unit-files: `cooklang-watcher.service` and `cooklang-watcher.path`. As above, I'll annotate the (new) directives to explain their functionality.
#### `cooklang-watcher.service` #### `cooklang-watcher.service`
{{< highlight ini >}} ```
[Unit] [Unit]
Description=cooklang server restarter Description=cooklang server restarter
After=network.target After=network.target
@ -81,10 +81,10 @@ ExecStart=/usr/bin/systemctl restart cooklang.service
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
{{< /highlight >}} ```
#### `cooklang-watcher.path` #### `cooklang-watcher.path`
{{< highlight ini >}} ```
[Unit] [Unit]
Description="Monitor /home/cook/recipes for changes" Description="Monitor /home/cook/recipes for changes"
@ -97,7 +97,7 @@ PathModified=/home/cook/recipes
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
{{< /highlight >}} ```
### Conclusion ### Conclusion
This is by far the most advanced `systemd` setup I've rolled from scratch and I'm really pleased with how it came together. I don't know if I'll stick with cooklang long-term but from an administrator/operator perspective the tools offered everything I needed to handle all the edge cases. Now I can start converting my recipes from Markdown. This is by far the most advanced `systemd` setup I've rolled from scratch and I'm really pleased with how it came together. I don't know if I'll stick with cooklang long-term but from an administrator/operator perspective the tools offered everything I needed to handle all the edge cases. Now I can start converting my recipes from Markdown.
Loading…
Cancel
Save