I’m currently testing the waters with NixOS, and want to deploy a Rails app on a NixOS.
At first I thought I could just specify as user packages things like
ruby zlib etc, but I’ve fallen into the trap that pkg-config does not find it in this case.
Now, I’ve since learned that I should create a
.nix file and use
nix-shell to get access to the libraries I need to build my webapp.
So far so good, it works in the nix-shell. However I now have trouble unifying it with my preferred deployment pattern:
(If you know mina/capistrano it is pretty much exactly that)
mina deploy and this happens on the remote server:
- Each new release creates a new folder, and the running release gets symlinked to ‘current’
- You have a set of shared folders, which get symlinked into the ‘current’ release
- The shared folders are never deleted or touched between upgrades
To me it sounds very similar to what NixOS does on its own already, and I think I am just missing some techniques and ways to get a similar idea working.
I’ve tried to play around with profiles, but that didn’t get me much further. I then thought of creating a service file for my webapp, but it is unclear to me how it would be structured for a rails app.
I had so far no trouble creating a custom systemd service.
I’d love some help and learn how this could be achieved! Thank you for any pointers
You could use
mina deploy and wrap your application in
nix-shell but this might end up in garbage collecting the libraries if you run nix-collect-garbage at some point on your server. A better approach is to package your gems with bundix from your existing Gemfile. This allows you to use the same setup for both development and deployment. The nice thing about bundix is that for many gems we already know the native dependencies and put them in place automatically. You can checkout this file to see what gems are already covered by this: nixpkgs/default.nix at master · NixOS/nixpkgs · GitHub. In the wiki we also have a tutorial and a bit in our manual.
nixops also has a quite similar feel to it. It would require to wrap the application is a package, declare the service as a systemd unit, write a configuration.nix for the target machine and finally attach it to the nixosp config. Then
nixops deploy would have a similar effect as
mina deploy except that the whole system configuration is also included with it. nixops also supports rollbacks.
Usually services have a way to specify the “data” dir that contains mutable data. So you would also declare a user for the service and then point the service to the user’s home. Unfortunately rails has this insane notion of mixing code and mutable data in the same directory so that might make things a bit more difficult. The
12factor-rails gem tries to fix this so it might come in handy. Otherwise I would recommend to create symlinks from
/var/myapp/log for example.
How would I wrap the application in nix-shell?
Is there a way to start a nix-shell by replacing the current env instead of starting a sub-env?
Thanks for the suggestion! But I’m using Rails 5, so it already is 12Factor ready so to speak.
But for example users can upload files, and losing them in between deploys would be bad.
Install direnv and then create a
use nix as the content.
Is it possible to configure the upload folder? As long as it’s possible to pass a custom target directory to rails it’s fine. The goal is to move away from relative to absolute paths.