Packaging a dynamic website

I’m pretty new to Nix, I have been using NixOS for a year and I have written a few Python derivations and I think I understand more or less the basic concepts.

I recently started using Nixops and liked it a lot, and I thought I’d migrate one of my Debian servers to NixOS. So I’m trying to package a website that is hosted on this server.

The website is made with Python/Django, and uses webpack to build the frontend assets. I managed to generate derivations for the Python part using mach-nix, and for the frontend part using node2nix. I’m using these derivations in a third derivation which contains both the Python code and the compiled JS/CSS files like so:

with import <nixpkgs> { };

let
  src = builtins.fetchGit {
    url = ./.;
    rev = "7bda671b2f52e48507497059a88b6a6f776e76bc";
  };

  mach-nix = import (builtins.fetchGit {
    url = "https://github.com/DavHau/mach-nix/";
    ref = "refs/tags/3.1.1";
  }) { };

  pyenv = mach-nix.mkPython {
    requirements = builtins.readFile ./requirements/base.txt;
  };

  nodeEnv = callPackage ./node-env.nix {
    nodejs = pkgs.nodejs-12_x;
    libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
  };

  nodePackages = callPackage ./node-packages.nix { inherit nodeEnv; };

  nodeArgs = nodePackages.args // {
    production = false;
    src = builtins.filterSource (path: type:
      /. + path == ./package.json || /. + path == ./package-lock.json) ./.;
    dontNpmInstall = true;
  };

  nodeShell = nodeEnv.buildNodeShell nodeArgs;

  nodeDependencies = stdenv.mkDerivation {
    name = "mywebsite-front";
    src = src;
    installPhase = ''
      ln -s ${nodeShell.nodeDependencies}/lib/node_modules ./node_modules
      export PATH="${nodeShell.nodeDependencies}/bin:$PATH"
      NODE_ENV=production webpack
      mkdir $out
      cp -r dist/* $out/
    '';
  };

in python3Packages.buildPythonPackage {
  propagatedBuildInputs = [ pyenv ];
  name = "mywebsite";
  src = src;
  doCheck = false;
  configurePhase = ''
    ln -s ${nodeDependencies} ./blog/staticfiles
  '';
}

It works but:

  • I need to update src every time I make a new commit. Ideally I’d like to always build the main branch. I tried using ref = refs/heads/main but it seems that without specifying a checksum, Nix doesn’t recreate the derivation. The reason I’m using fetchgit here is that I want to package a clean version of the project, without the risk of including any non-committed change. Maybe there’s another way to do this?
  • I would like to be able to run commands on the website (using Django’s entrypoint ./manage.py command). I guess I can add the entrypoint in my setup.py file, but the thing is that I would like to be able to deploy multiple “instances” of the website on the same server (eg. staging, production, etc). So instead of having a mywebsite command, I guess I should have something like mywebsite-staging and mywebsite-prod commands (which could, or could not, point to the same version of the package). Is it something that should be done outside of the package, eg. with Nixops?
  • What if I want to use this Nix package on a non-NixOS server? How can I make the application server point to the correct directory in /nix/store? Or maybe I should add the application server as an input for the derivation, but then how do I write a systemd unit to use it?

I’m surprised the only examples I could find on the internet were people packaging static websites, but very few packaging something more complex. I plan on sharing my experience, with the hope that it will be of use to some people.

Thanks for your help!

1 Like

That should be possible to handle with the nix option tarball-ttl. Something like nixos-rebuild -I /your/system/configuration.nix --tarball-ttl 0.

I can imagine that you override each of your package instances with a patch that renames the entry point accordingly. Such as:

stage: python3Packages.buildPythonPackage {
# ...
patchPhase = ''
  substituteInPlace $src/setup.cfg \
    "manage = manage:main" "manage-${stage} = manage:main"
'';
}

For the other question I can’t help, but I remember reading about people trying to run NixOS systemd services on Ubuntu. The gut feel I was left with was, it’s nightmarishly tedious.

1 Like

I guess it was this Unix & Linux Stackexchange thread:
How does Nix manage SystemD modules on a non-NixOS?

Just linking it here because I’m about to descend into this hellscape…:slight_smile:

1 Like