Add quatresaisons server
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Sat, 24 Oct 2020 10:30:42 +0000 (12:30 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Sat, 24 Oct 2020 10:30:42 +0000 (12:30 +0200)
Makefile
modules/private/environment.nix
modules/private/system/quatresaisons.nix [new file with mode: 0644]
modules/private/system/quatresaisons/databases.nix [new file with mode: 0644]
modules/private/system/quatresaisons/landing.yml [new file with mode: 0644]
modules/private/system/quatresaisons/landing_4c.yml [new file with mode: 0644]
modules/private/system/quatresaisons/nextcloud.nix [new file with mode: 0644]
nixops/Makefile
nixops/default.nix
nixops/secrets

index 9c12ff48fdeafc687e840fe989cd1a54aefb40b1..466b63a7d045ebc1d7de27214eb4f2e3972ef2e4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 subrecipes = setup nix-info edit_env
-subrecipes += ssh-eldiron ssh-backup-2 ssh-monitoring-1
-subrecipes += debug build upload deploy deploy-reboot
+subrecipes += ssh-eldiron ssh-backup-2 ssh-monitoring-1 ssh-4c
+subrecipes += debug build dry-run upload deploy deploy-reboot
 subrecipes += list-generations delete-generations cleanup
 ${subrecipes}:
        @$(MAKE) --no-print-directory -C nixops/ $@
index a8799d26e492ef821edd7aae8d194b1bcf94b82f..e79feec573e2273e3471cc3d2f0b362f397173ae 100644 (file)
@@ -1171,6 +1171,7 @@ in
         };
       };
     };
