1
Fork 0
blog/_posts/2023-07-24-old-ruby-on-modern-nix.md

210 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
permalink: "/{{ year }}/{{ month }}/{{ day }}/old-ruby-on-modern-nix"
title: "Old Ruby on modern Nix"
published_date: "2023-07-24 14:40:00 +0200"
layout: post.liquid
data:
route: blog
tags:
- nix
---
The other day I had to deploy an old Ruby 2.7 application.
As I've recently started experimenting with NixOS I used this as an opportunity to figure out how to reliably and consistently deploy this application.
Along the way I had to figure out a couple of things and the available Nix documentation was either outdated or things didn't work as specified.
## A dev shell for old Ruby
To get started all I wanted was a dev shell with the right Ruby version available.
So I started with [ruby-nix]:
```
nix flake init -t github:inscapist/ruby-nix/main
```
That got me a basic `flake.nix` installing Ruby 3.2.
I trimmed that down just slightly and swapped in Ruby 2.7 (here's the [list of available Ruby version][ruby_avail]):
[ruby-nix]: https://github.com/inscapist/ruby-nix
[ruby_avail]: https://github.com/bobvanderlinden/nixpkgs-ruby/blob/master/ruby/versions.json
```nix
{
description = "An old Ruby application";
nixConfig = {
extra-substituters = "https://nixpkgs-ruby.cachix.org";
extra-trusted-public-keys =
"nixpkgs-ruby.cachix.org-1:vrcdi50fTolOxWCZZkw0jakOnUI1T19oYJ+PRYdK4SM=";
};
inputs = {
nixpkgs.url = "nixpkgs";
ruby-nix = {
url = "github:inscapist/ruby-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
fu.url = "github:numtide/flake-utils";
bob-ruby = {
url = "github:bobvanderlinden/nixpkgs-ruby";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, fu, ruby-nix, bob-ruby }:
with fu.lib;
eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ bob-ruby.overlays.default ];
};
rubyNix = ruby-nix.lib pkgs;
ruby = pkgs."ruby-2.7.8";
in rec {
inherit (rubyNix {
inherit ruby;
name = "old-ruby-app";
})
env;
devShells = rec {
default = dev;
dev = pkgs.mkShell {
buildInputs = [ env ];
};
};
});
}
```
The important line is this:
```
ruby = pkgs."ruby-2.7.8";
```
`pkgs` contains the `bob-ruby` overlay and so the previously listed Ruby versions are all directly available.
Now on to installing it into a shell:
```
nix develop
```
And boom:
```
error: Package openssl-1.1.1u in /nix/store/b1l1kkp1g07gy67wglfpwlwaxs1rqkpx-source/pkgs/development/libraries/openssl/default.nix:210 is marked as insecure, refusing to evaluate.
Known issues:
- OpenSSL 1.1 is reaching its end of life on 2023/09/11 and cannot be supported through the NixOS 23.05 release cycle. https://www.openssl.org/blog/blog/2023/03/28/1.1.1-EOL/
You can install it anyway by allowing this package, using the
following methods:
a) To temporarily allow all insecure packages, you can use an environment
variable for a single invocation of the nix tools:
$ export NIXPKGS_ALLOW_INSECURE=1
Note: For `nix shell`, `nix build`, `nix develop` or any other Nix 2.4+
(Flake) command, `--impure` must be passed in order to read this
environment variable.
b) for `nixos-rebuild` you can add openssl-1.1.1u to
`nixpkgs.config.permittedInsecurePackages` in the configuration.nix,
like so:
{
nixpkgs.config.permittedInsecurePackages = [
"openssl-1.1.1u"
];
}
c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add
openssl-1.1.1u to `permittedInsecurePackages` in
~/.config/nixpkgs/config.nix, like so:
{
permittedInsecurePackages = [
"openssl-1.1.1u"
];
}
```
That's ... unfortunate, but at least it tells us what to do:
```
NIXPKGS_ALLOW_INSECURE=1 nix develop --impure
```
And that works:
```
$ NIXPKGS_ALLOW_INSECURE=1 nix develop --impure
(nix:nix-shell-env)
; ruby -v
ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [arm64-darwin22]
```
Partial success!
## A failed attempt to deploy this on NixOS
I set up a server running NixOS recently and wanted to deploy something like the above to it.
So I added my custom flake as an input and then references it in my `configuration.nix`.
Lo and behold, it failed with an error message like the one above.
But hey, option b) in there said what to do:
```nix
{
nixpkgs.config.permittedInsecurePackages = [
"openssl-1.1.1u"
];
}
```
Except no matter where, when and how I added this in my configuration it did not work.
I spent a couple of hours trying out every solution I could find on the internet.
None of them worked and neither the error messages nor the documentation could clear this up.
Failure.
## The hack: Ignoring vulnerabilities
[openssl_1_1_vuln]: https://github.com/NixOS/nixpkgs/blob/12303c652b881435065a98729eb7278313041e49/pkgs/development/libraries/openssl/default.nix#L237-L241
Vulnerabilities in `nixpkgs` are declared by adding a `meta.knownVulnerabilities` list.
That's what triggers the error above and the erorr message includes the custom description.
For OpenSSL 1.1 this Vulnerability is declared in [`pkgs/development/libraries/openssl/default.nix`][openssl_1_1_vuln].
Knowing this I later stumbled upon a StackOverflow question: [Nix(OS): Set "permittedInsecurePackages" only for one package build (in an overlay?)](https://stackoverflow.com/questions/53566342/nixos-set-permittedinsecurepackages-only-for-one-package-build-in-an-overl),
which had an answer: Patch the package to just contain an empty `knownVulnerabilities` list.
So I changed my `flake.nix` in the Ruby app to override that just for the Ruby version:
```nix
ignoringVulns = x: x // { meta = (x.meta // { knownVulnerabilities = []; }); };
ruby = pkgs."ruby-2.7.8".override {
openssl = pkgs.openssl_1_1.overrideAttrs ignoringVulns;
};
```
And now it works without any issues:
```
$ nix develop
(nix:nix-shell-env)
; ruby -v
ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [arm64-darwin22]
```
No more changes to my NixOS configuration required. Only this particular flake overrides the `openssl` version and that's good enough for this deployment.
Success.