I experimented with several ways to run my services:
- “regular” systemd services (
services.glance = { ... };
) - nix containers (
containers.glance = { ... };
) - podman containers (
virtualisation.oci-containers.containers.glance = { ... }
)
and I must say I’m starting to appreciate the last option (the least nixos-y) more and more.
Specifically, I appreciate that:
- I just have to learn the app/container configuration, instead of also backwards-translating from their config into the various nixos options (of course the
.yaml
or whatever configuration files are still generated from my nixos config, I just do that in a derivation instead on relying on a module doing it for me) - Services are sometimes outdated in nixpks (even in unstable - and juggling packages between stable and unstable is yet another complication)
- I feel like it’s more secure (very arguable and also of very little consequence since everything is on my homelab… it’s mainly for the warm fuzzies)
Do you guys use one of the options above? Something different?
Like another commenter I’m also running Proxmox. I have a couple VMs to ensure certain services have total segregation, and otherwise usually configure systemd services from my nix flake.
This is an important question for selfhosting, which there’s too little guidance. It should be systemd services somehow, but i want to deploy NixOS (the underlying platform) separate from independent collections of services (one collection per app/project) without having to use another tool or concept like Docker or Kubernetes… Also i’m really looking forward to NixOS “Contracts” https://github.com/ibizaman/selfhostblocks
If the package you’re using stays up to date and doesn’t require much setup, you could plug a dockerTools.buildLayeredImage into the imageFile attribute. The name and the tag in the built image should match what’s in the image attribute. An example (busybox is only included for debugging):
image = "my-calibre-web:latest"; imageFile = pkgs.dockerTools.buildLayeredImage { name = "my-calibre-web"; tag = "latest"; contents = [ pkgs.busybox ]; config.Cmd = [ "${pkgs.calibre-web}/bin/calibre-web" "-p" "/config/app.db" "-g" "/config/gdrive.db" "-i" "0.0.0.0" ]; };
I use systemd services when I can, and fall back to podman containers when - for one reason or another - the systemd services aren’t a viable option. There are currently two services I run in containers: the glitch-soc fork of Mastodon (because I have no desire to compile it myself, and their container image is the next best thing), and Wallabag (because at the time I made my config, the nixos module for it wasn’t in a good shape). Everything else (about a dozen other services) runs as a systemd service.
My primary reason for this is that before NixOS, I used containers for all of these, and keeping them updated and functional and at a reasonable size was a pain in the backside to say the least. Especially if I wanted to patch something (I often patch my Forgejo instance, for example). If I need a patched version, or an updated version, I can easily do that with overriding a few attributes in the vast majority of cases - I do not juggle stable & unstable.
Using the NixOS-provided modules also allow me to configure all of these using the same language: Nix. While it’s not a language I like, I hate it much less than I hate YAML and all the others. Using Nix for configuration lets me wrap it all in Org Roam, easily, which makes it very easy to document my configuration thoroughly and completely, and also allows me to organize it in a way that makes sense to me. Generating YAML from Org is a much, much, much more painful thing.
Plain old Debian with systemd services. I don’t want my server to waste RAM running multiple copies of the same thing.
I’ve been running Proxmox with LXC containers for years and it has been super stable and convenient!
I’ve used proxmox with VMs running Debian for Docker Compose stacks.
Most “get started quickly” tutorials are docker based, and building into a compose stack with dependencies is easy enough.
Then a VM per stack (depending on isolation, duplication/redundancy and all that).I’ve recently started playing with k8s, and Talos Linux is amazing.
I went from no-idea to k8s-yaml-hell faster than I could imagine. No need to configure kubernetes.I guess I’m weird and use the NixOS options and packages? I just have Jellyfin and Kavita setup currently but I want more.
No, that’s the way. Containers are glorified chroots to work around the fact that 20th century package managers can’t manage packages for shit. NixOS needs none of that.
I got PhotoPrism working over the weekend and it’s nice.
Plain old
docker compose
since it seems to come with by far the fewest surprises and is most widely supported.Nearly every project of interest has a compose.yml available, which is hardly true for systemd services, nix services, or for podman/kubernetes.
I was using podman-compose briefly, but it is just different enough to break in unclear ways and I kept having to fight with it so I went back to docker docker to eliminate the headache.
This is the way. Docker (& compose) are not flawless, but they are predictable and useful enough for all my needs.
I currently have around 12 containers running on my server, all trough docker compose. Only thing I use nix for is providing tools & their configs. And also restic backups.
I use both 1 and 3, personally (although docker rather than podman). I normally prefer the nix way but it doesn’t support every service. I like that nix config is all in one place. In theory, so is docker-compose to am extent but there are usually exceptions and things can get complex. I also hate having to directly manage containers with minimal commandline tools.
But yeah the whole translate config routine in nix is kind of annoying, and I often need to experiment to get the options right if they aren’t documented.
I use proxmox as my hypervisor with:
- TrueNAS VM
- Home Assistant OS VM
- Debian VM for MDAD and MASH, but I’m slowly moving things to Nix when I can.
- NixOS VM for everything else using compose2nix for services designed for docker and regular systemd services where it makes sense.
I lean on nixos modules first, but half the time it either doesnt exist or its too complicated at first glance. So I will manually create an oci-container configuration by referencing a docker compose on the projects site. For simple compose files this is easy. Sometimes its not easy, and I dont end up deploying it.
I’ve been wanting to find or build a method that lets me drop a compose alongside ny config and have nix load the yaml and build the oci-container configuration for me. That would be nice since Im familiar with compose syntax and it’s usually easier to write imo.
Maybe https://github.com/aksiksi/compose2nix will help you out!
My server runs Proxmox and I usually just run things as a systemd service each in its own virtual container
ansible-playbook
even if its just one target host. Services might get hosted as systemd or docker, or a raw binary, whatever’s appropriate. The absible docker module is extremely similar to docker-compose. It only gets messy if you have a complicated system of networks and dependencies.