Unverified Commit 059f376f authored by K900's avatar K900 Committed by GitHub
Browse files

opencloud: init at 2.3.0 (#404891)

parents 3cd899b3 b504cc13
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -50,6 +50,12 @@
  "module-services-crab-hole-upstream-options": [
    "index.html#module-services-crab-hole-upstream-options"
  ],
  "module-services-opencloud": [
    "index.html#module-services-opencloud"
  ],
  "module-services-opencloud-basic-usage": [
    "index.html#module-services-opencloud-basic-usage"
  ],
  "module-services-strfry": [
    "index.html#module-services-strfry"
  ],
+2 −0
Original line number Diff line number Diff line
@@ -200,6 +200,8 @@ Alongside many enhancements to NixOS modules and general system improvements, th

- [`g3proxy`](https://github.com/bytedance/g3), an open source enterprise forward proxy from ByteDance, similar to Squid or tinyproxy. Available as [services.g3proxy](#opt-services.g3proxy.enable).

- [OpenCloud](https://opencloud.eu/), an open-source, modern file-sync and sharing platform. It is a fork of oCIS, a ground-up rewrite of the well-known PHP-based NextCloud server. Available as [services.opencloud](#opt-services.opencloud.enable).

- [echoip](https://github.com/mpolden/echoip), a simple service for looking up your IP address. Available as [services.echoip](#opt-services.echoip.enable).

- [whoami](https://github.com/traefik/whoami), a tiny Go server that prints OS information and HTTP request to output. Available as [services.whoami](#opt-services.whoami.enable).
+1 −0
Original line number Diff line number Diff line
@@ -1610,6 +1610,7 @@
  ./services/web-apps/oncall.nix
  ./services/web-apps/onlyoffice.nix
  ./services/web-apps/open-web-calendar.nix
  ./services/web-apps/opencloud.nix
  ./services/web-apps/openvscode-server.nix
  ./services/web-apps/openwebrx.nix
  ./services/web-apps/outline.nix
+64 −0
Original line number Diff line number Diff line
# OpenCloud {#module-services-opencloud}

[OpenCloud](https://opencloud.eu/en) is an open-source, modern file-sync and
sharing platform. It is a fork of oCIS, a ground-up rewrite of the well-known
PHP-based NextCloud server.

The service can be configured using a combination of [](#opt-services.opencloud.settings),
[](#opt-services.opencloud.environment) and [](#opt-services.opencloud.environmentFile).

## Basic usage {#module-services-opencloud-basic-usage}

OpenCloud is configured using a combination of YAML and environment
variables. The full documentation can be found at
[OpenCloud Admin Docs](https://docs.opencloud.eu/docs/admin/intro).

The general flow of configuring OpenCloud is:
- configure services with `services.opencloud.settings.<service>` when possible
- configure global settings that affect multiple services via `services.opencloud.environment`
- allow NixOS to provision a default `opencloud.yaml` for you, containing default credentials
  for communication between the microservices
- provide additional secrets via `environmentFile`, provisioned out of band

Please note that current NixOS module for OpenCloud is configured to run in
`fullstack` mode, which starts all the services for OpenCloud in a single
instance, in so called supervised mode. This will start multiple OpenCloud
services and listen on multiple other ports.

Current known services and their ports are as below:

| Service            | Group   |  Port |
|--------------------|---------|-------|
| gateway            | api     |  9142 |
| sharing            | api     |  9150 |
| app-registry       | api     |  9242 |
| ocdav              | web     | 45023 |
| auth-machine       | api     |  9166 |
| storage-system     | api     |  9215 |
| webdav             | web     |  9115 |
| webfinger          | web     | 46871 |
| storage-system     | web     |  9216 |
| web                | web     |  9100 |
| eventhistory       | api     | 33177 |
| ocs                | web     |  9110 |
| storage-publiclink | api     |  9178 |
| settings           | web     |  9190 |
| ocm                | api     |  9282 |
| settings           | api     |  9191 |
| ocm                | web     |  9280 |
| app-provider       | api     |  9164 |
| storage-users      | api     |  9157 |
| auth-service       | api     |  9199 |
| thumbnails         | web     |  9186 |
| thumbnails         | api     |  9185 |
| storage-shares     | api     |  9154 |
| sse                | sse     | 46833 |
| userlog            | userlog | 45363 |
| search             | api     |  9220 |
| proxy              | web     |  9200 |
| idp                | web     |  9130 |
| frontend           | web     |  9140 |
| groups             | api     |  9160 |
| graph              | graph   |  9120 |
| users              | api     |  9144 |
| auth-basic         | api     |  9146 |
+242 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  inherit (lib) types;
  cfg = config.services.opencloud;

  defaultUser = "opencloud";
  defaultGroup = defaultUser;

  settingsFormat = pkgs.formats.yaml { };
in
{
  options = {
    services.opencloud = {
      enable = lib.mkEnableOption "OpenCloud";

      package = lib.mkPackageOption pkgs "opencloud" { };
      webPackage = lib.mkPackageOption pkgs [ "opencloud" "web" ] { };
      idpWebPackage = lib.mkPackageOption pkgs [ "opencloud" "idp-web" ] { };

      user = lib.mkOption {
        type = types.str;
        default = defaultUser;
        example = "mycloud";
        description = ''
          The user to run OpenCloud as.
          By default, a user named `${defaultUser}` will be created whose home
          directory is [](#opt-services.opencloud.stateDir).
        '';
      };

      group = lib.mkOption {
        type = types.str;
        default = defaultGroup;
        example = "mycloud";
        description = ''
          The group to run OpenCloud under.
          By default, a group named `${defaultGroup}` will be created.
        '';
      };

      address = lib.mkOption {
        type = types.str;
        default = "127.0.0.1";
        description = "Web server bind address.";
      };

      port = lib.mkOption {
        type = types.port;
        default = 9200;
        description = "Web server port.";
      };

      url = lib.mkOption {
        type = types.str;
        default = "https://localhost:9200";
        example = "https://cloud.example.com";
        description = "Web interface root public URL, including scheme and port (if non-default).";
      };

      stateDir = lib.mkOption {
        default = "/var/lib/opencloud";
        type = types.str;
        description = "OpenCloud data directory.";
      };

      settings = lib.mkOption {
        type = lib.types.attrsOf settingsFormat.type;
        default = { };
        description = ''
          Additional YAML configuration for OpenCloud services.

          Every item in this attrset will be mapped to a .yaml file in /etc/opencloud.

          The possible config options are currently not well documented, see source code:
          https://github.com/opencloud-eu/opencloud/blob/main/pkg/config/config.go
        '';
      };

      environmentFile = lib.mkOption {
        type = types.nullOr types.path;
        default = null;
        example = "/run/keys/opencloud.env";
        description = ''
          An environment file as defined in {manpage}`systemd.exec(5)`.

          Use this to inject secrets, e.g. database or auth credentials out of band.

          Configuration provided here will override `settings` and `environment`.
        '';
      };

      environment = lib.mkOption {
        type = types.attrsOf types.str;
        default = {
          OC_INSECURE = "true";
        };
        description = ''
          Extra environment variables to set for the service.

          Use this to set configuration that may affect multiple microservices.

          Configuration provided here will override `settings`.
        '';
        example = {
          OC_INSECURE = "false";
          OC_LOG_LEVEL = "error";
        };
      };
    };
  };

  config = lib.mkIf cfg.enable {
    users.users.${defaultUser} = lib.mkIf (cfg.user == defaultUser) {
      group = cfg.group;
      home = cfg.stateDir;
      isSystemUser = true;
      createHome = true;
      description = "OpenCloud daemon user";
    };

    users.groups = lib.mkIf (cfg.group == defaultGroup) { ${defaultGroup} = { }; };

    systemd = {
      services =
        let
          environment = {
            PROXY_HTTP_ADDR = "${cfg.address}:${toString cfg.port}";
            OC_URL = cfg.url;
            OC_BASE_DATA_PATH = cfg.stateDir;
            WEB_ASSET_CORE_PATH = "${cfg.webPackage}";
            IDP_ASSET_PATH = "${cfg.idpWebPackage}/assets";
            OC_CONFIG_DIR = "/etc/opencloud";
          } // cfg.environment;
          commonServiceConfig = {
            EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile;
            MemoryDenyWriteExecute = true;
            NoNewPrivileges = true;
            PrivateTmp = true;
            PrivateDevices = true;
            ProtectSystem = "strict";
            ProtectHome = true;
            ProtectControlGroups = true;
            ProtectKernelModules = true;
            ProtectKernelTunables = true;
            ProtectKernelLogs = true;
            RestrictAddressFamilies = [
              "AF_UNIX"
              "AF_INET"
              "AF_INET6"
            ];
            RestrictNamespaces = true;
            RestrictRealtime = true;
            RestrictSUIDSGID = true;
            LockPersonality = true;
            SystemCallArchitectures = "native";
          };
        in
        {
          opencloud-init-config = lib.mkIf (cfg.settings.opencloud or { } == { }) {
            description = "Provision initial OpenCloud config";
            before = [ "opencloud.service" ];
            wantedBy = [ "multi-user.target" ];

            inherit environment;

            serviceConfig = {
              Type = "oneshot";
              ReadWritePaths = [ "/etc/opencloud" ];
            } // commonServiceConfig;

            path = [ cfg.package ];
            script = ''
              set -x
              config="''${OC_CONFIG_DIR}/opencloud.yaml"
              if [ ! -e "$config" ]; then
                echo "Provisioning initial OpenCloud config..."
                opencloud init --insecure "''${OC_INSECURE:false}" --config-path "''${OC_CONFIG_DIR}"
                chown ${cfg.user}:${cfg.group} "$config"
              fi
            '';
          };

          opencloud = {
            description = "OpenCloud - a secure and private way to store, access, and share your files";
            after = [ "network.target" ];
            wantedBy = [ "multi-user.target" ];

            inherit environment;

            serviceConfig = {
              Type = "simple";
              ExecStart = "${lib.getExe cfg.package} server";
              WorkingDirectory = cfg.stateDir;
              User = cfg.user;
              Group = cfg.group;
              Restart = "always";
              ReadWritePaths = [ cfg.stateDir ];
            } // commonServiceConfig;

            restartTriggers = lib.mapAttrsToList (
              name: _: config.environment.etc."opencloud/${name}.yaml".source
            ) cfg.settings;
          };
        };
    };

    systemd.tmpfiles.settings."10-opencloud" = {
      ${cfg.stateDir}.d = {
        inherit (cfg) user group;
        mode = "0750";
      };
      "${cfg.stateDir}/idm".d = {
        inherit (cfg) user group;
        mode = "0750";
      };
    };

    environment.etc =
      (lib.mapAttrs' (name: value: {
        name = "opencloud/${name}.yaml";
        value.source = settingsFormat.generate "${name}.yaml" value;
      }) cfg.settings)
      // {
        # ensure /etc/opencloud gets created, so we can provision the config
        "opencloud/.keep".text = "";
      };
  };

  meta = {
    doc = ./opencloud.md;
    maintainers = with lib.maintainers; [
      christoph-heiss
      k900
    ];
  };
}
Loading