+    serverSpecific = mkOption { type = attrsOf unspecified; description = "Server specific configuration"; };
     websites = mkOption {
       description = "Websites configurations";
       type = submodule {
diff --git a/modules/private/system/quatresaisons.nix b/modules/private/system/quatresaisons.nix
new file mode 100644 (file)
index 0000000..395b604
--- /dev/null
@@ -0,0 +1,449 @@
+{ privateFiles }:
+{ config, pkgs, lib, ... }:
+let
+  serverSpecificConfig = config.myEnv.serverSpecific.quatresaisons;
+  yarnModules = pkgs.yarn2nix-moretea.mkYarnModules rec {
+    name = "landing";
+    pname = name;
+    version = "v1.0.0";
+    packageJSON = "${pkgs.sources.webapps-landing}/package.json";
+    yarnLock = "${pkgs.sources.webapps-landing}/yarn.lock";
+    yarnNix = ../websites/tools/tools/landing/yarn-packages.nix;
+  };
+  toLanding = landingConfig: pkgs.stdenv.mkDerivation rec {
+    pname = "landing";
+    version = "v1.0.0";
+    src = pkgs.sources.webapps-landing;
+
+    buildInputs = [ yarnModules pkgs.yarn2nix-moretea.yarn ];
+    configurePhase = ''
+      ln -s ${yarnModules}/node_modules .
+    '';
+    buildPhase = ''
+      yarn build
+    '';
+    installPhase = ''
+      cp -a dist $out
+      cp -f ${landingConfig} $out/config.yml
+      ln -s service-worker.js $out/worker.js
+    '';
+  };
+  normalUsers = serverSpecificConfig.users;
+  sponsoredUser = pkgs.writeScriptBin "sponsored_user" ''
+    #!/usr/bin/env bash
+
+    set -euo pipefail
+    [ -z "''${SUDO_USER+x}" ] && echo "Must be run with sudo" && exit 1
+
+    mygroup=$(id -ng $SUDO_USER)
+
+    sponsored=$(getent group $mygroup | cut -d':' -f4)
+
+    echo "Sponsored users: ''${sponsored:-<none>}"
+
+    log () {
+      touch /var/log/sponsored_users
+      chmod go-rwx /var/log/sponsored_users
+      echo "`date` $mygroup $1" | LANG=C cat -v | tr '\012' ' ' | sed 's:$:\x0a:' >> /var/log/sponsored_users
+    }
+
+    create_user () {
+      log "creates $1: $2"
+      useradd -m -G users,$mygroup -g $mygroup -p '!' "$1"
+      touch /var/lib/nixos/sponsored_users
+      chmod go-rwx /var/lib/nixos/sponsored_users
+      echo "$mygroup $1 $2" >> /var/lib/nixos/sponsored_users
+      (${pkgs.openldap}/bin/ldapadd -c -D cn=root,dc=salle-s,dc=org \
+        -y /var/secrets/ldap/sync_password 2>/dev/null >/dev/null || true) <<EOF
+    dn: uid=$1,uid=$mygroup,ou=users,dc=salle-s,dc=org
+    objectClass: inetOrgPerson
+    cn: $1
+    description:: $(echo -n "$2" | base64)
+    sn: $1
+    uid: $1
+    EOF
+      while ! passwd "$1"; do
+        echo "please give an initial password"
+      done
+    }
+
+    delete_user () {
+      IFS=",";
+      for u in $sponsored; do
+      if [ "$u" = "$1" ]; then
+        log "deletes $1"
+        userdel -r "$1"
+        sed -i -e "/^$mygroup $1/d" /var/lib/nixos/sponsored_users
+        ${pkgs.openldap}/bin/ldapdelete -D cn=root,dc=salle-s,dc=org \
+          -y /var/secrets/ldap/sync_password \
+          "uid=$1,uid=$mygroup,ou=users,dc=salle-s,dc=org"
+        echo "deleted"
+        exit 0
+      fi
+      done
+
+      echo "User does not exist or does not belong to you";
+      exit 1
+    }
+
+    reset_password () {
+      IFS=",";
+      for u in $sponsored; do
+      if [ "$u" = "$1" ]; then
+        log "resets password for $1"
+        passwd "$1"
+        exit 0
+      fi
+      done
+
+      echo "User does not exist or does not belong to you";
+      exit 1
+    }
+
+    reset_ldap_password () {
+      if [ "$1" = "$mygroup" ]; then
+        log "resets web password"
+        ${pkgs.openldap}/bin/ldappasswd -D cn=root,dc=salle-s,dc=org \
+          -y /var/secrets/ldap/sync_password \
+          -S "uid=$mygroup,ou=users,dc=salle-s,dc=org"
+      else
+        IFS=",";
+        for u in $sponsored; do
+        if [ "$u" = "$1" ]; then
+          log "resets web password of $1"
+          ${pkgs.openldap}/bin/ldappasswd -D cn=root,dc=salle-s,dc=org \
+            -y /var/secrets/ldap/sync_password \
+            -S "uid=$1,uid=$mygroup,ou=users,dc=salle-s,dc=org"
+          exit 0
+        fi
+        done
+
+        echo "User does not exist or does not belong to you";
+        exit 1
+      fi
+    }
+
+    show_help () {
+      echo "sponsored_users create username realname"
+      echo "    create a new sub-user attached to your account"
+      echo "sponsored_users (delete|reset_password) username"
+      echo "    delete a sub-user attached to your account or reset his password"
+      echo "sponsored_users reset_ldap_password username"
+      echo "    reset the web password of a sub-user or yourself"
+    }
+
+    [ -z "''${1+x}" -o -z "''${2+x}" ] && { show_help ; exit 0; }
+    action="$1"
+    username="$2"
+    shift
+    shift
+
+    case "$action" in
+      create)
+        [ -z "''${1+x}" ] && { show_help ; echo "Conformément à la charte https://4c.salle-s.org/charte veuillez préciser le nom réel du futur utilisateur du compte $username, juste pour root." ; exit 1; }
+        create_user "$username" "$*";
+        ;;
+      delete)
+        delete_user "$username";
+        ;;
+      reset_password)
+        reset_password "$username";
+        ;;
+      reset_ldap_password)
+        reset_ldap_password "$username";
+        ;;
+      *)
+        show_help
+        ;;
+    esac
+  '';
+in
+{
+  deployment = {
+    targetUser = "root";
+    targetHost = config.hostEnv.ips.main.ip4;
+    substituteOnDestination = true;
+  };
+
+  programs.ssh.package = pkgs.openssh.overrideAttrs(old: {
+    PATH_PASSWD_PROG = "/run/wrappers/bin/passwd";
+    buildFlags = [ "SSH_KEYSIGN=/run/wrappers/bin/ssh-keysign" ];
+  });
+
+  imports = builtins.attrValues (import ../..) ++
+    [ ./quatresaisons/nextcloud.nix ./quatresaisons/databases.nix ];
+
+  myEnv = import "${privateFiles}/environment.nix" // { inherit privateFiles; };
+
+  fileSystems = {
+    "/"     = { device = "/dev/disk/by-uuid/865931b4-c5cc-439f-8e42-8072c7a30634"; fsType = "ext4"; };
+    "/home" = { device = "/dev/disk/by-uuid/76020bc4-5b88-464c-8952-9a59072c597f"; fsType = "ext4"; neededForBoot = true; };
+    "/boot" = { device = "/dev/disk/by-uuid/0fb8421a-61e5-4ed5-a795-4dd3a9b2152a"; fsType = "ext4"; };
+    "/var/lib" = { device = "/home/var_lib"; fsType = "none"; options = [ "defaults,bind" ]; };
+  };
+  powerManagement.cpuFreqGovernor = "powersave";
+  hardware.enableRedistributableFirmware = true;
+
+  boot.initrd.availableKernelModules = [ "ahci" "megaraid_sas" "sd_mod" ];
+  boot.initrd.kernelModules = [ "dm-snapshot" ];
+  boot.kernelModules = [ "kvm-intel" ];
+
+  boot.loader.grub.enable = true;
+  boot.loader.grub.version = 2;
+  boot.loader.grub.device = "/dev/sda";
+
+  networking.firewall.enable = false;
+  networking.firewall.allowedTCPPorts = [ 80 443 ];
+  networking.useDHCP = false;
+  networking.interfaces.eth0.useDHCP = true;
+  networking.interfaces.eth0.ipv6.addresses = [
+    { address = pkgs.lib.head config.hostEnv.ips.main.ip6; prefixLength = 64; }
+  ];
+  networking.defaultGateway6 = { address = "fe80::1"; interface = "eth0"; };
+  services.udev.extraRules = ''
+    ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="c8:60:00:8b:2f:f0", NAME="eth0"
+  '';
+  security.pam.services.chage.text = ''
+    auth      sufficient pam_rootok.so
+    auth      required   pam_unix.so
+    account   required   pam_unix.so
+    session   required   pam_unix.so
+    password  required   pam_permit.so
+  '';
+  security.pam.services.sshd.makeHomeDir = true;
+  security.pam.services.passwd_default = {};
+  security.pam.services.passwd.text = ''
+    password        required        pam_cracklib.so enforce_for_root difok=2 minlen=8 dcredit=2 ocredit=2 retry=3
+  '' + config.security.pam.services.passwd_default.text;
+
+  system.activationScripts.ldapSync = {
+    deps = [ "secrets" "users" ];
+    text =
+      let
+        com = "-D cn=root,dc=salle-s,dc=org -y /var/secrets/ldap/sync_password";
+      in ''
+      # Add users
+      ${pkgs.openldap}/bin/ldapadd -c ${com} -f /var/secrets/ldap/ldaptree.ldif 2>/dev/null >/dev/null || true
+
+      # Remove obsolete users
+      ${pkgs.openldap}/bin/ldapsearch -LLL ${com} -s one -b "ou=users,dc=salle-s,dc=org" "uid" |\
+        grep "^uid" | ${pkgs.gnused}/bin/sed -e "s/uid: //" | while read ldapuser; do
+
+        for user in ${builtins.concatStringsSep " " (builtins.attrNames normalUsers)}; do
+          if [ "$user" = "$ldapuser" ]; then
+            continue 2
+          fi
+        done
+        ${pkgs.openldap}/bin/ldapdelete -r ${com} uid=$ldapuser,ou=users,dc=salle-s,dc=org
+      done
+
+      # Subusers
+      if [ -f /var/lib/nixos/sponsored_users ]; then
+        cat /var/lib/nixos/sponsored_users | while read mainUser subUser name; do
+          (${pkgs.openldap}/bin/ldapadd -c ${com} 2>/dev/null >/dev/null || true) <<EOF
+      dn: uid=$subUser,uid=$mainUser,ou=users,dc=salle-s,dc=org
+      objectClass: inetOrgPerson
+      cn: $subUser
+      description:: $(echo -n "$name" | base64)
+      sn: $subUser
+      uid: $subUser
+      EOF
+        done
+      fi
+    '';
+  };
+
+  secrets.keys = [
+    {
+      dest = "ldap/sync_password";
+      permissions = "0400";
+      text = serverSpecificConfig.ldap_sync_password;
+    }
+    {
+      dest = "ldap/ldaptree.ldif";
+      permissions = "0400";
+      text = serverSpecificConfig.ldap_service_users
+        + (builtins.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
+        dn: uid=${n},ou=users,dc=salle-s,dc=org
+        objectClass: inetOrgPerson
+        cn: ${n}
+        description: ${v._meta.name or n} ${v._meta.email}
+        sn: ${n}
+        uid: ${n}
+      '') normalUsers));
+    }
+  ];
+
+  myServices.certificates.enable = true;
+  users.mutableUsers = true;
+  system.stateVersion = "21.03";
+  programs.zsh.enable = true;
+
+  users.motd = ''
+    Bienvenue sur quatresaisons.salle-s.org !
+
+    * Charte :
+      https://4c.salle-s.org/charte
+    * Gérer les utilisateurs unix additionnels :
+      sudo sponsored_user -h
+    * Applications web :
+      * tableau de bord : https://4c.salle-s.org/
+      * nextcloud : https://nextcloud.4c.salle-s.org/
+  '';
+
+  users.groups =
+    lib.mapAttrs (n: v: { gid = v.uid; }) normalUsers
+    // { wwwrun = { gid = config.ids.gids.wwwrun; }; };
+  users.users =
+    let
+      defaultNormal = n: {
+        group = n;
+        extraGroups = [ "users" ];
+        isNormalUser = true;
+      };
+    in
+      lib.mapAttrs (n: v: defaultNormal n // (lib.filterAttrs (k: _: k != "_meta") v)) normalUsers
+      // {
+        sponsored-separator = {
+          uid = 10000;
+          group = "users";
+          home = "/var/empty";
+          extraGroups = [];
+          isNormalUser = true;
+          createHome = false;
+        };
+        wwwrun = {
+          group = "wwwrun";
+          description = "Apache httpd user";
+          uid = config.ids.uids.wwwrun;
+          extraGroups = [ "keys" ];
+        };
+      };
+
+  system.activationScripts.usersPost = {
+    deps = [ "users" "groups" ];
+    text = builtins.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
+      if getent shadow "${n}" | grep -q '^${n}:${v.initialHashedPassword or "!"}:1'; then
+        chage -d 0 "${n}"
+        [ '${v.initialHashedPassword or "!"}' = '!' ] && passwd -d "${n}"
+      fi
+    '') normalUsers);
+  };
+  security.sudo.extraRules = [
+    {
+      commands = [
+        { command = "${sponsoredUser}/bin/sponsored_user"; options = [ "NOPASSWD" ]; }
+      ];
+      users = builtins.attrNames normalUsers;
+      runAs = "root";
+    }
+  ];
+
+  environment.systemPackages = [
+    sponsoredUser
+    pkgs.git
+    pkgs.vim
+    pkgs.rsync
+    pkgs.strace
+    pkgs.home-manager
+    pkgs.telnet
+    pkgs.htop
+    pkgs.iftop
+    pkgs.bind.dnsutils
+    pkgs.httpie
+    pkgs.iotop
+    pkgs.whois
+    pkgs.ngrep
+    pkgs.tcpdump
+    pkgs.tshark
+    pkgs.tcpflow
+    pkgs.nmap
+    pkgs.p0f
+    pkgs.socat
+    pkgs.lsof
+    pkgs.psmisc
+    pkgs.openssl
+    pkgs.wget
+    pkgs.pv
+    pkgs.smartmontools
+  ];
+
+  services.websites.env.production = {
+    enable = true;
+    adminAddr = "httpd@immae.eu";
+    httpdName = "Prod";
+    modules = [ "http2" "deflate" "filter" ];
+    extraConfig = [
+      ''
+        LogFormat "%{Host}i:%p %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedVhost
+        Protocols h2 http/1.1
+        AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript
+      '' ];
+    ips =
+      let ips = config.hostEnv.ips.main;
+      in [ips.ip4] ++ (ips.ip6 or []);
+
+    fallbackVhost = {
+      certName    = "quatresaisons";
+      hosts       = [ "quatresaisons.immae.eu" ];
+      root        = pkgs.runCommand "empty" {} "mkdir $out && touch $out/index.html";
+      extraConfig = [ "DirectoryIndex index.html" ];
+    };
+    vhostConfs.salle-s = {
+      certName = "quatresaisons";
+      addToCerts = true;
+      hosts = [ "salle-s.org" ];
+      root = toLanding ./quatresaisons/landing.yml;
+      extraConfig = [
+        ''
+          <Directory ${toLanding ./quatresaisons/landing.yml}>
+            AllowOverride None
+            Require all granted
+            DirectoryIndex index.html
+          </Directory>
+      ''
+      ];
+    };
+    vhostConfs.tools = {
+      certName = "quatresaisons";
+      addToCerts = true;
+      hosts = [ "4c.salle-s.org" "quatresaisons.salle-s.org" "quatre-saisons.salle-s.org" ];
+      root = toLanding ./quatresaisons/landing_4c.yml;
+      extraConfig = [
+        ''
+          Alias /charte ${serverSpecificConfig.charte_path}
+          <Directory ${serverSpecificConfig.charte_path}>
+            AllowOverride None
+            Require all granted
+            DirectoryIndex index.html index.txt
+          </Directory>
+
+          <Directory ${toLanding ./quatresaisons/landing_4c.yml}>
+            AllowOverride None
+            Require all granted
+            DirectoryIndex index.html
+          </Directory>
+      ''
+      ];
+    };
+  };
+  system.activationScripts.httpd = '' 
+    install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php
+    install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php/sessions
+  '';
+
+  services.phpfpm = {
+    phpOptions = ''
+      session.save_path = "/var/lib/php/sessions"
+      post_max_size = 20M
+      ; 15 days (seconds)
+      session.gc_maxlifetime = 1296000
+      ; 30 days (minutes)
+      session.cache_expire = 43200
+      '';
+    settings = {
+      log_level = "notice";
+    };
+  };
+
+}
diff --git a/modules/private/system/quatresaisons/databases.nix b/modules/private/system/quatresaisons/databases.nix
new file mode 100644 (file)
index 0000000..3491ae4
--- /dev/null
@@ -0,0 +1,146 @@
+{ pkgs, config, lib, ... }:
+{
+  config = let
+    serverSpecificConfig = config.myEnv.serverSpecific.quatresaisons;
+    phpLdapAdmin = pkgs.webapps.phpldapadmin.override { config = "/var/secrets/webapps/tools-ldap"; };
+  in {
+    services.postgresql.enable = true;
+    services.postgresql.package = pkgs.postgresql_12;
+    secrets.keys = [
+      {
+        dest = "ldap/password";
+        permissions = "0400";
+        user = "openldap";
+        group = "openldap";
+        text = "rootpw      ${serverSpecificConfig.ldap_root_pw}";
+      }
+      {
+        dest = "webapps/tools-ldap";
+        user = "wwwrun";
+        group = "wwwrun";
+        permissions = "0400";
+        text = ''
+          <?php
+          $config->custom->appearance['show_clear_password'] = true;
+          $config->custom->appearance['hide_template_warning'] = true;
+          $config->custom->appearance['theme'] = "tango";
+          $config->custom->appearance['minimalMode'] = false;
+          $config->custom->appearance['tree'] = 'AJAXTree';
+
+          $servers = new Datastore();
+
+          $servers->newServer('ldap_pla');
+          $servers->setValue('server','name','LDAP');
+          $servers->setValue('server','host','ldap://localhost');
+          $servers->setValue('login','auth_type','cookie');
+          $servers->setValue('login','bind_id','${serverSpecificConfig.ldap_phpldapadmin_dn}');
+          $servers->setValue('login','bind_pass','${serverSpecificConfig.ldap_phpldapadmin_password}');
+          $servers->setValue('appearance','pla_password_hash','ssha');
+          $servers->setValue('login','attr','uid');
+          $servers->setValue('login','fallback_dn',true);
+        '';
+      }
+    ];
+
+    users.users.openldap.extraGroups = [ "keys" ];
+    services.openldap = {
+      enable = true;
+      dataDir = "/var/lib/openldap";
+      urlList = [ "ldap://localhost" ];
+      logLevel = "none";
+      extraConfig = ''
+        pidfile     /run/slapd/slapd.pid
+        argsfile    /run/slapd/slapd.args
+
+        moduleload  back_hdb
+        backend     hdb
+      '';
+
+      extraDatabaseConfig = ''
+        moduleload  memberof
+        overlay     memberof
+
+        moduleload  syncprov
+        overlay     syncprov
+        syncprov-checkpoint 100 10
+
+        index   objectClass       eq
+        index   uid               pres,eq
+        #index   uidMember         pres,eq
+        index   mail              pres,sub,eq
+        index   cn                pres,sub,eq
+        index   sn                pres,sub,eq
+        index   dc                eq
+        index   member            eq
+        index   memberOf          eq
+
+        # No one must access that information except root
+        access to attrs=description
+          by * none
+
+        access to attrs=entry,uid filter="(uid=*)"
+          by dn.exact="${serverSpecificConfig.ldap_phpldapadmin_dn}" read
+          by * break
+
+        access to dn.subtree="ou=users,dc=salle-s,dc=org"
+          by dn.subtree="ou=services,dc=salle-s,dc=org" read
+          by * break
+
+        access to *
+          by self read
+          by anonymous auth
+          by * break
+      '';
+      rootpwFile = "${config.secrets.location}/ldap/password";
+      suffix = "dc=salle-s,dc=org";
+      rootdn = "cn=root,dc=salle-s,dc=org";
+      database = "hdb";
+    };
+
+    services.websites.env.production.modules = [ "proxy_fcgi" ];
+    services.websites.env.production.vhostConfs.tools.extraConfig = [
+      ''
+        Alias /ldap "${phpLdapAdmin}/htdocs"
+        <Directory "${phpLdapAdmin}/htdocs">
+          DirectoryIndex index.php
+          <FilesMatch "\.php$">
+            SetHandler "proxy:unix:${config.services.phpfpm.pools.ldap.socket}|fcgi://localhost"
+          </FilesMatch>
+
+          AllowOverride None
+          Require all granted
+        </Directory>
+      ''
+    ];
+    services.phpfpm.pools.ldap = {
+      user = "wwwrun";
+      group = "wwwrun";
+      settings =
+        let
+          basedir = builtins.concatStringsSep ":" [ phpLdapAdmin "/var/secrets/webapps/tools-ldap" ];
+        in {
+          "listen.owner" = "wwwrun";
+          "listen.group" = "wwwrun";
+          "pm" = "ondemand";
+          "pm.max_children" = "60";
+          "pm.process_idle_timeout" = "60";
+
+          # Needed to avoid clashes in browser cookies (same domain)
+          "php_value[session.name]" = "LdapPHPSESSID";
+          "php_admin_value[open_basedir]" = "${basedir}:/tmp:/var/lib/php/sessions/phpldapadmin";
+          "php_admin_value[session.save_path]" = "/var/lib/php/sessions/phpldapadmin";
+        };
+      phpPackage = pkgs.php72;
+    };
+    system.activationScripts.ldap = {
+      deps = [ "users" ];
+      text = ''
+        install -m 0755 -o wwwrun -g wwwrun -d /var/lib/php/sessions/phpldapadmin
+        '';
+    };
+    systemd.services.phpfpm-ldap = {
+      after = lib.mkAfter [ "openldap.service" ];
+      wants = [ "openldap.service" ];
+    };
+  };
+}
diff --git a/modules/private/system/quatresaisons/landing.yml b/modules/private/system/quatresaisons/landing.yml
new file mode 100644 (file)
index 0000000..cf4ba87
--- /dev/null
@@ -0,0 +1,32 @@
+---
+# Homepage configuration
+# See https://fontawesome.com/icons for icons options
+
+title: "Websites dashboard"
+subtitle: "Salle-S"
+footer: false
+#footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>'  # set false if you want to hide it.
+
+# Optional navbar
+# links: [] # Allows for navbar (dark mode, layout, and search) without any links
+links: []
+
+# Services
+# First level array represent a group.
+# Leave only a "items" key if not using group (group name, icon & tagstyle are optional, section separation will not be displayed).
+services:
+  - name: "Quatramaran"
+    items:
+      - name: "Roundcube"
+        logo: "assets/tools/roundcube.svg"
+        url: "https://quatramaran.salle-s.org/roundcube/"
+      - name: "Les dessous de paillasse"
+        url: "https://dessous-de-paillasse.salle-s.org"
+  - name: "Quatre Saisons"
+    items:
+      - name: "Charte d’utilisation"
+        icon: "fas fa-scroll"
+        url: "https://4c.salle-s.org/charte/"
+      - name: "Nextcloud"
+        logo: "assets/tools/nextcloud.png"
+        url: "https://nextcloud.4c.salle-s.org"
diff --git a/modules/private/system/quatresaisons/landing_4c.yml b/modules/private/system/quatresaisons/landing_4c.yml
new file mode 100644 (file)
index 0000000..0b9f6b6
--- /dev/null
@@ -0,0 +1,24 @@
+---
+# Homepage configuration
+# See https://fontawesome.com/icons for icons options
+
+title: "Websites dashboard"
+subtitle: "Quatre saisons"
+footer: false
+#footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>'  # set false if you want to hide it.
+
+# Optional navbar
+# links: [] # Allows for navbar (dark mode, layout, and search) without any links
+links: []
+
+# Services
+# First level array represent a group.
+# Leave only a "items" key if not using group (group name, icon & tagstyle are optional, section separation will not be displayed).
+services:
+  - items:
+      - name: "Charte d’utilisation"
+        icon: "fas fa-scroll"
+        url: "https://4c.salle-s.org/charte/"
+      - name: "Nextcloud"
+        logo: "assets/tools/nextcloud.png"
+        url: "https://nextcloud.4c.salle-s.org"
diff --git a/modules/private/system/quatresaisons/nextcloud.nix b/modules/private/system/quatresaisons/nextcloud.nix
new file mode 100644 (file)
index 0000000..047d17e
--- /dev/null
@@ -0,0 +1,141 @@
+{ lib, pkgs, config,  ... }:
+let
+  nextcloud = pkgs.webapps.nextcloud.withApps (a: [
+    a.apporder a.audioplayer a.bookmarks a.calendar a.carnet a.circles
+    a.contacts a.cookbook a.deck a.extract a.files_markdown
+    a.files_readmemd a.flowupload a.gpxedit a.gpxpod a.keeweb a.maps
+    a.metadata a.music a.notes a.ocsms a.passman a.polls a.spreed
+    a.social a.tasks
+  ]);
+  varDir = "/var/lib/nextcloud";
+  phpFpm = rec {
+    basedir = builtins.concatStringsSep ":" ([ nextcloud varDir ] ++ nextcloud.apps);
+    pool = {
+      "listen.owner" = "wwwrun";
+      "listen.group" = "wwwrun";
+      "pm" = "ondemand";
+      "pm.max_children" = "60";
+      "pm.process_idle_timeout" = "60";
+
+      "php_admin_value[output_buffering]" = "0";
+      "php_admin_value[max_execution_time]" = "1800";
+      "php_admin_value[zend_extension]" = "opcache";
+      #already enabled by default?
+      #"php_value[opcache.enable]" = "1";
+      "php_value[opcache.enable_cli]" = "1";
+      "php_value[opcache.interned_strings_buffer]" = "8";
+      "php_value[opcache.max_accelerated_files]" = "10000";
+      "php_value[opcache.memory_consumption]" = "128";
+      "php_value[opcache.save_comments]" = "1";
+      "php_value[opcache.revalidate_freq]" = "1";
+      "php_admin_value[memory_limit]" = "512M";
+
+      "php_admin_value[open_basedir]" = "/run/wrappers/bin/sendmail:${basedir}:/proc/meminfo:/dev/urandom:/proc/self/fd:/tmp";
+      "php_admin_value[session.save_path]" = "${varDir}/phpSessions";
+    };
+  };
+in {
+  config = {
+    services.postgresql.ensureDatabases = [ "nextcloud" ];
+    services.postgresql.ensureUsers = [
+      { name = "nextcloud"; ensurePermissions = { "DATABASE nextcloud" = "ALL PRIVILEGES"; }; }
+    ];
+    services.websites.env.production.modules = [ "proxy_fcgi" ];
+
+    services.websites.env.production.vhostConfs.cloud = {
+      certName    = "quatresaisons";
+      addToCerts  = true;
+      hosts       = ["nextcloud.4c.salle-s.org" ];
+      root        = nextcloud;
+      extraConfig = 
+        [
+        ''
+          SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
+          <Directory ${nextcloud}>
+            AcceptPathInfo On
+            DirectoryIndex index.php
+            Options FollowSymlinks
+            Require all granted
+            AllowOverride all
+
+            <IfModule mod_headers.c>
+              Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains; preload"
+            </IfModule>
+            <FilesMatch "\.php$">
+              CGIPassAuth on
+              SetHandler "proxy:unix:${config.services.phpfpm.pools.nextcloud.socket}|fcgi://localhost"
+            </FilesMatch>
+
+          </Directory>
+        ''
+      ];
+    };
+    services.websites.env.production.vhostConfs.cloud_wait = let
+      content = pkgs.writeText "contenu" ''
+        nextcloud est un service qui a besoin de pérennité du nom
+        "nextcloud.salle-s.org", on va peut-etre y arriver, c'est une
+        question de jours, voir le message informatique.internet:8017
+      '';
+    in {
+      certName    = "quatresaisons";
+      addToCerts  = true;
+      hosts       = ["nextcloud.salle-s.org" ];
+      root        = content;
+      extraConfig =
+        [
+        ''
+          Alias / ${content}
+        ''
+      ];
+    };
+
+    users.users.root.packages = let
+      occ = pkgs.writeScriptBin "nextcloud-occ" ''
+        #! ${pkgs.stdenv.shell}
+        cd ${nextcloud}
+        NEXTCLOUD_CONFIG_DIR="${nextcloud}/config" \
+          exec \
+          sudo -u wwwrun ${pkgs.php74}/bin/php \
+          -c ${pkgs.php74}/etc/php.ini \
+          occ $*
+        '';
+    in [ occ ];
+
+    system.activationScripts.nextcloud = {
+      deps = [ "users" ];
+      text = let
+        confs = lib.attrsets.mapAttrs (n: v: pkgs.writeText "${n}.json" (builtins.toJSON v)) nextcloud.otherConfig;
+      in
+        ''
+        install -m 0755 -o wwwrun -g wwwrun -d ${varDir}
+        install -m 0755 -o wwwrun -g wwwrun -d ${varDir}/config
+        install -m 0750 -o wwwrun -g wwwrun -d ${varDir}/phpSessions
+        ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (n: v:
+          "install -D -m 0644 -o wwwrun -g wwwrun -T ${v} ${varDir}/config/${n}.json"
+          ) confs)}
+      '';
+    };
+    services.phpfpm.pools.nextcloud = {
+      user = "wwwrun";
+      group = "wwwrun";
+      settings = phpFpm.pool;
+      phpPackage = pkgs.php74.withExtensions({ enabled, all }: enabled ++ [ all.redis all.apcu all.opcache all.imagick ]);
+    };
+
+    services.cron = {
+      enable = true;
+      systemCronJobs = let
+        script = pkgs.writeScriptBin "nextcloud-cron" ''
+          #! ${pkgs.stdenv.shell}
+          export LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive
+          export PATH=/run/wrappers/bin:$PATH
+          ${pkgs.php74}/bin/php -d memory_limit=512M -f ${nextcloud}/cron.php
+          '';
+      in [
+        ''
+          */15 * * * * wwwrun ${script}/bin/nextcloud-cron
+        ''
+      ];
+    };
+  };
+}
index cefd677a056c04dbcc5519b7f953ad8efded1d8b..27d8d959c1363771b73b689e58180bca7a0e4d6f 100644 (file)
@@ -40,6 +40,9 @@ ssh-backup-2:
 ssh-monitoring-1:
        ./scripts/with_env bash -c 'ssh -i $$SSH_IDENTITY_FILE root@monitoring-1 $(SSH_ARGS)'
 
+ssh-4c:
+       ./scripts/with_env bash -c 'ssh -i $$SSH_IDENTITY_FILE root@quatresaisons $(SSH_ARGS)'
+
 debug:
        ./scripts/with_env morph build --show-trace default.nix $(MORPH_ARGS)
 
index 7c6dd380de953a83c75f0208620344cda91ceb18..f048c80c7c445952e39177c72f85b46c2ba42d1e 100644 (file)
@@ -6,4 +6,6 @@ in
   eldiron = import ../modules/private/system/eldiron.nix { inherit privateFiles; };
   backup-2 = import ../modules/private/system/backup-2.nix { inherit privateFiles; };
   monitoring-1 = import ../modules/private/system/monitoring-1.nix { inherit privateFiles; };
+
+  quatresaisons = import ../modules/private/system/quatresaisons.nix { inherit privateFiles; };
 }
index c91ba443bf2849b8fb81fc72818b77be77b3aabf..3475398eed524be65d0516cf2a648b20a2418f3a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c91ba443bf2849b8fb81fc72818b77be77b3aabf
+Subproject commit 3475398eed524be65d0516cf2a648b20a2418f3a