aboutsummaryrefslogtreecommitdiff
path: root/nixops/modules/websites/commons
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2019-01-25 23:15:08 +0100
committerIsmaël Bouya <ismael.bouya@normalesup.org>2019-01-25 23:15:08 +0100
commit01f21083a897b86bf148f1d2bb9c8edca4d3786a (patch)
tree784f04e9b6ef99a49e572c84e4b7ab40b5eb5fde /nixops/modules/websites/commons
parentbfe3c9c9df0c5112bc8806483292b55ed0f7e02d (diff)
downloadNix-01f21083a897b86bf148f1d2bb9c8edca4d3786a.tar.gz
Nix-01f21083a897b86bf148f1d2bb9c8edca4d3786a.tar.zst
Nix-01f21083a897b86bf148f1d2bb9c8edca4d3786a.zip
Rename virtual folder to nixops
Fixes https://git.immae.eu/mantisbt/view.php?id=82
Diffstat (limited to 'nixops/modules/websites/commons')
-rw-r--r--nixops/modules/websites/commons/adminer.nix65
-rw-r--r--nixops/modules/websites/commons/composer-env.nix280
-rw-r--r--nixops/modules/websites/commons/spip/spip_ldap_patch.patch60
-rw-r--r--nixops/modules/websites/commons/spip/spip_mes_options.php18
-rw-r--r--nixops/modules/websites/commons/stats.nix67
5 files changed, 490 insertions, 0 deletions
diff --git a/nixops/modules/websites/commons/adminer.nix b/nixops/modules/websites/commons/adminer.nix
new file mode 100644
index 0000000..891046f
--- /dev/null
+++ b/nixops/modules/websites/commons/adminer.nix
@@ -0,0 +1,65 @@
1{ stdenv, fetchurl, nginx }:
2let
3 adminer = rec {
4 webRoot = stdenv.mkDerivation rec {
5 version = "4.7.0";
6 name = "adminer-${version}";
7 src = fetchurl {
8 url = "https://www.adminer.org/static/download/${version}/${name}.php";
9 sha256 = "1qq2g7rbfh2vrqfm3g0bz0qs057b049n0mhabnsbd1sgnpvnc5z7";
10 };
11 phases = "installPhase";
12 installPhase = ''
13 mkdir -p $out
14 cp $src $out/index.php
15 '';
16 };
17 phpFpm = rec {
18 socket = "/var/run/phpfpm/adminer.sock";
19 pool = ''
20 listen = ${socket}
21 user = ${apache.user}
22 group = ${apache.group}
23 listen.owner = ${apache.user}
24 listen.group = ${apache.group}
25 pm = ondemand
26 pm.max_children = 5
27 pm.process_idle_timeout = 60
28 ;php_admin_flag[log_errors] = on
29 ; Needed to avoid clashes in browser cookies (same domain)
30 php_value[session.name] = AdminerPHPSESSID
31 php_admin_value[open_basedir] = "${webRoot}:/tmp"
32 php_admin_value[session.save_path] = "/var/lib/php/sessions/adminer"
33 '';
34 };
35 apache = {
36 user = "wwwrun";
37 group = "wwwrun";
38 modules = [ "proxy_fcgi" ];
39 vhostConf = ''
40 Alias /adminer ${webRoot}
41 <Directory ${webRoot}>
42 DirectoryIndex index.php
43 Require all granted
44 <FilesMatch "\.php$">
45 SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost"
46 </FilesMatch>
47 </Directory>
48 '';
49 };
50 nginxConf = {
51 alias = webRoot;
52 index = "index.php";
53 extraConfig = ''
54 include ${nginx}/conf/fastcgi.conf;
55 fastcgi_split_path_info ^(.+?\.php)(/.*)$;
56 fastcgi_param HTTP_PROXY "";
57 fastcgi_param SCRIPT_FILENAME ${webRoot}/index.php;
58 fastcgi_pass unix:${phpFpm.socket};
59 fastcgi_index index.php;
60 fastcgi_intercept_errors on;
61 '';
62 };
63 };
64in
65 adminer
diff --git a/nixops/modules/websites/commons/composer-env.nix b/nixops/modules/websites/commons/composer-env.nix
new file mode 100644
index 0000000..416a61c
--- /dev/null
+++ b/nixops/modules/websites/commons/composer-env.nix
@@ -0,0 +1,280 @@
1# This file originates from composer2nix
2
3{ stdenv, writeTextFile, fetchurl, php, unzip }:
4
5let
6 composer = stdenv.mkDerivation {
7 name = "composer-1.8.0";
8 src = fetchurl {
9 url = https://github.com/composer/composer/releases/download/1.8.0/composer.phar;
10 sha256 = "19pg9ip2mpyf5cyq34fld7qwl77mshqw3c4nif7sxmpnar6sh089";
11 };
12 buildInputs = [ php ];
13
14 # We must wrap the composer.phar because of the impure shebang.
15 # We cannot use patchShebangs because the executable verifies its own integrity and will detect that somebody has tampered with it.
16
17 buildCommand = ''
18 # Copy phar file
19 mkdir -p $out/share/php
20 cp $src $out/share/php/composer.phar
21 chmod 755 $out/share/php/composer.phar
22
23 # Create wrapper executable
24 mkdir -p $out/bin
25 cat > $out/bin/composer <<EOF
26 #! ${stdenv.shell} -e
27 exec ${php}/bin/php $out/share/php/composer.phar "\$@"
28 EOF
29 chmod +x $out/bin/composer
30 '';
31 meta = {
32 description = "Dependency Manager for PHP";
33 #license = stdenv.licenses.mit;
34 maintainers = [ stdenv.lib.maintainers.sander ];
35 platforms = stdenv.lib.platforms.unix;
36 };
37 };
38
39 buildZipPackage = { name, src }:
40 stdenv.mkDerivation {
41 inherit name src;
42 buildInputs = [ unzip ];
43 buildCommand = ''
44 unzip $src
45 baseDir=$(find . -type d -mindepth 1 -maxdepth 1)
46 cd $baseDir
47 mkdir -p $out
48 mv * $out
49 '';
50 };
51
52 buildPackage =
53 { name
54 , src
55 , packages ? {}
56 , devPackages ? {}
57 , buildInputs ? []
58 , symlinkDependencies ? false
59 , executable ? false
60 , removeComposerArtifacts ? false
61 , postInstall ? ""
62 , preInstall ? ""
63 , noDev ? false
64 , unpackPhase ? "true"
65 , buildPhase ? "true"
66 , doRemoveVendor ? true
67 , ...}@args:
68
69 let
70 reconstructInstalled = writeTextFile {
71 name = "reconstructinstalled.php";
72 executable = true;
73 text = ''
74 #! ${php}/bin/php
75 <?php
76 if(file_exists($argv[1]))
77 {
78 $composerLockStr = file_get_contents($argv[1]);
79
80 if($composerLockStr === false)
81 {
82 fwrite(STDERR, "Cannot open composer.lock contents\n");
83 exit(1);
84 }
85 else
86 {
87 $config = json_decode($composerLockStr, true);
88
89 if(array_key_exists("packages", $config))
90 $allPackages = $config["packages"];
91 else
92 $allPackages = array();
93
94 ${stdenv.lib.optionalString (!noDev) ''
95 if(array_key_exists("packages-dev", $config))
96 $allPackages = array_merge($allPackages, $config["packages-dev"]);
97 ''}
98
99 $packagesStr = json_encode($allPackages, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
100 print($packagesStr);
101 }
102 }
103 else
104 print("[]");
105 ?>
106 '';
107 };
108
109 constructBin = writeTextFile {
110 name = "constructbin.php";
111 executable = true;
112 text = ''
113 #! ${php}/bin/php
114 <?php
115 $composerJSONStr = file_get_contents($argv[1]);
116
117 if($composerJSONStr === false)
118 {
119 fwrite(STDERR, "Cannot open composer.json contents\n");
120 exit(1);
121 }
122 else
123 {
124 $config = json_decode($composerJSONStr, true);
125
126 if(array_key_exists("bin-dir", $config))
127 $binDir = $config["bin-dir"];
128 else
129 $binDir = "bin";
130
131 if(array_key_exists("bin", $config))
132 {
133 if(!file_exists("vendor/".$binDir))
134 mkdir("vendor/".$binDir);
135
136 foreach($config["bin"] as $bin)
137 symlink("../../".$bin, "vendor/".$binDir."/".basename($bin));
138 }
139 }
140 ?>
141 '';
142 };
143
144 bundleDependencies = dependencies:
145 stdenv.lib.concatMapStrings (dependencyName:
146 let
147 dependency = dependencies.${dependencyName};
148 in
149 ''
150 ${if dependency.targetDir == "" then ''
151 vendorDir="$(dirname ${dependencyName})"
152 mkdir -p "$vendorDir"
153 ${if symlinkDependencies then
154 ''ln -s "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
155 else
156 ''cp -a "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
157 }${if dependency.needsModifyRights or false then "\n" + ''
158 chmod -R u+rwx "$vendorDir/$(basename "${dependencyName}")"
159 '' else ""}
160 '' else ''
161 namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")"
162 mkdir -p "$namespaceDir"
163 ${if symlinkDependencies then
164 ''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
165 else
166 ''cp -a "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
167 }${if dependency.needsModifyRights or false then "\n" + ''
168 chmod -R u+rwx "$namespaceDir/$(basename "${dependency.targetDir}")"
169 '' else ""}
170 ''}
171 '') (builtins.attrNames dependencies);
172
173 extraArgs = removeAttrs args [ "name" "packages" "devPackages" "buildInputs" ];
174 in
175 stdenv.mkDerivation ({
176 name = "composer-${name}";
177 buildInputs = [ php composer ] ++ buildInputs;
178
179 inherit unpackPhase buildPhase;
180
181 installPhase = ''
182 ${if executable then ''
183 mkdir -p $out/share/php
184 cp -a $src $out/share/php/$name
185 chmod -R u+w $out/share/php/$name
186 cd $out/share/php/$name
187 '' else ''
188 cp -a $src $out
189 chmod -R u+w $out
190 cd $out
191 ''}
192
193 # Execute pre install hook
194 runHook preInstall
195
196 # Remove unwanted files
197 rm -f *.nix
198
199 export HOME=$TMPDIR
200
201 ${if doRemoveVendor then ''
202 # Remove the provided vendor folder if it exists
203 rm -Rf vendor
204 '' else ""}
205 # If there is no composer.lock file, compose a dummy file.
206 # Otherwise, composer attempts to download the package.json file from
207 # the registry which we do not want.
208 if [ ! -f composer.lock ]
209 then
210 cat > composer.lock <<EOF
211 {
212 "packages": []
213 }
214 EOF
215 fi
216
217 # Reconstruct the installed.json file from the lock file
218 mkdir -p vendor/composer
219 ${reconstructInstalled} composer.lock > vendor/composer/installed.json
220
221 # Copy or symlink the provided dependencies
222 cd vendor
223 ${bundleDependencies packages}
224 ${stdenv.lib.optionalString (!noDev) (bundleDependencies devPackages)}
225 cd ..
226
227 # Reconstruct autoload scripts
228 # We use the optimize feature because Nix packages cannot change after they have been built
229 # Using the dynamic loader for a Nix package is useless since there is nothing to dynamically reload.
230 composer dump-autoload --optimize ${stdenv.lib.optionalString noDev "--no-dev"}
231
232 # Run the install step as a validation to confirm that everything works out as expected
233 composer install --optimize-autoloader ${stdenv.lib.optionalString noDev "--no-dev"}
234
235 ${stdenv.lib.optionalString executable ''
236 # Reconstruct the bin/ folder if we deploy an executable project
237 ${constructBin} composer.json
238 ln -s $(pwd)/vendor/bin $out/bin
239 ''}
240
241 ${stdenv.lib.optionalString (!symlinkDependencies) ''
242 # Patch the shebangs if possible
243 if [ -d $(pwd)/vendor/bin ]
244 then
245 # Look for all executables in bin/
246 for i in $(pwd)/vendor/bin/*
247 do
248 # Look for their location
249 realFile=$(readlink -f "$i")
250
251 # Restore write permissions
252 chmod u+wx "$(dirname "$realFile")"
253 chmod u+w "$realFile"
254
255 # Patch shebang
256 sed -e "s|#!/usr/bin/php|#!${php}/bin/php|" \
257 -e "s|#!/usr/bin/env php|#!${php}/bin/php|" \
258 "$realFile" > tmp
259 mv tmp "$realFile"
260 chmod u+x "$realFile"
261 done
262 fi
263 ''}
264
265 if [ "$removeComposerArtifacts" = "1" ]
266 then
267 # Remove composer stuff
268 rm -f composer.json composer.lock
269 fi
270
271 # Execute post install hook
272 runHook postInstall
273 '';
274 } // extraArgs);
275in
276{
277 composer = stdenv.lib.makeOverridable composer;
278 buildZipPackage = stdenv.lib.makeOverridable buildZipPackage;
279 buildPackage = stdenv.lib.makeOverridable buildPackage;
280}
diff --git a/nixops/modules/websites/commons/spip/spip_ldap_patch.patch b/nixops/modules/websites/commons/spip/spip_ldap_patch.patch
new file mode 100644
index 0000000..653c909
--- /dev/null
+++ b/nixops/modules/websites/commons/spip/spip_ldap_patch.patch
@@ -0,0 +1,60 @@
1--- old/ecrire/auth/ldap.php 2017-06-08 21:58:17.000000000 +0200
2+++ new/ecrire/auth/ldap.php 2017-06-10 02:54:02.687954143 +0200
3@@ -171,24 +171,41 @@
4 $desc = isset($ldap['attributes']) && $ldap['attributes'] ? $ldap['attributes'] : $GLOBALS['ldap_attributes'] ;
5
6 $logins = is_array($desc['login']) ? $desc['login'] : array($desc['login']);
7+ if (isset($GLOBALS['ldap_search'])) {
8+ $search_query = str_replace("%user%", $login_search, $GLOBALS['ldap_search']);
9+ $result = @ldap_search($ldap_link, $ldap_base, $search_query, array("dn"));
10+ $info = @ldap_get_entries($ldap_link, $result);
11+ // Ne pas accepter les resultats si plus d'une entree
12+ // (on veut un attribut unique)
13
14- // Tenter une recherche pour essayer de retrouver le DN
15- foreach ($logins as $att) {
16- $result = @ldap_search($ldap_link, $ldap_base, "$att=$login_search", array("dn"));
17- $info = @ldap_get_entries($ldap_link, $result);
18- // Ne pas accepter les resultats si plus d'une entree
19- // (on veut un attribut unique)
20+ if (is_array($info) and $info['count'] == 1) {
21+ $dn = $info[0]['dn'];
22+ if (!$checkpass) {
23+ return $dn;
24+ }
25+ if (@ldap_bind($ldap_link, $dn, $pass)) {
26+ return $dn;
27+ }
28+ }
29+ } else {
30+ // Tenter une recherche pour essayer de retrouver le DN
31+ foreach ($logins as $att) {
32+ $result = @ldap_search($ldap_link, $ldap_base, "$att=$login_search", array("dn"));
33+ $info = @ldap_get_entries($ldap_link, $result);
34+ // Ne pas accepter les resultats si plus d'une entree
35+ // (on veut un attribut unique)
36
37- if (is_array($info) and $info['count'] == 1) {
38- $dn = $info[0]['dn'];
39- if (!$checkpass) {
40- return $dn;
41- }
42- if (@ldap_bind($ldap_link, $dn, $pass)) {
43- return $dn;
44- }
45- }
46- }
47+ if (is_array($info) and $info['count'] == 1) {
48+ $dn = $info[0]['dn'];
49+ if (!$checkpass) {
50+ return $dn;
51+ }
52+ if (@ldap_bind($ldap_link, $dn, $pass)) {
53+ return $dn;
54+ }
55+ }
56+ }
57+ }
58
59 if ($checkpass and !isset($dn)) {
60 // Si echec, essayer de deviner le DN
diff --git a/nixops/modules/websites/commons/spip/spip_mes_options.php b/nixops/modules/websites/commons/spip/spip_mes_options.php
new file mode 100644
index 0000000..8db8389
--- /dev/null
+++ b/nixops/modules/websites/commons/spip/spip_mes_options.php
@@ -0,0 +1,18 @@
1<?php // /!\ Important: There must be no blank space before &lt;?php or after ?&gt;
2// This file was inspired from the spip contrib website
3// http://www.spip.net/fr_article3811.html
4
5$config_dir = getenv('SPIP_CONFIG_DIR') . '/';
6$var_dir = getenv('SPIP_VAR_DIR') . '/';
7
8$cookie_prefix = str_replace('.', '_', getenv("SPIP_SITE"));
9$table_prefix = 'spip';
10
11spip_initialisation(
12 $config_dir,
13 _DIR_RACINE . _NOM_PERMANENTS_ACCESSIBLES,
14 $var_dir . _NOM_TEMPORAIRES_INACCESSIBLES,
15 _DIR_RACINE . _NOM_TEMPORAIRES_ACCESSIBLES
16);
17
18?>
diff --git a/nixops/modules/websites/commons/stats.nix b/nixops/modules/websites/commons/stats.nix
new file mode 100644
index 0000000..b5bf0e0
--- /dev/null
+++ b/nixops/modules/websites/commons/stats.nix
@@ -0,0 +1,67 @@
1{ lib, pkgs, config, mylibs, ... }:
2let
3 cfg = config.services.myWebsites.commons.stats;
4in {
5 options = {
6 services.myWebsites.commons.stats = {
7 enable = lib.mkEnableOption "enable statistics";
8 sites = lib.mkOption {
9 type = lib.types.listOf (lib.types.submodule {
10 options = {
11 conf = lib.mkOption { type = lib.types.path; };
12 name = lib.mkOption { type = lib.types.string; };
13 };
14 });
15 default = [];
16 description = "Sites to generate stats";
17 };
18 };
19 };
20
21 config = lib.mkIf cfg.enable {
22 environment.systemPackages = [
23 pkgs.goaccess
24 ];
25
26 nixpkgs.config.packageOverrides = oldpkgs: rec {
27 goaccess = oldpkgs.goaccess.overrideAttrs(old: rec {
28 name = "goaccess-${version}";
29 version = "1.3";
30 src = pkgs.fetchurl {
31 url = "https://tar.goaccess.io/${name}.tar.gz";
32 sha256 = "16vv3pj7pbraq173wlxa89jjsd279004j4kgzlrsk1dz4if5qxwc";
33 };
34 configureFlags = old.configureFlags ++ [ "--enable-tcb=btree" ];
35 buildInputs = old.buildInputs ++ [ pkgs.tokyocabinet pkgs.bzip2 ];
36 });
37 };
38
39 services.cron = {
40 enable = true;
41 systemCronJobs = let
42 stats = domain: conf: let
43 d = pkgs.writeScriptBin "stats-${domain}" ''
44 #!${pkgs.stdenv.shell}
45 set -e
46 shopt -s nullglob
47 date_regex=$(LC_ALL=C date -d yesterday +'%d\/%b\/%Y')
48 TMPFILE=$(mktemp)
49 trap "rm -f $TMPFILE" EXIT
50
51 cat /var/log/httpd/access_log-${domain} | sed -n "/\\[$date_regex/ p" > $TMPFILE
52 for i in /var/log/httpd/access_log-${domain}*.gz; do
53 zcat "$i" | sed -n "/\\[$date_regex/ p" >> $TMPFILE
54 done
55 goaccess $TMPFILE --no-progress -o /var/lib/goaccess/${domain}/index.html -p ${conf}
56 '';
57 in "${d}/bin/stats-${domain}";
58 in
59 pkgs.lib.lists.imap0 (i: v: "${toString (i+5)} 0 * * * root ${stats v.name v.conf}") cfg.sites;
60 };
61
62 system.activationScripts.goaccess = ''
63 mkdir -p /var/lib/goaccess
64 '' +
65 builtins.concatStringsSep "\n" (map (v: "mkdir -p /var/lib/goaccess/${v.name}") cfg.sites);
66 };
67}