Nextcloud development environment on NixOS
Using nixos-shell it is easy to build and run a virtual machine from a Nix configuration file describing the system. I started using this tool to create clean and reproducible test environments for developing Nextcloud apps.
The requirement for this setup was to automatically configure Nextcloud, additional apps and users for testing. The Nextcloud service should be able to deliver mails to a local mail server with preconfigured mailboxes and users.
Unfortunately the development setup requires NixOS and nixos-shell installed and most probably won’t work on other systems. The following commands clone the repositories and run the virtual machine. After that Nextcloud will be available at http://localhost:8080
and the mail server on port 1433 (IMAP)
git clone https://github.com/NixOS/nixpkgs.git
git clone https://github.com/onny/nixos-nextcloud-testumgebung.git
cd nixos-nextcloud-testumgebung
QEMU_NET_OPTS="hostfwd=tcp::8080-:80,hostfwd=tcp::1433-:143,hostfwd=tcp::5877-:587" NIX_PATH=nixpkgs=../nixpkgs nixos-shell vm-nextcloud.nix
The state of the virtual machine is stored in an image file called nixos.qcow2
. Deleting this file will reset the state back to a clean environment.
The configuration explained
In the following part I’m going to describe some parts of this configuration found in vm-nixos.nix
in more detail.
The first part overrides the Nextcloud package from the NixOS repository. Overriding in NixOS means, that we’ll going to change parts of the package. In this case, we’ll remove default apps which we don’t need in our test environment
{ pkgs, config, lib, options, ... }: {
nixpkgs = {
overlays = [
(self: super: {
# Remove first run wizard and password policy check from Nextcloud
# package
nextcloud25 = super.nextcloud25.overrideAttrs (oldAttrs: rec {
installPhase = oldAttrs.installPhase + ''
rm -r $out/apps/firstrunwizard
rm -r $out/apps/password_policy
'';
});
})
];
};
This section installs and enables the Nextcloud server. We define the username and password for the administrator account. Further we install the circle
app from a release tarball, the mail app from the repository and the compiled calendar app from a local git checkout / development directory. The last part configures local mail delivery using sendmail
# Setup Nextcloud including apps
services.nextcloud = {
enable = true;
package = pkgs.nextcloud25;
hostName = "localhost";
config = {
adminuser = "admin";
adminpassFile = "${pkgs.writeText "adminpass" "test123"}";
};
extraApps = {
circles = pkgs.fetchNextcloudApp rec {
url = "https://github.com/nextcloud-releases/circles/releases/download/0.21.4/circles-0.21.4.tar.gz";
sha256 = "sha256-gkW9jZvXS86ScuM434mUbvQajYKwHVjm9PfTMNgHL/Q=";
};
calendar = pkgs.stdenvNoCC.mkDerivation rec {
name = "calendar";
src = /home/onny/projects/calendar;
unpackPhase = ''cp -r --no-preserve=mode $src/* .'';
dontBuild = true;
installPhase = ''cp -r --no-preserve=mode . $out/'';
};
mail = pkgs.nextcloud25Packages.apps.mail;
};
extraOptions = {
mail_smtpmode = "sendmail";
mail_sendmailmode = "pipe";
};
};
The next service is maddy
, a simple and small mail server. The configuration below doesn’t use any TLS or other secure settings since we’re only using it in the development environment. The msmtp
section configures the sendmail
client to use the local mailbox for mail delivery
# Setup mail server
services.maddy = {
enable = true;
hostname = "localhost";
primaryDomain = "localhost";
# Disable any sender validation checks
config = lib.concatStrings (
builtins.match "(.*)authorize_sender.*identity\n[ ]+\}(.*)" options.services.maddy.config.default
);
};
# Configure local mail delivery
programs.msmtp = {
enable = true;
accounts.default = {
host = "localhost";
port = 587;
auth = "login";
tls = "off";
from = "admin@localhost";
user = "admin@localhost";
password = "test123";
};
};
To further automate the bootstrapping process, two systemd
services create users and mailboxes for maddy and Nextcloud
# Creating mail users and inboxes
systemd.services.maddy-accounts = {
script = ''
${pkgs.maddy}/bin/maddyctl creds create --password test123 user1@localhost
${pkgs.maddy}/bin/maddyctl imap-acct create user1@localhost
${pkgs.maddy}/bin/maddyctl creds create --password test123 user2@localhost
${pkgs.maddy}/bin/maddyctl imap-acct create user2@localhost
${pkgs.maddy}/bin/maddyctl creds create --password test123 admin@localhost
${pkgs.maddy}/bin/maddyctl imap-acct create admin@localhost
'';
serviceConfig = {
Type = "oneshot";
User= "maddy";
};
after = [ "maddy.service" ];
wantedBy = [ "multi-user.target" ];
};
# Creating Nextcloud users and configure mail adresses
systemd.services.nextcloud-add-user = {
script = ''
export OC_PASS="test123"
${config.services.nextcloud.occ}/bin/nextcloud-occ user:add --password-from-env user1
${config.services.nextcloud.occ}/bin/nextcloud-occ user:setting user1 settings email "user1@localhost"
${config.services.nextcloud.occ}/bin/nextcloud-occ user:add --password-from-env user2
${config.services.nextcloud.occ}/bin/nextcloud-occ user:setting user2 settings email "user2@localhost"
${config.services.nextcloud.occ}/bin/nextcloud-occ user:setting admin settings email "admin@localhost"
'';
serviceConfig = {
Type = "oneshot";
User= "nextcloud";
};
after = [ "nextcloud-setup.service" ];
wantedBy = [ "multi-user.target" ];
};
[...]