From: Ismaël Bouya Date: Sat, 24 Oct 2020 10:30:42 +0000 (+0200) Subject: Add quatresaisons server X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=75489e72e379af8aeac64bc4967717d9ae776ff0;p=perso%2FImmae%2FConfig%2FNix.git Add quatresaisons server --- diff --git a/Makefile b/Makefile index 9c12ff4..466b63a 100644 --- 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/ $@ diff --git a/modules/private/environment.nix b/modules/private/environment.nix index a8799d2..e79feec 100644 --- a/modules/private/environment.nix +++ b/modules/private/environment.nix @@ -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 index 0000000..395b604 --- /dev/null +++ b/modules/private/system/quatresaisons.nix @@ -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:-}" + + 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) </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) <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 = [ + '' + + AllowOverride None + Require all granted + DirectoryIndex index.html + + '' + ]; + }; + 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} + + AllowOverride None + Require all granted + DirectoryIndex index.html index.txt + + + + AllowOverride None + Require all granted + DirectoryIndex index.html + + '' + ]; + }; + }; + 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 index 0000000..3491ae4 --- /dev/null +++ b/modules/private/system/quatresaisons/databases.nix @@ -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 = '' + 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" + + DirectoryIndex index.php + + SetHandler "proxy:unix:${config.services.phpfpm.pools.ldap.socket}|fcgi://localhost" + + + AllowOverride None + Require all granted + + '' + ]; + 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 index 0000000..cf4ba87 --- /dev/null +++ b/modules/private/system/quatresaisons/landing.yml @@ -0,0 +1,32 @@ +--- +# Homepage configuration +# See https://fontawesome.com/icons for icons options + +title: "Websites dashboard" +subtitle: "Salle-S" +footer: false +#footer: '

Created with ❤️ with bulma, vuejs & font awesome // Fork me on

' # 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 index 0000000..0b9f6b6 --- /dev/null +++ b/modules/private/system/quatresaisons/landing_4c.yml @@ -0,0 +1,24 @@ +--- +# Homepage configuration +# See https://fontawesome.com/icons for icons options + +title: "Websites dashboard" +subtitle: "Quatre saisons" +footer: false +#footer: '

Created with ❤️ with bulma, vuejs & font awesome // Fork me on

' # 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 index 0000000..047d17e --- /dev/null +++ b/modules/private/system/quatresaisons/nextcloud.nix @@ -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 + + AcceptPathInfo On + DirectoryIndex index.php + Options FollowSymlinks + Require all granted + AllowOverride all + + + Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" + + + CGIPassAuth on + SetHandler "proxy:unix:${config.services.phpfpm.pools.nextcloud.socket}|fcgi://localhost" + + + + '' + ]; + }; + 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 + '' + ]; + }; + }; +} diff --git a/nixops/Makefile b/nixops/Makefile index cefd677..27d8d95 100644 --- a/nixops/Makefile +++ b/nixops/Makefile @@ -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) diff --git a/nixops/default.nix b/nixops/default.nix index 7c6dd38..f048c80 100644 --- a/nixops/default.nix +++ b/nixops/default.nix @@ -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; }; } diff --git a/nixops/secrets b/nixops/secrets index c91ba44..3475398 160000 --- a/nixops/secrets +++ b/nixops/secrets @@ -1 +1 @@ -Subproject commit c91ba443bf2849b8fb81fc72818b77be77b3aabf +Subproject commit 3475398eed524be65d0516cf2a648b20a2418f3a