Personally I use the same approach to piku, but instead rebuild my Nixos config on push. My projects use nix flakes, so I get both something that I know will run on my server and on my local machine with the full development environment. No containers needed technically, but I use systemd nspawn to run the software in its own sandboxed namespace.
My entire server is then managed declaratively, so if I want to add a new project, it’s like 3-5 lines of Nginx config and push, that’s all. Something goes wrong? Just revert the commit.