{ network = { description = "Immae's network"; enableRollback = true; }; eldiron = { config, pkgs, mylibs, ... }: with mylibs; let mypkgs = pkgs.callPackage ./packages.nix { inherit checkEnv fetchedGit fetchedGitPrivate fetchedGithub; }; in { _module.args = { mylibs = import ../libs.nix; }; imports = [ ./modules/certificates.nix ./modules/gitolite.nix ./modules/gitweb.nix ./modules/databases.nix ./modules/websites/chloe.nix ./modules/websites/ludivine.nix ./modules/websites/aten.nix ./modules/websites/piedsjaloux.nix ./modules/websites/connexionswing.nix ]; services.myGitolite.enable = true; services.myGitweb.enable = true; services.myDatabases.enable = true; services.myWebsites.Chloe.production.enable = true; services.myWebsites.Chloe.integration.enable = true; services.myWebsites.Ludivine.production.enable = true; services.myWebsites.Ludivine.integration.enable = true; services.myWebsites.Aten.production.enable = true; services.myWebsites.Aten.integration.enable = true; services.myWebsites.PiedsJaloux.production.enable = true; services.myWebsites.PiedsJaloux.integration.enable = true; services.myWebsites.Connexionswing.production.enable = true; services.myWebsites.Connexionswing.integration.enable = true; nixpkgs.config.packageOverrides = oldpkgs: rec { goaccess = oldpkgs.goaccess.overrideAttrs(old: rec { name = "goaccess-${version}"; version = "1.3"; src = pkgs.fetchurl { url = "https://tar.goaccess.io/${name}.tar.gz"; sha256 = "16vv3pj7pbraq173wlxa89jjsd279004j4kgzlrsk1dz4if5qxwc"; }; configureFlags = old.configureFlags ++ [ "--enable-tcb=btree" ]; buildInputs = old.buildInputs ++ [ pkgs.tokyocabinet pkgs.bzip2 ]; }); }; networking = { firewall = { enable = true; allowedTCPPorts = [ 22 80 443 9418 ]; }; }; deployment = { targetEnv = "hetzner"; hetzner = { #robotUser = "defined in HETZNER_ROBOT_USER"; #robotPass = "defined in HETZNER_ROBOT_PASS"; mainIPv4 = "176.9.151.89"; partitions = '' clearpart --all --initlabel --drives=sda,sdb part swap1 --recommended --label=swap1 --fstype=swap --ondisk=sda part swap2 --recommended --label=swap2 --fstype=swap --ondisk=sdb part raid.1 --grow --ondisk=sda part raid.2 --grow --ondisk=sdb raid / --level=1 --device=md0 --fstype=ext4 --label=root raid.1 raid.2 ''; }; }; environment.systemPackages = let # FIXME: move it to nextcloud occ = pkgs.writeScriptBin "nextcloud-occ" '' #! ${pkgs.stdenv.shell} cd ${mypkgs.nextcloud.webRoot} NEXTCLOUD_CONFIG_DIR="${mypkgs.nextcloud.webRoot}/config" \ exec \ ${config.services.phpfpm.phpPackage}/bin/php \ -c ${config.services.phpfpm.phpPackage}/etc/php.ini \ occ $* ''; in [ pkgs.telnet pkgs.htop pkgs.vim pkgs.goaccess occ ]; security.acme.certs."eldiron".extraDomains = { "db-1.immae.eu" = null; "tools.immae.eu" = null; "cloud.immae.eu" = null; "dav.immae.eu" = null; }; services.openssh.extraConfig = '' AuthorizedKeysCommand /etc/ssh/ldap_authorized_keys AuthorizedKeysCommandUser nobody ''; services.ympd = mypkgs.ympd.config // { enable = false; }; services.phpfpm = { # FIXME: move session files to separate dirs # /!\ phppackage is used in nextcloud configuation phpOptions = '' session.save_path = "/var/lib/php/sessions" session.gc_maxlifetime = 60*60*24*15 session.cache_expire = 60*24*30 ; For nextcloud extension=${pkgs.phpPackages.redis}/lib/php/extensions/redis.so ; For nextcloud extension=${pkgs.phpPackages.apcu}/lib/php/extensions/apcu.so ; For nextcloud zend_extension=${pkgs.php}/lib/php/extensions/opcache.so ''; extraConfig = '' log_level = notice ''; poolConfigs = { adminer = mypkgs.adminer.phpFpm.pool; connexionswing_dev = mypkgs.connexionswing_dev.phpFpm.pool; connexionswing_prod = mypkgs.connexionswing_prod.phpFpm.pool; ludivinecassal_dev = mypkgs.ludivinecassal_dev.phpFpm.pool; ludivinecassal_prod = mypkgs.ludivinecassal_prod.phpFpm.pool; piedsjaloux_dev = mypkgs.piedsjaloux_dev.phpFpm.pool; piedsjaloux_prod = mypkgs.piedsjaloux_prod.phpFpm.pool; chloe_dev = mypkgs.chloe_dev.phpFpm.pool; chloe_prod = mypkgs.chloe_prod.phpFpm.pool; aten_dev = mypkgs.aten_dev.phpFpm.pool; aten_prod = mypkgs.aten_prod.phpFpm.pool; nextcloud = mypkgs.nextcloud.phpFpm.pool; mantisbt = mypkgs.mantisbt.phpFpm.pool; ttrss = mypkgs.ttrss.phpFpm.pool; roundcubemail = mypkgs.roundcubemail.phpFpm.pool; davical = mypkgs.davical.phpFpm.pool; }; }; system.activationScripts = { connexionswing_dev = mypkgs.connexionswing_dev.activationScript; connexionswing_prod = mypkgs.connexionswing_prod.activationScript; ludivinecassal_dev = mypkgs.ludivinecassal_dev.activationScript; ludivinecassal_prod = mypkgs.ludivinecassal_prod.activationScript; piedsjaloux_dev = mypkgs.piedsjaloux_dev.activationScript; piedsjaloux_prod = mypkgs.piedsjaloux_prod.activationScript; chloe_dev = mypkgs.chloe_dev.activationScript; chloe_prod = mypkgs.chloe_prod.activationScript; aten_dev = mypkgs.aten_dev.activationScript; aten_prod = mypkgs.aten_prod.activationScript; nextcloud = mypkgs.nextcloud.activationScript; ttrss = mypkgs.ttrss.activationScript; roundcubemail = mypkgs.roundcubemail.activationScript; httpd = '' install -d -m 0755 /var/lib/acme/acme-challenge install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php/sessions install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php/sessions/adminer install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php/sessions/mantisbt install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php/sessions/ttrss install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php/sessions/davical ''; redis = '' mkdir -p /run/redis chown redis /run/redis ''; # FIXME: initial sync goaccess = '' mkdir -p /var/lib/goaccess mkdir -p /var/lib/goaccess/aten.pro mkdir -p /var/lib/goaccess/ludivinecassal.com mkdir -p /var/lib/goaccess/piedsjaloux.fr mkdir -p /var/lib/goaccess/osteopathe-cc.fr mkdir -p /var/lib/goaccess/connexionswing.com ''; }; environment.etc."ssh/ldap_authorized_keys" = let ldap_authorized_keys = assert checkEnv "NIXOPS_SSHD_LDAP_PASSWORD"; wrap { name = "ldap_authorized_keys"; file = ./ldap_authorized_keys.sh; vars = { LDAP_PASS = builtins.getEnv "NIXOPS_SSHD_LDAP_PASSWORD"; GITOLITE_SHELL = "${pkgs.gitolite}/bin/gitolite-shell"; ECHO = "${pkgs.coreutils}/bin/echo"; }; paths = [ pkgs.openldap pkgs.stdenv.shellPackage pkgs.gnugrep pkgs.gnused pkgs.coreutils ]; }; in { enable = true; mode = "0755"; user = "root"; source = ldap_authorized_keys; }; services.gitDaemon = { enable = true; user = "gitolite"; group = "gitolite"; basePath = "${mypkgs.git.web.varDir}/repositories"; }; # FIXME: logrotate services.httpd = let withConf = domain: { enableSSL = true; sslServerCert = "/var/lib/acme/${domain}/cert.pem"; sslServerKey = "/var/lib/acme/${domain}/key.pem"; sslServerChain = "/var/lib/acme/${domain}/fullchain.pem"; logFormat = "combinedVhost"; listen = [ { ip = "*"; port = 443; } ]; }; apacheConfig = { gzip = { modules = [ "deflate" "filter" ]; extraConfig = '' AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript ''; }; ldap = { modules = [ "ldap" "authnz_ldap" ]; extraConfig = assert checkEnv "NIXOPS_HTTP_LDAP_PASSWORD"; '' LDAPSharedCacheSize 500000 LDAPCacheEntries 1024 LDAPCacheTTL 600 LDAPOpCacheEntries 1024 LDAPOpCacheTTL 600 AuthLDAPURL ldap://ldap.immae.eu:389/dc=immae,dc=eu AuthLDAPBindDN cn=httpd,ou=services,dc=immae,dc=eu AuthLDAPBindPassword "${builtins.getEnv "NIXOPS_HTTP_LDAP_PASSWORD"}" AuthType Basic AuthName "Authentification requise (Acces LDAP)" AuthBasicProvider ldap Alias /awstats /var/lib/goaccess/%{domain} DirectoryIndex index.html AllowOverride None Require all granted Use LDAPConnect Require ldap-group cn=%{domain},ou=stats,cn=httpd,ou=services,dc=immae,dc=eu ''; }; http2 = { modules = [ "http2" ]; extraConfig = '' Protocols h2 http/1.1 ''; }; customLog = { modules = []; extraConfig = '' LogFormat "%v:%p %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedVhost ''; }; }; in rec { enable = true; logPerVirtualHost = true; multiProcessingModule = "worker"; adminAddr = "httpd@immae.eu"; logFormat = "combinedVhost"; extraModules = pkgs.lib.lists.unique ( mypkgs.adminer.apache.modules ++ mypkgs.nextcloud.apache.modules ++ mypkgs.connexionswing_dev.apache.modules ++ mypkgs.connexionswing_prod.apache.modules ++ mypkgs.ludivinecassal_dev.apache.modules ++ mypkgs.ludivinecassal_prod.apache.modules ++ mypkgs.piedsjaloux_dev.apache.modules ++ mypkgs.piedsjaloux_prod.apache.modules ++ mypkgs.chloe_dev.apache.modules ++ mypkgs.chloe_prod.apache.modules ++ mypkgs.aten_dev.apache.modules ++ mypkgs.aten_prod.apache.modules ++ mypkgs.ympd.apache.modules ++ mypkgs.git.web.apache.modules ++ mypkgs.mantisbt.apache.modules ++ mypkgs.ttrss.apache.modules ++ mypkgs.roundcubemail.apache.modules ++ pkgs.lib.lists.flatten (pkgs.lib.attrsets.mapAttrsToList (n: v: v.modules) apacheConfig) ++ [ "macro" ]); extraConfig = builtins.concatStringsSep "\n" (pkgs.lib.attrsets.mapAttrsToList (n: v: v.extraConfig) apacheConfig); virtualHosts = [ (withConf "eldiron" // { hostName = "eldiron.immae.eu"; documentRoot = ./www; extraConfig = '' DirectoryIndex index.htm ''; }) (withConf "eldiron" // { hostName = "db-1.immae.eu"; documentRoot = null; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.adminer.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "tools.immae.eu"; documentRoot = null; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.adminer.apache.vhostConf mypkgs.ympd.apache.vhostConf mypkgs.ttrss.apache.vhostConf mypkgs.roundcubemail.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "dav.immae.eu"; documentRoot = null; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.infcloud.apache.vhostConf mypkgs.davical.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "connexionswing.immae.eu"; serverAliases = [ "sandetludo.immae.eu" ]; documentRoot = mypkgs.connexionswing_dev.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.connexionswing_dev.apache.vhostConf ]; }) (withConf "connexionswing" // { hostName = "connexionswing.com"; serverAliases = [ "sandetludo.com" "www.connexionswing.com" "www.sandetludo.com" ]; documentRoot = mypkgs.connexionswing_prod.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.connexionswing_prod.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "ludivine.immae.eu"; documentRoot = mypkgs.ludivinecassal_dev.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.ludivinecassal_dev.apache.vhostConf ]; }) (withConf "ludivinecassal" // { hostName = "ludivinecassal.com"; serverAliases = [ "www.ludivinecassal.com" ]; documentRoot = mypkgs.ludivinecassal_prod.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.ludivinecassal_prod.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "piedsjaloux.immae.eu"; documentRoot = mypkgs.piedsjaloux_dev.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.piedsjaloux_dev.apache.vhostConf ]; }) (withConf "piedsjaloux" // { hostName = "piedsjaloux.fr"; serverAliases = [ "www.piedsjaloux.fr" ]; documentRoot = mypkgs.piedsjaloux_prod.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.piedsjaloux_prod.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "chloe.immae.eu"; documentRoot = mypkgs.chloe_dev.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.chloe_dev.apache.vhostConf ]; }) (withConf "chloe" // { hostName = "osteopathe-cc.fr"; serverAliases = [ "www.osteopathe-cc.fr" ]; documentRoot = mypkgs.chloe_prod.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.chloe_prod.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "dev.aten.pro"; documentRoot = mypkgs.aten_dev.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.aten_dev.apache.vhostConf ]; }) (withConf "aten" // { hostName = "aten.pro"; serverAliases = [ "www.aten.pro" ]; documentRoot = mypkgs.aten_prod.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.aten_prod.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "cloud.immae.eu"; documentRoot = mypkgs.nextcloud.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.nextcloud.apache.vhostConf ]; }) (withConf "eldiron" // { hostName = "git.immae.eu"; documentRoot = mypkgs.git.web.webRoot; extraConfig = builtins.concatStringsSep "\n" [ mypkgs.git.web.apache.vhostConf mypkgs.mantisbt.apache.vhostConf ] + '' RewriteEngine on RewriteCond %{REQUEST_URI} ^/releases RewriteRule /releases(.*) https://release.immae.eu$1 [P,L] ''; }) { # Should go last, default fallback listen = [ { ip = "*"; port = 80; } ]; hostName = "redirectSSL"; serverAliases = [ "*" ]; enableSSL = false; logFormat = "combinedVhost"; documentRoot = "/var/lib/acme/acme-challenge"; extraConfig = '' RewriteEngine on RewriteCond "%{REQUEST_URI}" "!^/\.well-known" RewriteRule ^(.+) https://%{HTTP_HOST}$1 [R=301] # To redirect in specific "VirtualHost *:80", do # RedirectMatch 301 ^/((?!\.well-known.*$).*)$ https://host/$1 # rather than rewrite ''; } ]; }; services.cron = { enable = true; systemCronJobs = let stats = domain: conf: let d = pkgs.writeScriptBin "stats-${domain}" '' #!${pkgs.stdenv.shell} set -e shopt -s nullglob date_regex=$(LC_ALL=C date -d yesterday +'%d\/%b\/%Y') TMPFILE=$(mktemp) trap "rm -f $TMPFILE" EXIT cat /var/log/httpd/access_log-${domain} | sed -n "/\\[$date_regex/ p" > $TMPFILE for i in /var/log/httpd/access_log-${domain}*.gz; do zcat "$i" | sed -n "/\\[$date_regex/ p" >> $TMPFILE done goaccess $TMPFILE --no-progress -o /var/lib/goaccess/${domain}/index.html -p ${conf} ''; in "${d}/bin/stats-${domain}"; # FIXME: running several goaccess simultaneously seems to be # bugged? in [ "5 0 * * * root ${stats "aten.pro" ./packages/aten_goaccess.conf}" "6 0 * * * root ${stats "ludivinecassal.com" ./packages/ludivinecassal_goaccess.conf}" "7 0 * * * root ${stats "piedsjaloux.fr" ./packages/piedsjaloux_goaccess.conf}" "8 0 * * * root ${stats "osteopathe-cc.fr" ./packages/chloe_goaccess.conf}" "9 0 * * * root ${stats "connexionswing.com" ./packages/connexionswing_goaccess.conf}" ]; }; systemd.services.tt-rss = { description = "Tiny Tiny RSS feeds update daemon"; serviceConfig = { User = "wwwrun"; ExecStart = "${pkgs.php}/bin/php ${mypkgs.ttrss.webRoot}/update.php --daemon"; StandardOutput = "syslog"; StandardError = "syslog"; PermissionsStartOnly = true; }; wantedBy = [ "multi-user.target" ]; requires = ["postgresql.service"]; after = ["network.target" "postgresql.service"]; }; }; }