Compare commits

..

4 commits

125 changed files with 9304 additions and 1915 deletions

2
.gitignore vendored
View file

@ -4,4 +4,4 @@ secrets/*
cluster/*/secrets/* cluster/*/secrets/*
!cluster/*/secrets/*.sample !cluster/*/secrets/*.sample
adrn-notes/ bugs/

View file

@ -1,32 +0,0 @@
## Pour remonter locement un backup de PSQL fait par Nomad (backup-weekly.hcl)
```bash
export AWS_BUCKET=backups-pgbasebackup
export AWS_ENDPOINT=s3.deuxfleurs.shirokumo.net
export AWS_ACCESS_KEY_ID=$(consul kv get "secrets/postgres/backup/aws_access_key_id")
export AWS_SECRET_ACCESS_KEY=$(consul kv get secrets/postgres/backup/aws_secret_access_key)
export CRYPT_PUBLIC_KEY=$(consul kv get secrets/postgres/backup/crypt_public_key)
```
Et voilà le travail :
```bash
$ aws s3 --endpoint https://$AWS_ENDPOINT ls
2022-04-14 17:00:50 backups-pgbasebackup
$ aws s3 --endpoint https://$AWS_ENDPOINT ls s3://backups-pgbasebackup
PRE 2024-07-28 00:00:36.140539/
PRE 2024-08-04 00:00:21.291551/
PRE 2024-08-11 00:00:26.589762/
PRE 2024-08-18 00:00:40.873939/
PRE 2024-08-25 01:03:54.672763/
PRE 2024-09-01 00:00:20.019605/
PRE 2024-09-08 00:00:16.969740/
PRE 2024-09-15 00:00:37.951459/
PRE 2024-09-22 00:00:21.030452/
$ aws s3 --endpoint https://$AWS_ENDPOINT ls "s3://backups-pgbasebackup/2024-09-22 00:00:21.030452/"
2024-09-22 03:23:28 623490 backup_manifest
2024-09-22 03:25:32 6037121487 base.tar.gz
2024-09-22 03:25:33 19948939 pg_wal.tar.gz
```

View file

@ -44,8 +44,6 @@ if not client.bucket_exists(bucket):
abort(f"Bucket {bucket} does not exist or its access is forbidden, aborting") abort(f"Bucket {bucket} does not exist or its access is forbidden, aborting")
# Perform the backup locally # Perform the backup locally
# Via command-line:
# pg_basebackup --host=localhost --username=$PSQL_USER --pgdata=. --format=tar --wal-method=stream --gzip --compress=6 --progress --max-rate=5M
try: try:
ret = subprocess.run(["pg_basebackup", ret = subprocess.run(["pg_basebackup",
f"--host={psql_host}", f"--host={psql_host}",

View file

@ -14,14 +14,14 @@ job "backup_daily" {
constraint { constraint {
attribute = "${attr.unique.hostname}" attribute = "${attr.unique.hostname}"
operator = "=" operator = "="
value = "celeri" value = "ananas"
} }
task "main" { task "main" {
driver = "docker" driver = "docker"
config { config {
image = "restic/restic:0.16.4" image = "restic/restic:0.16.0"
entrypoint = [ "/bin/sh", "-c" ] entrypoint = [ "/bin/sh", "-c" ]
args = [ "restic backup /mail && restic forget --group-by paths --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ] args = [ "restic backup /mail && restic forget --group-by paths --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ]
volumes = [ volumes = [
@ -116,7 +116,7 @@ EOH
driver = "docker" driver = "docker"
config { config {
image = "restic/restic:0.16.4" image = "restic/restic:0.16.0"
entrypoint = [ "/bin/sh", "-c" ] entrypoint = [ "/bin/sh", "-c" ]
args = [ "restic backup $NOMAD_ALLOC_DIR/consul.json && restic forget --group-by paths --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ] args = [ "restic backup $NOMAD_ALLOC_DIR/consul.json && restic forget --group-by paths --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ]
} }
@ -152,14 +152,14 @@ EOH
constraint { constraint {
attribute = "${attr.unique.hostname}" attribute = "${attr.unique.hostname}"
operator = "=" operator = "="
value = "courgette" value = "concombre"
} }
task "main" { task "main" {
driver = "docker" driver = "docker"
config { config {
image = "restic/restic:0.16.4" image = "restic/restic:0.16.0"
entrypoint = [ "/bin/sh", "-c" ] entrypoint = [ "/bin/sh", "-c" ]
args = [ "restic backup /cryptpad && restic forget --group-by paths --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ] args = [ "restic backup /cryptpad && restic forget --group-by paths --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ]
volumes = [ volumes = [

View file

@ -1,5 +1,5 @@
job "core-d53" { job "core-d53" {
datacenters = ["neptune", "scorpio", "bespin", "corrin"] datacenters = ["neptune", "scorpio", "bespin"]
type = "service" type = "service"
priority = 90 priority = 90

View file

@ -1,5 +1,5 @@
job "core-diplonat" { job "core-diplonat" {
datacenters = ["neptune", "scorpio", "bespin", "corrin"] datacenters = ["neptune", "scorpio", "bespin"]
type = "system" type = "system"
priority = 90 priority = 90

View file

@ -3,7 +3,7 @@ job "core-tricot" {
# on pourra mettre bespin quand on aura migré gitea de la vm vers le cluster # on pourra mettre bespin quand on aura migré gitea de la vm vers le cluster
# en attendant, les deux ne sont pas capables de partager les certificats SSL # en attendant, les deux ne sont pas capables de partager les certificats SSL
# donc on laisse la VM gitea gérer les certifs et prendre tout le trafic http(s) # donc on laisse la VM gitea gérer les certifs et prendre tout le trafic http(s)
datacenters = ["corrin", "neptune", "scorpio"] datacenters = ["neptune", "scorpio"]
type = "system" type = "system"
priority = 90 priority = 90
@ -28,16 +28,13 @@ job "core-tricot" {
driver = "docker" driver = "docker"
config { config {
image = "armael/tricot:n6dk1b5xrdww12zf12jbcmihqs6g1brz" image = "superboum/amd64_tricot:54"
network_mode = "host" network_mode = "host"
readonly_rootfs = true readonly_rootfs = true
ports = [ "http_port", "https_port" ] ports = [ "http_port", "https_port" ]
volumes = [ volumes = [
"secrets:/etc/tricot", "secrets:/etc/tricot",
] ]
ulimit {
nofile = "65535:65535"
}
} }
resources { resources {
@ -90,10 +87,7 @@ EOH
service { service {
name = "tricot-http" name = "tricot-http"
port = "http_port" port = "http_port"
tags = [ tags = [ "(diplonat (tcp_port 80))", "${meta.site}" ]
"(diplonat (tcp_port 80))",
"${meta.site}"
]
address_mode = "host" address_mode = "host"
} }
@ -103,12 +97,9 @@ EOH
tags = [ tags = [
"(diplonat (tcp_port 443))", "(diplonat (tcp_port 443))",
"${meta.site}", "${meta.site}",
"d53-aaaa ${meta.site}.site.deuxfleurs.fr",
"d53-a global.site.deuxfleurs.fr", "d53-a global.site.deuxfleurs.fr",
"d53-aaaa global.site.deuxfleurs.fr", "d53-aaaa global.site.deuxfleurs.fr",
"d53-a ${meta.site}.site.deuxfleurs.fr",
"d53-aaaa ${meta.site}.site.deuxfleurs.fr",
"d53-a v4.${meta.site}.site.deuxfleurs.fr",
"d53-aaaa v6.${meta.site}.site.deuxfleurs.fr",
] ]
address_mode = "host" address_mode = "host"
} }

View file

@ -3,7 +3,3 @@ type = 'user'
description = 'LDAP base DN for everything' description = 'LDAP base DN for everything'
example = 'dc=example,dc=com' example = 'dc=example,dc=com'
[secrets."d53/gandi_api_key"]
type = 'user'
description = 'Gandi API key'

View file

@ -34,13 +34,15 @@ job "coturn" {
ports = [ "prometheus", "turn_ctrl", "turn_data0", "turn_data1", "turn_data2", ports = [ "prometheus", "turn_ctrl", "turn_data0", "turn_data1", "turn_data2",
"turn_data3", "turn_data4", "turn_data5", "turn_data6", "turn_data7", "turn_data3", "turn_data4", "turn_data5", "turn_data6", "turn_data7",
"turn_data8", "turn_data9" ] "turn_data8", "turn_data9" ]
entrypoint = ["/local/docker-entrypoint.sh"]
network_mode = "host" network_mode = "host"
volumes = [
"secrets/docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh",
]
} }
template { template {
data = file("../config/docker-entrypoint.sh") data = file("../config/docker-entrypoint.sh")
destination = "local/docker-entrypoint.sh" destination = "secrets/docker-entrypoint.sh"
perms = 555 perms = 555
} }

View file

@ -1,52 +1,29 @@
# CryptPad for NixOS with Deuxfleurs flavour ## Build
## Building Cryptpad being not NixOS native, an upgrade must be done in 4 steps:
1. Bump the cryptpad version in `common.nix`
2. Rebuild the Nix lock files for the dependencies
3. Build the package for Nix
4. Create a container from the Nix package
The `default.nix` file follows the nixpkgs `callPackage` convention for fetching dependencies, so you need to either: To bump the nix version, set the desired tag in `common.nix` in the `cryptpadVersion` entry.
Set the corresponding commit in the `cryptadCommit` field, its goal would be to detect unwanted update of the tag.
- Run `nix-build --expr '{ ... }@args: (import <nixpkgs> {}).callPackage ./default.nix args'` To rebuild the lock files (they are stored in the `nix.lock` folder):
- Do the `callPackage from a higher-level directory importing your package`
### Docker ```
nix-shell --run "update_lock"
The `docker.nix` derives into a Docker image you can load simply by running:
```shell
docker load -i $(nix-build docker.nix)
``` ```
You can then test the built Docker image using the provided `docker-compose.yml` and `config.js` files, which are To build cryptpad:
configured to render the instance accessible at `http://localhost:3000` with data stored into the `_data` folder.
```
### Deuxfleurs flavour nix-build
The `deuxfleurs.nix` file derives into two derivations: The CryptPad derivation itself and a Docker image,
which can be choose by passing the `-A [name]` flags to `nix-build`
For example, to build and load the Deuxfleurs-flavoured CryptPad Docker image, you run:
```shell
docker load -i $(nix-build deuxfleurs.nix -A docker)
``` ```
## OnlyOffice integration Create the container:
Apart for `deuxfleurs.nix`, both `default.nix` and `docker.nix` files build CryptPad with a copy of OnlyOffice pre-built and
used by CryptPad, which can result to large Docker image (~2.6GiB)
This behaviour is configurable by passing the `--arg withOnlyOffice false` flag to `nix-build` when building them.
## Updating the Deuxfleurs pinned nixpkgs
The pinned sources files are generated with the [npins](https://github.com/andir/npins) tool.
To update the pinned nixpkgs, you simply run the following command:
```shell
npins update
``` ```
docker load < $(nix-build docker.nix)
To modify the pinned nixpkgs, remove it and re-add it using the new target, for exemple for `nixos-unstable`: docker push superboum/cryptpad:???
```shell
npins remove nixpkgs
npins add --name nixpkgs channel nixos-unstable
``` ```

View file

@ -0,0 +1,22 @@
rec {
cryptpadVersion = "4.14.1+2";
cryptpadCommit = "18c371bb5bda068a5d962dd7c4f0726320eea5e9";
pkgsSrc = fetchTarball {
# Latest commit on https://github.com/NixOS/nixpkgs/tree/nixos-21.11
# As of 2022-04-15
url ="https://github.com/NixOS/nixpkgs/archive/2f06b87f64bc06229e05045853e0876666e1b023.tar.gz";
sha256 = "sha256:1d7zg96xw4qsqh7c89pgha9wkq3rbi9as3k3d88jlxy2z0ns0cy2";
};
cryptpadSrc = builtins.fetchGit {
url = "https://github.com/superboum/cryptpad";
ref = "refs/tags/${cryptpadVersion}";
rev = cryptpadCommit;
};
bower2nixSrc = builtins.fetchGit {
url = "https://github.com/superboum/bower2nix";
ref = "new";
rev = "618ab3e206325c63fe4526ae842a1f6c792b0e27";
};
nodejs = "nodejs-slim-16_x";
}

View file

@ -1,132 +1,77 @@
{ lib let
, stdenvNoCC common = import ./common.nix;
pkgs = import common.pkgsSrc {};
nodejs = pkgs.${common.nodejs};
, buildNpmPackage bower = (pkgs.buildBowerComponents {
, fetchFromGitHub name = "cryptpad-${common.cryptpadVersion}-bower";
, fetchzip generated = ./nix.lock/bower.nix;
src = common.cryptpadSrc;
}).overrideAttrs (old: {
bowerPackages = old.bowerPackages.override (old_: {
# add missing dependencies:
# Those dependencies are EOL and they are not installed by buildBowerComponents,
# but they are required, otherwise the resolver crashes.
# * add the second jquery ~2.1.0 entry
# * add the second bootstrap ~3.1.1 entry
paths = old_.paths ++ [
(pkgs.fetchbower "jquery" "2.1.0" "~2.1.0" "02kwvz93vzpv10qnp7s0dz3al0jh77awwrizb6wadsvgifxssnlr")
(pkgs.fetchbower "bootstrap" "3.1.1" "~3.1.1" "06bhjwa8p7mzbpr3jkgydd804z1nwrkdql66h7jkfml99psv9811")
];
});
});
, nodejs npm = import ./nix.lock/npm.nix {
inherit pkgs;
, withOnlyOffice ? true
}: let
onlyOfficeVersions = {
v1 = {
rev = "4f370bebe96e3a0d4054df87412ee5b2c6ed8aaa";
hash = "sha256-TE/99qOx4wT2s0op9wi+SHwqTPYq/H+a9Uus9Zj4iSY=";
};
v2b = {
rev = "d9da72fda95daf93b90ffa345757c47eb5b919dd";
hash = "sha256-SiRDRc2vnLwCVnvtk+C8PKw7IeuSzHBaJmZHogRe3hQ=";
};
v4 = {
rev = "6ebc6938b6841440ffad2efc1e23f1dc1ceda964";
hash = "sha256-eto1+8Tk/s3kbUCpbUh8qCS8EOq700FYG1/KiHyynaA=";
};
v5 = {
rev = "88a356f08ded2f0f4620bda66951caf1d7f02c21";
hash = "sha256-8j1rlAyHlKx6oAs2pIhjPKcGhJFj6ZzahOcgenyeOCc=";
};
v6 = {
rev = "abd8a309f6dd37289f950cd8cea40df4492d8a15";
hash = "sha256-BZdExj2q/bqUD3k9uluOot2dlrWKA+vpad49EdgXKww=";
};
v7 = {
rev = "e1267803ea749cd93e9d5f81438011ea620d04af";
hash = "sha256-iIds0GnCHAyeIEdSD4aCCgDtnnwARh3NE470CywseS0=";
};
}; };
mkOnlyOffice = {
pname, version
}: stdenvNoCC.mkDerivation (final: {
pname = "${pname}-onlyoffice";
inherit version;
x2t = let in
version = "v7.3+1"; pkgs.stdenv.mkDerivation {
in fetchzip { name = "cryptpad-${common.cryptpadVersion}";
url = "https://github.com/cryptpad/onlyoffice-x2t-wasm/releases/download/${version}/x2t.zip"; src = common.cryptpadSrc;
hash = "sha256-d5raecsTOflo0UpjSEZW5lker4+wdkTb6IyHNq5iBg8=";
stripRoot = false;
};
srcs = lib.mapAttrsToList (version: { rev, hash ? lib.fakeHash }: fetchFromGitHub { buildPhase = ''
name = "${final.pname}-${version}-source"; cp -r ${npm.nodeDependencies}/lib/node_modules node_modules
owner = "cryptpad"; chmod +w -R node_modules
repo = "onlyoffice-builds";
inherit rev hash;
}) onlyOfficeVersions;
dontBuild = true; # clear executable files inside the node_modules folder to reduce dependencies
# and attack surface
find node_modules -type f ! -path 'node_modules/gar/*' -executable -print | tee >(xargs -n 20 rm)
sourceRoot = "."; # Remove only office that IS BIG
# COMMENTED as it is not as easy as planned.
# rm -rf www/common/onlyoffice
'';
installPhase = '' installPhase = ''
mkdir -p $out mkdir -p $out/{bin,opt}
${lib.concatLines (map
(version: "cp -Tr ${final.pname}-${version}-source $out/${version}") out_cryptpad=$out/opt/
(builtins.attrNames onlyOfficeVersions)
)} # copy the source code
cp -Tr $x2t $out/x2t cp -r .bowerrc bower.json package.json package-lock.json customize.dist lib server.js www $out_cryptpad
# mount node_modules
cp -r node_modules $out_cryptpad/node_modules
# patch
substituteInPlace $out_cryptpad/lib/workers/index.js --replace "lib/workers/db-worker" "$out_cryptpad/lib/workers/db-worker"
# mount bower, based on the .bowerrc file at the git repo root
cp -r ${bower}/bower_components $out_cryptpad/www/
# cryptpad is bugged with absolute path, this is a workaround to use absolute path as relative path
ln -s / $out_cryptpad/root
# start script, cryptpad is lost if its working directory is not its source directory
cat > $out/bin/cryptpad <<EOF
#!${pkgs.stdenv.shell}
cd $out_cryptpad
exec ${nodejs}/bin/node server.js
EOF
chmod +x $out/bin/cryptpad
''; '';
});
in buildNpmPackage rec {
pname = "cryptpad";
version = "2024.9.0";
src = fetchFromGitHub { dontFixup = true;
owner = "cryptpad"; }
repo = "cryptpad";
rev = version;
hash = "sha256-OUtWaDVLRUbKS0apwY0aNq4MalGFv+fH9VA7LvWWYRs=";
};
npmDepsHash = "sha256-pK0b7q1kJja9l8ANwudbfo3jpldwuO56kuulS8X9A5s=";
inherit nodejs;
onlyOffice = lib.optional withOnlyOffice (mkOnlyOffice {
inherit pname version;
});
makeCacheWritable = true;
dontFixup = true;
preBuild = ''
npm run install:components
'' + lib.optionalString withOnlyOffice ''
ln -s $onlyOffice www/common/onlyoffice/dist
'';
postBuild = ''
rm -rf customize
'';
installPhase = ''
runHook preInstall
mkdir -p $out
cp -R . $out/
substituteInPlace $out/lib/workers/index.js \
--replace-warn "lib/workers/db-worker" "$out/lib/workers/db-worker"
makeWrapper ${lib.getExe nodejs} $out/bin/cryptpad-server \
--chdir $out \
--add-flags server.js
runHook postInstall
'';
passthru = {
inherit onlyOffice;
};
meta = {
description = "Collaborative office suite, end-to-end encrypted and open-source.";
homepage = "https://cryptpad.org";
changelog = "https://github.com/cryptpad/cryptpad/releases/tag/${version}";
license = lib.licenses.agpl3Plus;
platforms = lib.platforms.all;
mainProgram = "cryptpad-server";
};
}

View file

@ -1,14 +0,0 @@
{ name ? "deuxfleurs/cryptpad"
, tag ? "nix-latest"
}: let
sources = import ./npins;
pkgs = import sources.nixpkgs {};
in rec {
cryptpad = pkgs.callPackage ./default.nix {};
docker = import ./docker.nix {
inherit pkgs;
inherit name tag;
inherit cryptpad;
withOnlyOffice = true;
};
}

View file

@ -1,27 +1,11 @@
{ pkgs ? import <nixpkgs> {} let
common = import ./common.nix;
, name ? "cryptpad" pkgs = import common.pkgsSrc {};
, tag ? "nix-latest" app = import ./default.nix;
in
, withOnlyOffice ? true pkgs.dockerTools.buildLayeredImage {
name = "superboum/cryptpad";
, cryptpad ? pkgs.callPackage ./default.nix { inherit withOnlyOffice; } config = {
}: let Cmd = [ "${app}/bin/cryptpad" ];
cryptpad' = cryptpad.overrideAttrs {
postInstall = ''
ln -sf /cryptpad/customize $out/customize
'';
};
in pkgs.dockerTools.buildImage {
inherit name tag;
config = {
Cmd = [
(pkgs.lib.getExe cryptpad')
];
Volumes = {
"/cryptpad/customize" = {};
}; };
}; }
}

View file

@ -0,0 +1,57 @@
{
"name": "cryptpad",
"version": "0.1.0",
"authors": [
"Caleb James DeLisle <cjd@cjdns.fr>"
],
"description": "realtime collaborative visual editor with zero knowlege server",
"main": "www/index.html",
"moduleType": [
"node"
],
"license": "AGPLv3",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"jquery": "3.6.0",
"tweetnacl": "0.12.2",
"components-font-awesome": "^4.6.3",
"ckeditor": "4.14.0",
"codemirror": "^5.19.0",
"requirejs": "2.3.5",
"marked": "1.1.0",
"rangy": "rangy-release#~1.3.0",
"json.sortify": "~2.1.0",
"hyperjson": "~1.4.0",
"chainpad-crypto": "^0.2.0",
"chainpad-listmap": "^1.0.0",
"chainpad": "^5.2.0",
"file-saver": "1.3.1",
"alertifyjs": "1.0.11",
"scrypt-async": "1.2.0",
"require-css": "0.1.10",
"bootstrap": "^v4.0.0",
"diff-dom": "2.1.1",
"nthen": "0.1.7",
"open-sans-fontface": "^1.4.2",
"bootstrap-tokenfield": "0.12.1",
"localforage": "^1.5.2",
"html2canvas": "^0.4.1",
"croppie": "^2.5.0",
"sortablejs": "^1.6.0",
"saferphore": "^0.0.1",
"jszip": "3.7.1",
"requirejs-plugins": "^1.0.3",
"dragula.js": "3.7.2",
"MathJax": "3.0.5"
},
"resolutions": {
"bootstrap": "^v4.0.0",
"jquery": "3.6.0"
}
}

View file

@ -0,0 +1,37 @@
# Generated by bower2nix v3.3.0 (https://github.com/rvl/bower2nix)
{ fetchbower, buildEnv }:
buildEnv { name = "bower-env"; ignoreCollisions = true; paths = [
(fetchbower "jquery" "3.6.0" "3.6.0" "1wx5n605x6ga483hba43gxjncgzk8yvxc3h0jlwgpjd0h54y9v6l")
(fetchbower "tweetnacl" "0.12.2" "0.12.2" "1lfzbfrdaly3zyzbcp1p53yhxlrx56k8x04q924kg7l52gblm65g")
(fetchbower "components-font-awesome" "4.7.0" "^4.6.3" "1w27im6ayjrbgjqa0i49ml5d3wy4ld40h9b29hz9myv77bpx4lg1")
(fetchbower "ckeditor" "4.14.0" "4.14.0" "0lw9q0k8c0jlxvf35vrccab9c3c8rgpc6x66czj9si8yy2lyliyp")
(fetchbower "codemirror" "5.65.3" "^5.19.0" "0z6pd0q0cy0k0dkplx4f3cmmjqbiixv6wqlzbz5j8dnsxr5hhgzh")
(fetchbower "requirejs" "2.3.5" "2.3.5" "05lyvgz914h2w08r24rk0vkk3yxmqrvlg7j3i5av9ffkg9lpzsli")
(fetchbower "marked" "1.1.0" "1.1.0" "1sdgqw9iki9c1pfm4c5h6c956mchbip2jywjrcmrlb75k53flsjz")
(fetchbower "rangy" "rangy-release#1.3.0" "rangy-release#~1.3.0" "13x3wci003p8jyv2ncir0k23bxckx99b3555r0zvgmlwycg7w0zv")
(fetchbower "json.sortify" "2.1.0" "~2.1.0" "1rz9xz0gnm4ak31n10vhslqsw8fw493gjylwj8xsy3bxqq1ygpnh")
(fetchbower "hyperjson" "1.4.0" "~1.4.0" "1n68ls3x4lyhg1yy8i4q3xkgh5xqpyakf45sny4x91mkr68x4bd9")
(fetchbower "chainpad-crypto" "0.2.7" "^0.2.0" "16j0gjj1v8dckqpsg38229qs4dammz7vx8ywsik6f0brzf4py65a")
(fetchbower "chainpad-listmap" "1.0.1" "^1.0.0" "0s2v27hhraifb1yjw5fka4a922zmgsdngsaq1nfd48gbs8gd2rrd")
(fetchbower "chainpad" "5.2.4" "^5.2.0" "1f4nap0r8w50qpmjdfhhjhpz5xcl0n4zaxxnav1qaxi5j6dyg8h6")
(fetchbower "file-saver" "1.3.1" "1.3.1" "065nzkvdiicxnw06z1sjz1sbp9nyis8z839hv6ng1fk25dc5kvkg")
(fetchbower "alertifyjs" "1.0.11" "1.0.11" "0v7323bzq90k35shm3h6azj4wd9la3kbi1va1pw4qyvndkwma69l")
(fetchbower "scrypt-async" "1.2.0" "1.2.0" "0d076ax708p9b8hcmk4f82j925nlnm0hmp0ni45ql37g7iirfpyv")
(fetchbower "require-css" "0.1.10" "0.1.10" "106gz9i76v71q9zx2pnqkkj342m630lvssnw54023a0ljc0gqcwq")
(fetchbower "bootstrap" "4.6.1" "^v4.0.0" "0g8zy1fl396lawgjvfhlpcl38zxsgybhnzi8b6b4m9nccvmpxv83")
(fetchbower "diff-dom" "2.1.1" "2.1.1" "0bp8c80g11hhlkvl3lhrqc39jvqiiyqvrgk1nsn35ps01ava07z9")
(fetchbower "nthen" "0.1.7" "0.1.7" "03yap5ildigaw4rwxmxs37pcwhq415iham8w39zd56ka98gpfxa5")
(fetchbower "open-sans-fontface" "1.4.2" "^1.4.2" "0ksav1fcq640fmdz49ra4prwsrrfj35y2p4shx1jh1j7zxd044nf")
(fetchbower "bootstrap-tokenfield" "0.12.1" "0.12.1" "1dh791s6ih8bf9ihck9n39h68c273jb3lg4mqk94bvqraz45fvwx")
(fetchbower "localforage" "1.10.0" "^1.5.2" "019rh006v2w5x63mgk78qhw59kf8czbkwdvfngmac8fs6gz88lc8")
(fetchbower "html2canvas" "0.4.1" "^0.4.1" "0yg7y90nav068q0i5afc2c221zkddpf28hi0hwc46cawx4180c69")
(fetchbower "croppie" "2.6.5" "^2.5.0" "1j1v5620zi13ad42r358i4ay891abwn6nz357484kgq2bgjj6ccx")
(fetchbower "sortablejs" "1.15.0" "^1.6.0" "1wk1097jrxbp2c4ghcppqd3h2gnq5b01qkf9426mc08zgszlvjr7")
(fetchbower "saferphore" "0.0.1" "^0.0.1" "1wfr9wpbm3lswmvy2p0247ydb108h4qh5s286py89k871qh6jwdi")
(fetchbower "jszip" "3.7.1" "3.7.1" "0f14bak7vylxizi6pvj3znjc2cx922avbv7lslklvic85x0318lf")
(fetchbower "requirejs-plugins" "1.0.3" "^1.0.3" "00s3sdz1ykygx5shldwhhhybwgw7c99vkqd94i5i5x0gl97ifxf5")
(fetchbower "dragula.js" "3.7.2" "3.7.2" "0dbkmrl8bcxiplprmmp9fj96ri5nahb2ql8cc7zwawncv0drvlh0")
(fetchbower "MathJax" "3.0.5" "3.0.5" "087a9av15qj43m8pr3b9g59ncmydhmg40m6dfzsac62ykianh2a0")
(fetchbower "chainpad-netflux" "1.0.0" "^1.0.0" "08rpc73x1vyvd6zkb7w0m1smzjhq3b7cwb30nlmg93x873zjlsl6")
(fetchbower "netflux-websocket" "1.0.0" "^1.0.0" "10hgc5ra3ll7qc2r8aal6p03gx6dgz06l2b54lh995pvf901wzi6")
]; }

View file

@ -0,0 +1,588 @@
# This file originates from node2nix
{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile, writeShellScript}:
let
# Workaround to cope with utillinux in Nixpkgs 20.09 and util-linux in Nixpkgs master
utillinux = if pkgs ? utillinux then pkgs.utillinux else pkgs.util-linux;
python = if nodejs ? python then nodejs.python else python2;
# Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
tarWrapper = runCommand "tarWrapper" {} ''
mkdir -p $out/bin
cat > $out/bin/tar <<EOF
#! ${stdenv.shell} -e
$(type -p tar) "\$@" --warning=no-unknown-keyword --delay-directory-restore
EOF
chmod +x $out/bin/tar
'';
# Function that generates a TGZ file from a NPM project
buildNodeSourceDist =
{ name, version, src, ... }:
stdenv.mkDerivation {
name = "node-tarball-${name}-${version}";
inherit src;
buildInputs = [ nodejs ];
buildPhase = ''
export HOME=$TMPDIR
tgzFile=$(npm pack | tail -n 1) # Hooks to the pack command will add output (https://docs.npmjs.com/misc/scripts)
'';
installPhase = ''
mkdir -p $out/tarballs
mv $tgzFile $out/tarballs
mkdir -p $out/nix-support
echo "file source-dist $out/tarballs/$tgzFile" >> $out/nix-support/hydra-build-products
'';
};
# Common shell logic
installPackage = writeShellScript "install-package" ''
installPackage() {
local packageName=$1 src=$2
local strippedName
local DIR=$PWD
cd $TMPDIR
unpackFile $src
# Make the base dir in which the target dependency resides first
mkdir -p "$(dirname "$DIR/$packageName")"
if [ -f "$src" ]
then
# Figure out what directory has been unpacked
packageDir="$(find . -maxdepth 1 -type d | tail -1)"
# Restore write permissions to make building work
find "$packageDir" -type d -exec chmod u+x {} \;
chmod -R u+w "$packageDir"
# Move the extracted tarball into the output folder
mv "$packageDir" "$DIR/$packageName"
elif [ -d "$src" ]
then
# Get a stripped name (without hash) of the source directory.
# On old nixpkgs it's already set internally.
if [ -z "$strippedName" ]
then
strippedName="$(stripHash $src)"
fi
# Restore write permissions to make building work
chmod -R u+w "$strippedName"
# Move the extracted directory into the output folder
mv "$strippedName" "$DIR/$packageName"
fi
# Change to the package directory to install dependencies
cd "$DIR/$packageName"
}
'';
# Bundle the dependencies of the package
#
# Only include dependencies if they don't exist. They may also be bundled in the package.
includeDependencies = {dependencies}:
lib.optionalString (dependencies != []) (
''
mkdir -p node_modules
cd node_modules
''
+ (lib.concatMapStrings (dependency:
''
if [ ! -e "${dependency.name}" ]; then
${composePackage dependency}
fi
''
) dependencies)
+ ''
cd ..
''
);
# Recursively composes the dependencies of a package
composePackage = { name, packageName, src, dependencies ? [], ... }@args:
builtins.addErrorContext "while evaluating node package '${packageName}'" ''
installPackage "${packageName}" "${src}"
${includeDependencies { inherit dependencies; }}
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
'';
pinpointDependencies = {dependencies, production}:
let
pinpointDependenciesFromPackageJSON = writeTextFile {
name = "pinpointDependencies.js";
text = ''
var fs = require('fs');
var path = require('path');
function resolveDependencyVersion(location, name) {
if(location == process.env['NIX_STORE']) {
return null;
} else {
var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
if(fs.existsSync(dependencyPackageJSON)) {
var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
if(dependencyPackageObj.name == name) {
return dependencyPackageObj.version;
}
} else {
return resolveDependencyVersion(path.resolve(location, ".."), name);
}
}
}
function replaceDependencies(dependencies) {
if(typeof dependencies == "object" && dependencies !== null) {
for(var dependency in dependencies) {
var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
if(resolvedVersion === null) {
process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
} else {
dependencies[dependency] = resolvedVersion;
}
}
}
}
/* Read the package.json configuration */
var packageObj = JSON.parse(fs.readFileSync('./package.json'));
/* Pinpoint all dependencies */
replaceDependencies(packageObj.dependencies);
if(process.argv[2] == "development") {
replaceDependencies(packageObj.devDependencies);
}
replaceDependencies(packageObj.optionalDependencies);
/* Write the fixed package.json file */
fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
'';
};
in
''
node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
${lib.optionalString (dependencies != [])
''
if [ -d node_modules ]
then
cd node_modules
${lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
cd ..
fi
''}
'';
# Recursively traverses all dependencies of a package and pinpoints all
# dependencies in the package.json file to the versions that are actually
# being used.
pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
''
if [ -d "${packageName}" ]
then
cd "${packageName}"
${pinpointDependencies { inherit dependencies production; }}
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
fi
'';
# Extract the Node.js source code which is used to compile packages with
# native bindings
nodeSources = runCommand "node-sources" {} ''
tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
mv node-* $out
'';
# Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
addIntegrityFieldsScript = writeTextFile {
name = "addintegrityfields.js";
text = ''
var fs = require('fs');
var path = require('path');
function augmentDependencies(baseDir, dependencies) {
for(var dependencyName in dependencies) {
var dependency = dependencies[dependencyName];
// Open package.json and augment metadata fields
var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
var packageJSONPath = path.join(packageJSONDir, "package.json");
if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
console.log("Adding metadata fields to: "+packageJSONPath);
var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
if(dependency.integrity) {
packageObj["_integrity"] = dependency.integrity;
} else {
packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
}
if(dependency.resolved) {
packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided
} else {
packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
}
if(dependency.from !== undefined) { // Adopt from property if one has been provided
packageObj["_from"] = dependency.from;
}
fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
}
// Augment transitive dependencies
if(dependency.dependencies !== undefined) {
augmentDependencies(packageJSONDir, dependency.dependencies);
}
}
}
if(fs.existsSync("./package-lock.json")) {
var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
if(![1, 2].includes(packageLock.lockfileVersion)) {
process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n");
process.exit(1);
}
if(packageLock.dependencies !== undefined) {
augmentDependencies(".", packageLock.dependencies);
}
}
'';
};
# Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
reconstructPackageLock = writeTextFile {
name = "addintegrityfields.js";
text = ''
var fs = require('fs');
var path = require('path');
var packageObj = JSON.parse(fs.readFileSync("package.json"));
var lockObj = {
name: packageObj.name,
version: packageObj.version,
lockfileVersion: 1,
requires: true,
dependencies: {}
};
function augmentPackageJSON(filePath, dependencies) {
var packageJSON = path.join(filePath, "package.json");
if(fs.existsSync(packageJSON)) {
var packageObj = JSON.parse(fs.readFileSync(packageJSON));
dependencies[packageObj.name] = {
version: packageObj.version,
integrity: "sha1-000000000000000000000000000=",
dependencies: {}
};
processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies);
}
}
function processDependencies(dir, dependencies) {
if(fs.existsSync(dir)) {
var files = fs.readdirSync(dir);
files.forEach(function(entry) {
var filePath = path.join(dir, entry);
var stats = fs.statSync(filePath);
if(stats.isDirectory()) {
if(entry.substr(0, 1) == "@") {
// When we encounter a namespace folder, augment all packages belonging to the scope
var pkgFiles = fs.readdirSync(filePath);
pkgFiles.forEach(function(entry) {
if(stats.isDirectory()) {
var pkgFilePath = path.join(filePath, entry);
augmentPackageJSON(pkgFilePath, dependencies);
}
});
} else {
augmentPackageJSON(filePath, dependencies);
}
}
});
}
}
processDependencies("node_modules", lockObj.dependencies);
fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
'';
};
prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}:
let
forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
in
''
# Pinpoint the versions of all dependencies to the ones that are actually being used
echo "pinpointing versions of dependencies..."
source $pinpointDependenciesScriptPath
# Patch the shebangs of the bundled modules to prevent them from
# calling executables outside the Nix store as much as possible
patchShebangs .
# Deploy the Node.js package by running npm install. Since the
# dependencies have been provided already by ourselves, it should not
# attempt to install them again, which is good, because we want to make
# it Nix's responsibility. If it needs to install any dependencies
# anyway (e.g. because the dependency parameters are
# incomplete/incorrect), it fails.
#
# The other responsibilities of NPM are kept -- version checks, build
# steps, postprocessing etc.
export HOME=$TMPDIR
cd "${packageName}"
runHook preRebuild
${lib.optionalString bypassCache ''
${lib.optionalString reconstructLock ''
if [ -f package-lock.json ]
then
echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!"
echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!"
rm package-lock.json
else
echo "No package-lock.json file found, reconstructing..."
fi
node ${reconstructPackageLock}
''}
node ${addIntegrityFieldsScript}
''}
npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild
if [ "''${dontNpmInstall-}" != "1" ]
then
# NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
rm -f npm-shrinkwrap.json
npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} install
fi
'';
# Builds and composes an NPM package including all its dependencies
buildNodePackage =
{ name
, packageName
, version
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, preRebuild ? ""
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, meta ? {}
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" "meta" ];
in
stdenv.mkDerivation ({
name = "${name}-${version}";
buildInputs = [ tarWrapper python nodejs ]
++ lib.optional (stdenv.isLinux) utillinux
++ lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit nodejs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall preRebuild unpackPhase buildPhase;
compositionScript = composePackage args;
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
installPhase = ''
source ${installPackage}
# Create and enter a root node_modules/ folder
mkdir -p $out/lib/node_modules
cd $out/lib/node_modules
# Compose the package and all its dependencies
source $compositionScriptPath
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Create symlink to the deployed executable folder, if applicable
if [ -d "$out/lib/node_modules/.bin" ]
then
ln -s $out/lib/node_modules/.bin $out/bin
fi
# Create symlinks to the deployed manual page folders, if applicable
if [ -d "$out/lib/node_modules/${packageName}/man" ]
then
mkdir -p $out/share
for dir in "$out/lib/node_modules/${packageName}/man/"*
do
mkdir -p $out/share/man/$(basename "$dir")
for page in "$dir"/*
do
ln -s $page $out/share/man/$(basename "$dir")
done
done
fi
# Run post install hook, if provided
runHook postInstall
'';
meta = {
# default to Node.js' platforms
platforms = nodejs.meta.platforms;
} // meta;
} // extraArgs);
# Builds a node environment (a node_modules folder and a set of binaries)
buildNodeDependencies =
{ name
, packageName
, version
, src
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
in
stdenv.mkDerivation ({
name = "node-dependencies-${name}-${version}";
buildInputs = [ tarWrapper python nodejs ]
++ lib.optional (stdenv.isLinux) utillinux
++ lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall unpackPhase buildPhase;
includeScript = includeDependencies { inherit dependencies; };
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
installPhase = ''
source ${installPackage}
mkdir -p $out/${packageName}
cd $out/${packageName}
source $includeScriptPath
# Create fake package.json to make the npm commands work properly
cp ${src}/package.json .
chmod 644 package.json
${lib.optionalString bypassCache ''
if [ -f ${src}/package-lock.json ]
then
cp ${src}/package-lock.json .
fi
''}
# Go to the parent folder to make sure that all packages are pinpointed
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Expose the executables that were installed
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
mv ${packageName} lib
ln -s $out/lib/node_modules/.bin $out/bin
'';
} // extraArgs);
# Builds a development shell
buildNodeShell =
{ name
, packageName
, version
, src
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
nodeDependencies = buildNodeDependencies args;
in
stdenv.mkDerivation {
name = "node-shell-${name}-${version}";
buildInputs = [ python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
buildCommand = ''
mkdir -p $out/bin
cat > $out/bin/shell <<EOF
#! ${stdenv.shell} -e
$shellHook
exec ${stdenv.shell}
EOF
chmod +x $out/bin/shell
'';
# Provide the dependencies in a development shell through the NODE_PATH environment variable
inherit nodeDependencies;
shellHook = lib.optionalString (dependencies != []) ''
export NODE_PATH=${nodeDependencies}/lib/node_modules
export PATH="${nodeDependencies}/bin:$PATH"
'';
};
in
{
buildNodeSourceDist = lib.makeOverridable buildNodeSourceDist;
buildNodePackage = lib.makeOverridable buildNodePackage;
buildNodeDependencies = lib.makeOverridable buildNodeDependencies;
buildNodeShell = lib.makeOverridable buildNodeShell;
}

View file

@ -0,0 +1,756 @@
# This file has been generated by node2nix 1.9.0. Do not edit!
{nodeEnv, fetchurl, fetchgit, nix-gitignore, stdenv, lib, globalBuildInputs ? []}:
let
sources = {
"@mcrowe/minibloom-0.2.0" = {
name = "_at_mcrowe_slash_minibloom";
packageName = "@mcrowe/minibloom";
version = "0.2.0";
src = fetchurl {
url = "https://registry.npmjs.org/@mcrowe/minibloom/-/minibloom-0.2.0.tgz";
sha1 = "1bed96aec18388198da37443899b2c3ff5948053";
};
};
"accepts-1.3.8" = {
name = "accepts";
packageName = "accepts";
version = "1.3.8";
src = fetchurl {
url = "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz";
sha512 = "PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==";
};
};
"array-flatten-1.1.1" = {
name = "array-flatten";
packageName = "array-flatten";
version = "1.1.1";
src = fetchurl {
url = "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz";
sha1 = "9a5f699051b1e7073328f2a008968b64ea2955d2";
};
};
"async-limiter-1.0.1" = {
name = "async-limiter";
packageName = "async-limiter";
version = "1.0.1";
src = fetchurl {
url = "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz";
sha512 = "csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==";
};
};
"body-parser-1.18.3" = {
name = "body-parser";
packageName = "body-parser";
version = "1.18.3";
src = fetchurl {
url = "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz";
sha1 = "5b292198ffdd553b3a0f20ded0592b956955c8b4";
};
};
"bytes-3.0.0" = {
name = "bytes";
packageName = "bytes";
version = "3.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz";
sha1 = "d32815404d689699f85a4ea4fa8755dd13a96048";
};
};
"chainpad-crypto-0.2.7" = {
name = "chainpad-crypto";
packageName = "chainpad-crypto";
version = "0.2.7";
src = fetchurl {
url = "https://registry.npmjs.org/chainpad-crypto/-/chainpad-crypto-0.2.7.tgz";
sha512 = "H2FfFmMwWw4i8XeGVjKUNEmgOnJohlAvc5IpnVnHqCDm6axntpZ15rv9hV70uhzDrmFhlAPW8MoY4roe5PhUyA==";
};
};
"chainpad-server-5.1.0" = {
name = "chainpad-server";
packageName = "chainpad-server";
version = "5.1.0";
src = fetchurl {
url = "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.1.0.tgz";
sha512 = "BdjgOOLTXXo1EjQ7lURDe7oqsqfQISNvwhILfp3K3diY2K1hxpPLbjYzOSgxNOTADeOAff0xnInR5eUCESVWaQ==";
};
};
"content-disposition-0.5.2" = {
name = "content-disposition";
packageName = "content-disposition";
version = "0.5.2";
src = fetchurl {
url = "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz";
sha1 = "0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4";
};
};
"content-type-1.0.4" = {
name = "content-type";
packageName = "content-type";
version = "1.0.4";
src = fetchurl {
url = "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz";
sha512 = "hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==";
};
};
"cookie-0.3.1" = {
name = "cookie";
packageName = "cookie";
version = "0.3.1";
src = fetchurl {
url = "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz";
sha1 = "e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb";
};
};
"cookie-signature-1.0.6" = {
name = "cookie-signature";
packageName = "cookie-signature";
version = "1.0.6";
src = fetchurl {
url = "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz";
sha1 = "e303a882b342cc3ee8ca513a79999734dab3ae2c";
};
};
"debug-2.6.9" = {
name = "debug";
packageName = "debug";
version = "2.6.9";
src = fetchurl {
url = "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz";
sha512 = "bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==";
};
};
"depd-1.1.2" = {
name = "depd";
packageName = "depd";
version = "1.1.2";
src = fetchurl {
url = "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz";
sha1 = "9bcd52e14c097763e749b274c4346ed2e560b5a9";
};
};
"destroy-1.0.4" = {
name = "destroy";
packageName = "destroy";
version = "1.0.4";
src = fetchurl {
url = "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz";
sha1 = "978857442c44749e4206613e37946205826abd80";
};
};
"ee-first-1.1.1" = {
name = "ee-first";
packageName = "ee-first";
version = "1.1.1";
src = fetchurl {
url = "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz";
sha1 = "590c61156b0ae2f4f0255732a158b266bc56b21d";
};
};
"encodeurl-1.0.2" = {
name = "encodeurl";
packageName = "encodeurl";
version = "1.0.2";
src = fetchurl {
url = "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz";
sha1 = "ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59";
};
};
"escape-html-1.0.3" = {
name = "escape-html";
packageName = "escape-html";
version = "1.0.3";
src = fetchurl {
url = "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz";
sha1 = "0258eae4d3d0c0974de1c169188ef0051d1d1988";
};
};
"etag-1.8.1" = {
name = "etag";
packageName = "etag";
version = "1.8.1";
src = fetchurl {
url = "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz";
sha1 = "41ae2eeb65efa62268aebfea83ac7d79299b0887";
};
};
"express-4.16.4" = {
name = "express";
packageName = "express";
version = "4.16.4";
src = fetchurl {
url = "https://registry.npmjs.org/express/-/express-4.16.4.tgz";
sha512 = "j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==";
};
};
"finalhandler-1.1.1" = {
name = "finalhandler";
packageName = "finalhandler";
version = "1.1.1";
src = fetchurl {
url = "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz";
sha512 = "Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==";
};
};
"forwarded-0.2.0" = {
name = "forwarded";
packageName = "forwarded";
version = "0.2.0";
src = fetchurl {
url = "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz";
sha512 = "buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==";
};
};
"fresh-0.5.2" = {
name = "fresh";
packageName = "fresh";
version = "0.5.2";
src = fetchurl {
url = "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz";
sha1 = "3d8cadd90d976569fa835ab1f8e4b23a105605a7";
};
};
"fs-extra-7.0.1" = {
name = "fs-extra";
packageName = "fs-extra";
version = "7.0.1";
src = fetchurl {
url = "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz";
sha512 = "YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==";
};
};
"gar-1.0.4" = {
name = "gar";
packageName = "gar";
version = "1.0.4";
src = fetchurl {
url = "https://registry.npmjs.org/gar/-/gar-1.0.4.tgz";
sha512 = "w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==";
};
};
"get-folder-size-2.0.1" = {
name = "get-folder-size";
packageName = "get-folder-size";
version = "2.0.1";
src = fetchurl {
url = "https://registry.npmjs.org/get-folder-size/-/get-folder-size-2.0.1.tgz";
sha512 = "+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==";
};
};
"graceful-fs-4.2.10" = {
name = "graceful-fs";
packageName = "graceful-fs";
version = "4.2.10";
src = fetchurl {
url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz";
sha512 = "9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==";
};
};
"http-errors-1.6.3" = {
name = "http-errors";
packageName = "http-errors";
version = "1.6.3";
src = fetchurl {
url = "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz";
sha1 = "8b55680bb4be283a0b5bf4ea2e38580be1d9320d";
};
};
"iconv-lite-0.4.23" = {
name = "iconv-lite";
packageName = "iconv-lite";
version = "0.4.23";
src = fetchurl {
url = "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz";
sha512 = "neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==";
};
};
"inherits-2.0.3" = {
name = "inherits";
packageName = "inherits";
version = "2.0.3";
src = fetchurl {
url = "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz";
sha1 = "633c2c83e3da42a502f52466022480f4208261de";
};
};
"ipaddr.js-1.9.1" = {
name = "ipaddr.js";
packageName = "ipaddr.js";
version = "1.9.1";
src = fetchurl {
url = "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz";
sha512 = "0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==";
};
};
"jsonfile-4.0.0" = {
name = "jsonfile";
packageName = "jsonfile";
version = "4.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz";
sha1 = "8771aae0799b64076b76640fca058f9c10e33ecb";
};
};
"lex-1.7.9" = {
name = "lex";
packageName = "lex";
version = "1.7.9";
src = fetchurl {
url = "https://registry.npmjs.org/lex/-/lex-1.7.9.tgz";
sha1 = "5d5636ccef574348362938b79a47f0eed8ed0d43";
};
};
"looper-3.0.0" = {
name = "looper";
packageName = "looper";
version = "3.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/looper/-/looper-3.0.0.tgz";
sha1 = "2efa54c3b1cbaba9b94aee2e5914b0be57fbb749";
};
};
"media-typer-0.3.0" = {
name = "media-typer";
packageName = "media-typer";
version = "0.3.0";
src = fetchurl {
url = "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz";
sha1 = "8710d7af0aa626f8fffa1ce00168545263255748";
};
};
"merge-descriptors-1.0.1" = {
name = "merge-descriptors";
packageName = "merge-descriptors";
version = "1.0.1";
src = fetchurl {
url = "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz";
sha1 = "b00aaa556dd8b44568150ec9d1b953f3f90cbb61";
};
};
"methods-1.1.2" = {
name = "methods";
packageName = "methods";
version = "1.1.2";
src = fetchurl {
url = "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz";
sha1 = "5529a4d67654134edcc5266656835b0f851afcee";
};
};
"mime-1.4.1" = {
name = "mime";
packageName = "mime";
version = "1.4.1";
src = fetchurl {
url = "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz";
sha512 = "KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==";
};
};
"mime-db-1.52.0" = {
name = "mime-db";
packageName = "mime-db";
version = "1.52.0";
src = fetchurl {
url = "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz";
sha512 = "sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==";
};
};
"mime-types-2.1.35" = {
name = "mime-types";
packageName = "mime-types";
version = "2.1.35";
src = fetchurl {
url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz";
sha512 = "ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==";
};
};
"ms-2.0.0" = {
name = "ms";
packageName = "ms";
version = "2.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz";
sha1 = "5608aeadfc00be6c2901df5f9861788de0d597c8";
};
};
"negotiator-0.6.3" = {
name = "negotiator";
packageName = "negotiator";
version = "0.6.3";
src = fetchurl {
url = "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz";
sha512 = "+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==";
};
};
"netflux-websocket-0.1.21" = {
name = "netflux-websocket";
packageName = "netflux-websocket";
version = "0.1.21";
src = fetchurl {
url = "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-0.1.21.tgz";
sha512 = "Zjl5lefg8urC0a0T7YCPGiUgRsISZBsTZl1STylmQz8Bq4ohcZ8cP3r6VoCpeVcvJ1Y/e3ZCXPxndWlNP9Jfug==";
};
};
"nthen-0.1.8" = {
name = "nthen";
packageName = "nthen";
version = "0.1.8";
src = fetchurl {
url = "https://registry.npmjs.org/nthen/-/nthen-0.1.8.tgz";
sha512 = "Oh2CwIbhj+wUT94lQV7LKmmgw3UYAGGd8oLIqp6btQN3Bz3PuWp4BuvtUo35H3rqDknjPfKx5P6mt7v+aJNjcw==";
};
};
"on-finished-2.3.0" = {
name = "on-finished";
packageName = "on-finished";
version = "2.3.0";
src = fetchurl {
url = "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz";
sha1 = "20f1336481b083cd75337992a16971aa2d906947";
};
};
"parseurl-1.3.3" = {
name = "parseurl";
packageName = "parseurl";
version = "1.3.3";
src = fetchurl {
url = "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz";
sha512 = "CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==";
};
};
"path-to-regexp-0.1.7" = {
name = "path-to-regexp";
packageName = "path-to-regexp";
version = "0.1.7";
src = fetchurl {
url = "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz";
sha1 = "df604178005f522f15eb4490e7247a1bfaa67f8c";
};
};
"proxy-addr-2.0.7" = {
name = "proxy-addr";
packageName = "proxy-addr";
version = "2.0.7";
src = fetchurl {
url = "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz";
sha512 = "llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==";
};
};
"pull-stream-3.6.14" = {
name = "pull-stream";
packageName = "pull-stream";
version = "3.6.14";
src = fetchurl {
url = "https://registry.npmjs.org/pull-stream/-/pull-stream-3.6.14.tgz";
sha512 = "KIqdvpqHHaTUA2mCYcLG1ibEbu/LCKoJZsBWyv9lSYtPkJPBq8m3Hxa103xHi6D2thj5YXa0TqK3L3GUkwgnew==";
};
};
"qs-6.5.2" = {
name = "qs";
packageName = "qs";
version = "6.5.2";
src = fetchurl {
url = "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz";
sha512 = "N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==";
};
};
"range-parser-1.2.1" = {
name = "range-parser";
packageName = "range-parser";
version = "1.2.1";
src = fetchurl {
url = "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz";
sha512 = "Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==";
};
};
"raw-body-2.3.3" = {
name = "raw-body";
packageName = "raw-body";
version = "2.3.3";
src = fetchurl {
url = "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz";
sha512 = "9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==";
};
};
"safe-buffer-5.1.2" = {
name = "safe-buffer";
packageName = "safe-buffer";
version = "5.1.2";
src = fetchurl {
url = "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz";
sha512 = "Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==";
};
};
"safer-buffer-2.1.2" = {
name = "safer-buffer";
packageName = "safer-buffer";
version = "2.1.2";
src = fetchurl {
url = "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz";
sha512 = "YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==";
};
};
"saferphore-0.0.1" = {
name = "saferphore";
packageName = "saferphore";
version = "0.0.1";
src = fetchurl {
url = "https://registry.npmjs.org/saferphore/-/saferphore-0.0.1.tgz";
sha1 = "cc962eda4e2b2452e6437fd32dcfb6f69ef2ea63";
};
};
"send-0.16.2" = {
name = "send";
packageName = "send";
version = "0.16.2";
src = fetchurl {
url = "https://registry.npmjs.org/send/-/send-0.16.2.tgz";
sha512 = "E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==";
};
};
"serve-static-1.13.2" = {
name = "serve-static";
packageName = "serve-static";
version = "1.13.2";
src = fetchurl {
url = "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz";
sha512 = "p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==";
};
};
"setprototypeof-1.1.0" = {
name = "setprototypeof";
packageName = "setprototypeof";
version = "1.1.0";
src = fetchurl {
url = "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz";
sha512 = "BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==";
};
};
"sortify-1.0.4" = {
name = "sortify";
packageName = "sortify";
version = "1.0.4";
src = fetchurl {
url = "https://registry.npmjs.org/sortify/-/sortify-1.0.4.tgz";
sha1 = "f0178687c83231be8a34fc0ec5462ea957b60284";
};
};
"statuses-1.4.0" = {
name = "statuses";
packageName = "statuses";
version = "1.4.0";
src = fetchurl {
url = "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz";
sha512 = "zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==";
};
};
"stream-to-pull-stream-1.7.3" = {
name = "stream-to-pull-stream";
packageName = "stream-to-pull-stream";
version = "1.7.3";
src = fetchurl {
url = "https://registry.npmjs.org/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz";
sha512 = "6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg==";
};
};
"tiny-each-async-2.0.3" = {
name = "tiny-each-async";
packageName = "tiny-each-async";
version = "2.0.3";
src = fetchurl {
url = "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz";
sha1 = "8ebbbfd6d6295f1370003fbb37162afe5a0a51d1";
};
};
"tweetnacl-0.12.2" = {
name = "tweetnacl";
packageName = "tweetnacl";
version = "0.12.2";
src = fetchurl {
url = "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.12.2.tgz";
sha1 = "bd59f890507856fb0a1136acc3a8b44547e29ddb";
};
};
"type-is-1.6.18" = {
name = "type-is";
packageName = "type-is";
version = "1.6.18";
src = fetchurl {
url = "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz";
sha512 = "TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==";
};
};
"ulimit-0.0.2" = {
name = "ulimit";
packageName = "ulimit";
version = "0.0.2";
src = fetchurl {
url = "https://registry.npmjs.org/ulimit/-/ulimit-0.0.2.tgz";
sha1 = "2b51f9dc8381ae4102636cec5eb338c2630588a0";
};
};
"ultron-1.1.1" = {
name = "ultron";
packageName = "ultron";
version = "1.1.1";
src = fetchurl {
url = "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz";
sha512 = "UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==";
};
};
"universalify-0.1.2" = {
name = "universalify";
packageName = "universalify";
version = "0.1.2";
src = fetchurl {
url = "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz";
sha512 = "rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==";
};
};
"unpipe-1.0.0" = {
name = "unpipe";
packageName = "unpipe";
version = "1.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz";
sha1 = "b2bf4ee8514aae6165b4817829d21b2ef49904ec";
};
};
"utils-merge-1.0.1" = {
name = "utils-merge";
packageName = "utils-merge";
version = "1.0.1";
src = fetchurl {
url = "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz";
sha1 = "9f95710f50a267947b2ccc124741c1028427e713";
};
};
"vary-1.1.2" = {
name = "vary";
packageName = "vary";
version = "1.1.2";
src = fetchurl {
url = "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz";
sha1 = "2299f02c6ded30d4a5961b0b9f74524a18f634fc";
};
};
"ws-3.3.3" = {
name = "ws";
packageName = "ws";
version = "3.3.3";
src = fetchurl {
url = "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz";
sha512 = "nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==";
};
};
};
args = {
name = "cryptpad";
packageName = "cryptpad";
version = "4.14.1";
src = ./.;
dependencies = [
sources."@mcrowe/minibloom-0.2.0"
sources."accepts-1.3.8"
sources."array-flatten-1.1.1"
sources."async-limiter-1.0.1"
sources."body-parser-1.18.3"
sources."bytes-3.0.0"
sources."chainpad-crypto-0.2.7"
sources."chainpad-server-5.1.0"
sources."content-disposition-0.5.2"
sources."content-type-1.0.4"
sources."cookie-0.3.1"
sources."cookie-signature-1.0.6"
sources."debug-2.6.9"
sources."depd-1.1.2"
sources."destroy-1.0.4"
sources."ee-first-1.1.1"
sources."encodeurl-1.0.2"
sources."escape-html-1.0.3"
sources."etag-1.8.1"
sources."express-4.16.4"
sources."finalhandler-1.1.1"
sources."forwarded-0.2.0"
sources."fresh-0.5.2"
sources."fs-extra-7.0.1"
sources."gar-1.0.4"
sources."get-folder-size-2.0.1"
sources."graceful-fs-4.2.10"
sources."http-errors-1.6.3"
sources."iconv-lite-0.4.23"
sources."inherits-2.0.3"
sources."ipaddr.js-1.9.1"
sources."jsonfile-4.0.0"
sources."lex-1.7.9"
sources."looper-3.0.0"
sources."media-typer-0.3.0"
sources."merge-descriptors-1.0.1"
sources."methods-1.1.2"
sources."mime-db-1.52.0"
sources."mime-types-2.1.35"
sources."ms-2.0.0"
sources."negotiator-0.6.3"
sources."netflux-websocket-0.1.21"
sources."nthen-0.1.8"
sources."on-finished-2.3.0"
sources."parseurl-1.3.3"
sources."path-to-regexp-0.1.7"
sources."proxy-addr-2.0.7"
sources."pull-stream-3.6.14"
sources."qs-6.5.2"
sources."range-parser-1.2.1"
sources."raw-body-2.3.3"
sources."safe-buffer-5.1.2"
sources."safer-buffer-2.1.2"
sources."saferphore-0.0.1"
(sources."send-0.16.2" // {
dependencies = [
sources."mime-1.4.1"
];
})
sources."serve-static-1.13.2"
sources."setprototypeof-1.1.0"
sources."sortify-1.0.4"
sources."statuses-1.4.0"
sources."stream-to-pull-stream-1.7.3"
sources."tiny-each-async-2.0.3"
sources."tweetnacl-0.12.2"
sources."type-is-1.6.18"
sources."ulimit-0.0.2"
sources."ultron-1.1.1"
sources."universalify-0.1.2"
sources."unpipe-1.0.0"
sources."utils-merge-1.0.1"
sources."vary-1.1.2"
sources."ws-3.3.3"
];
buildInputs = globalBuildInputs;
meta = {
description = "realtime collaborative visual editor with zero knowlege server";
license = "AGPL-3.0+";
};
production = true;
bypassCache = true;
reconstructLock = false;
};
in
{
args = args;
sources = sources;
tarball = nodeEnv.buildNodeSourceDist args;
package = nodeEnv.buildNodePackage args;
shell = nodeEnv.buildNodeShell args;
nodeDependencies = nodeEnv.buildNodeDependencies (lib.overrideExisting args {
src = stdenv.mkDerivation {
name = args.name + "-package-json";
src = nix-gitignore.gitignoreSourcePure [
"*"
"!package.json"
"!package-lock.json"
] args.src;
dontBuild = true;
installPhase = "mkdir -p $out; cp -r ./* $out;";
};
});
}

View file

@ -0,0 +1,17 @@
# This file has been generated by node2nix 1.9.0. Do not edit!
{pkgs ? import <nixpkgs> {
inherit system;
}, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-12_x"}:
let
nodeEnv = import ./node-env.nix {
inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript;
inherit pkgs nodejs;
libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
};
in
import ./node-packages.nix {
inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit;
inherit nodeEnv;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,55 @@
{
"name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server",
"version": "4.14.1",
"license": "AGPL-3.0+",
"repository": {
"type": "git",
"url": "git+https://github.com/xwiki-labs/cryptpad.git"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/cryptpad"
},
"dependencies": {
"@mcrowe/minibloom": "^0.2.0",
"chainpad-crypto": "^0.2.5",
"chainpad-server": "^5.1.0",
"express": "~4.16.0",
"fs-extra": "^7.0.0",
"get-folder-size": "^2.0.1",
"netflux-websocket": "^0.1.20",
"nthen": "0.1.8",
"pull-stream": "^3.6.1",
"saferphore": "0.0.1",
"sortify": "^1.0.4",
"stream-to-pull-stream": "^1.7.2",
"tweetnacl": "~0.12.2",
"ulimit": "0.0.2",
"ws": "^3.3.1"
},
"devDependencies": {
"jshint": "^2.13.4",
"less": "3.7.1",
"lesshint": "6.3.7",
"selenium-webdriver": "^3.6.0"
},
"scripts": {
"start": "node server.js",
"dev": "DEV=1 node server.js",
"fresh": "FRESH=1 node server.js",
"offline": "FRESH=1 OFFLINE=1 node server.js",
"offlinedev": "DEV=1 OFFLINE=1 node server.js",
"package": "PACKAGE=1 node server.js",
"lint": "jshint --config .jshintrc --exclude-path .jshintignore . && ./node_modules/lesshint/bin/lesshint -c ./.lesshintrc ./customize.dist/src/less2/",
"lint:js": "jshint --config .jshintrc --exclude-path .jshintignore .",
"lint:server": "jshint --config .jshintrc lib",
"lint:less": "./node_modules/lesshint/bin/lesshint -c ./.lesshintrc ./customize.dist/src/less2/",
"lint:translations": "node ./scripts/translations/lint-translations.js",
"unused-translations": "node ./scripts/translations/unused-translations.js",
"test": "node scripts/TestSelenium.js",
"test-rpc": "cd scripts/tests && node test-rpc",
"template": "cd customize.dist/src && for page in ../index.html ../privacy.html ../terms.html ../contact.html ../what-is-cryptpad.html ../features.html ../../www/login/index.html ../../www/register/index.html ../../www/user/index.html;do echo $page; cp template.html $page; done;",
"evict-inactive": "node scripts/evict-inactive.js"
}
}

View file

@ -1,80 +0,0 @@
# Generated by npins. Do not modify; will be overwritten regularly
let
data = builtins.fromJSON (builtins.readFile ./sources.json);
version = data.version;
mkSource =
spec:
assert spec ? type;
let
path =
if spec.type == "Git" then
mkGitSource spec
else if spec.type == "GitRelease" then
mkGitSource spec
else if spec.type == "PyPi" then
mkPyPiSource spec
else if spec.type == "Channel" then
mkChannelSource spec
else
builtins.throw "Unknown source type ${spec.type}";
in
spec // { outPath = path; };
mkGitSource =
{
repository,
revision,
url ? null,
hash,
branch ? null,
...
}:
assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball
if url != null then
(builtins.fetchTarball {
inherit url;
sha256 = hash; # FIXME: check nix version & use SRI hashes
})
else
assert repository.type == "Git";
let
urlToName =
url: rev:
let
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
short = builtins.substring 0 7 rev;
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
in
"${if matched == null then "source" else builtins.head matched}${appendShort}";
name = urlToName repository.url revision;
in
builtins.fetchGit {
url = repository.url;
rev = revision;
inherit name;
# hash = hash;
};
mkPyPiSource =
{ url, hash, ... }:
builtins.fetchurl {
inherit url;
sha256 = hash;
};
mkChannelSource =
{ url, hash, ... }:
builtins.fetchTarball {
inherit url;
sha256 = hash;
};
in
if version == 3 then
builtins.mapAttrs (_: mkSource) data.pins
else
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"

View file

@ -1,11 +0,0 @@
{
"pins": {
"nixpkgs": {
"type": "Channel",
"name": "nixos-24.05",
"url": "https://releases.nixos.org/nixos/24.05/nixos-24.05.5385.1719f27dd95f/nixexprs.tar.xz",
"hash": "0f7i315g1z8kjh10hvj2zv7y2vfqxmwvd96hwlcrr8aig6qq5gzm"
}
},
"version": 3
}

View file

@ -0,0 +1,31 @@
let
common = import ./common.nix;
pkgs = import common.pkgsSrc {};
bower2nixRepo = (import common.bower2nixSrc {
inherit pkgs;
});
bower2nix = bower2nixRepo // {
package = bower2nixRepo.package.override {
postInstall = "tsc";
};
};
in
pkgs.mkShell {
nativeBuildInputs = [
bower2nix.package
pkgs.nodePackages.node2nix
];
shellHook = ''
function update_lock {
set -exuo pipefail
mkdir -p nix.lock
${pkgs.wget}/bin/wget https://raw.githubusercontent.com/xwiki-labs/cryptpad/${common.cryptpadCommit}/package.json -O nix.lock/package.json
${pkgs.wget}/bin/wget https://raw.githubusercontent.com/xwiki-labs/cryptpad/${common.cryptpadCommit}/package-lock.json -O nix.lock/package-lock.json
${pkgs.wget}/bin/wget https://raw.githubusercontent.com/xwiki-labs/cryptpad/${common.cryptpadCommit}/bower.json -O nix.lock/bower.json
${bower2nix.package}/bin/bower2nix nix.lock/bower.json nix.lock/bower.nix
${pkgs.nodePackages.node2nix}/bin/node2nix --input nix.lock/package.json --lock nix.lock/package-lock.json --composition nix.lock/npm.nix --node-env nix.lock/node-env.nix --output nix.lock/node-packages.nix
}
'';
}

View file

@ -1,59 +0,0 @@
# SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Tweaks by Deuxfleurs
# Multistage build to reduce image size and increase security
FROM node:lts-slim AS build
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install --no-install-recommends -y \
ca-certificates tar wget
# Download the release tarball
RUN wget https://github.com/cryptpad/cryptpad/archive/refs/tags/2024.9.0.tar.gz -O cryptpad.tar.gz
# Create folder for CryptPad
RUN mkdir /cryptpad
# Extract the release into /cryptpad
RUN tar xvzf cryptpad.tar.gz -C /cryptpad --strip-components 1
# Go to /cryptpad
WORKDIR /cryptpad
# Install dependencies
RUN npm install --production && npm run install:components
# Create the actual CryptPad image
FROM node:lts-slim
ENV DEBIAN_FRONTEND=noninteractive
# Install curl for healthcheck
# Install git, rdfind and unzip for install-onlyoffice.sh
RUN apt-get update && apt-get install --no-install-recommends -y \
curl ca-certificates git rdfind unzip && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Copy cryptpad with installed modules
COPY --from=build /cryptpad /cryptpad
# Set workdir to cryptpad
WORKDIR /cryptpad
# Install onlyoffice
RUN ./install-onlyoffice.sh --accept-license --trust-repository
# Build static pages (?) unsure we need this
RUN npm run build
# Healthcheck
HEALTHCHECK --interval=1m CMD curl -f http://localhost:3000/ || exit 1
# Ports
EXPOSE 3000 3003
# Run cryptpad on startup
CMD ["npm", "start"]

View file

@ -1,296 +0,0 @@
/* globals module */
/* DISCLAIMER:
There are two recommended methods of running a CryptPad instance:
1. Using a standalone nodejs server without HTTPS (suitable for local development)
2. Using NGINX to serve static assets and to handle HTTPS for API server's websocket traffic
We do not officially recommend or support Apache, Docker, Kubernetes, Traefik, or any other configuration.
Support requests for such setups should be directed to their authors.
If you're having difficulty difficulty configuring your instance
we suggest that you join the project's IRC/Matrix channel.
If you don't have any difficulty configuring your instance and you'd like to
support us for the work that went into making it pain-free we are quite happy
to accept donations via our opencollective page: https://opencollective.com/cryptpad
*/
module.exports = {
/* CryptPad is designed to serve its content over two domains.
* Account passwords and cryptographic content is handled on the 'main' domain,
* while the user interface is loaded on a 'sandbox' domain
* which can only access information which the main domain willingly shares.
*
* In the event of an XSS vulnerability in the UI (that's bad)
* this system prevents attackers from gaining access to your account (that's good).
*
* Most problems with new instances are related to this system blocking access
* because of incorrectly configured sandboxes. If you only see a white screen
* when you try to load CryptPad, this is probably the cause.
*
* PLEASE READ THE FOLLOWING COMMENTS CAREFULLY.
*
*/
/* httpUnsafeOrigin is the URL that clients will enter to load your instance.
* Any other URL that somehow points to your instance is supposed to be blocked.
* The default provided below assumes you are loading CryptPad from a server
* which is running on the same machine, using port 3000.
*
* In a production instance this should be available ONLY over HTTPS
* using the default port for HTTPS (443) ie. https://cryptpad.fr
* In such a case this should be also handled by NGINX, as documented in
* cryptpad/docs/example.nginx.conf (see the $main_domain variable)
*
*/
httpUnsafeOrigin: 'https://pad-debug.deuxfleurs.fr',
/* httpSafeOrigin is the URL that is used for the 'sandbox' described above.
* If you're testing or developing with CryptPad on your local machine then
* it is appropriate to leave this blank. The default behaviour is to serve
* the main domain over port 3000 and to serve the sandbox content over port 3001.
*
* This is not appropriate in a production environment where invasive networks
* may filter traffic going over abnormal ports.
* To correctly configure your production instance you must provide a URL
* with a different domain (a subdomain is sufficient).
* It will be used to load the UI in our 'sandbox' system.
*
* This value corresponds to the $sandbox_domain variable
* in the example nginx file.
*
* Note that in order for the sandboxing system to be effective
* httpSafeOrigin must be different from httpUnsafeOrigin.
*
* CUSTOMIZE AND UNCOMMENT THIS FOR PRODUCTION INSTALLATIONS.
*/
httpSafeOrigin: "https://pad-sandbox-debug.deuxfleurs.fr",
/* httpAddress specifies the address on which the nodejs server
* should be accessible. By default it will listen on 127.0.0.1
* (IPv4 localhost on most systems). If you want it to listen on
* all addresses, including IPv6, set this to '::'.
*
*/
httpAddress: '::',
/* httpPort specifies on which port the nodejs server should listen.
* By default it will serve content over port 3000, which is suitable
* for both local development and for use with the provided nginx example,
* which will proxy websocket traffic to your node server.
*
*/
httpPort: 3000,
/* httpSafePort allows you to specify an alternative port from which
* the node process should serve sandboxed assets. The default value is
* that of your httpPort + 1. You probably don't need to change this.
*
*/
// httpSafePort: 3001,
/* CryptPad will launch a child process for every core available
* in order to perform CPU-intensive tasks in parallel.
* Some host environments may have a very large number of cores available
* or you may want to limit how much computing power CryptPad can take.
* If so, set 'maxWorkers' to a positive integer.
*/
// maxWorkers: 4,
/* =====================
* Admin
* ===================== */
/*
* CryptPad contains an administration panel. Its access is restricted to specific
* users using the following list.
* To give access to the admin panel to a user account, just add their public signing
* key, which can be found on the settings page for registered users.
* Entries should be strings separated by a comma.
*/
adminKeys: [
"[quentin@pad.deuxfleurs.fr/EWtzm-CiqJnM9RZL9mj-YyTgAtX-Zh76sru1K5bFpN8=]",
"[adrn@pad.deuxfleurs.fr/PxDpkPwd-jDJWkfWdAzFX7wtnLpnPlBeYZ4MmoEYS6E=]",
"[lx@pad.deuxfleurs.fr/FwQzcXywx1FIb83z6COB7c3sHnz8rNSDX1xhjPuH3Fg=]",
"[trinity-1686a@pad-debug.deuxfleurs.fr/Pu6Ef03jEsAGBbZI6IOdKd6+5pORD5N51QIYt4-Ys1c=]",
"[Jill@pad.deuxfleurs.fr/tLW7W8EVNB2KYETXEaOYR+HmNiBQtZj7u+SOxS3hGmg=]",
"[vincent@pad.deuxfleurs.fr/07FQiE8w1iztRWwzbRJzEy3xIqnNR31mUFjLNiGXjwU=]",
"[boris@pad.deuxfleurs.fr/kHo5LIhSxDFk39GuhGRp+XKlMjNe+lWfFWM75cINoTQ=]",
"[maximilien@pad.deuxfleurs.fr/UoXHLejYRUjvX6t55hAQKpjMdU-3ecg4eDhAeckZmyE=]",
"[armael@pad-debug.deuxfleurs.fr/CIKMvNdFxGavwTmni0TnR3x9GM0ypgx3DMcFyzppplU=]",
"[bjonglez@pad-debug.deuxfleurs.fr/+RRzwcLPj5ZCWELUXMjmt3u+-lvYnyhpDt4cqAn9nh8=]"
],
/* =====================
* STORAGE
* ===================== */
/* Pads that are not 'pinned' by any registered user can be set to expire
* after a configurable number of days of inactivity (default 90 days).
* The value can be changed or set to false to remove expiration.
* Expired pads can then be removed using a cron job calling the
* `evict-inactive.js` script with node
*
* defaults to 90 days if nothing is provided
*/
//inactiveTime: 90, // days
/* CryptPad archives some data instead of deleting it outright.
* This archived data still takes up space and so you'll probably still want to
* remove these files after a brief period.
*
* cryptpad/scripts/evict-inactive.js is intended to be run daily
* from a crontab or similar scheduling service.
*
* The intent with this feature is to provide a safety net in case of accidental
* deletion. Set this value to the number of days you'd like to retain
* archived data before it's removed permanently.
*
* defaults to 15 days if nothing is provided
*/
//archiveRetentionTime: 15,
/* It's possible to configure your instance to remove data
* stored on behalf of inactive accounts. Set 'accountRetentionTime'
* to the number of days an account can remain idle before its
* documents and other account data is removed.
*
* Leave this value commented out to preserve all data stored
* by user accounts regardless of inactivity.
*/
//accountRetentionTime: 365,
/* Starting with CryptPad 3.23.0, the server automatically runs
* the script responsible for removing inactive data according to
* your configured definition of inactivity. Set this value to `true`
* if you prefer not to remove inactive data, or if you prefer to
* do so manually using `scripts/evict-inactive.js`.
*/
//disableIntegratedEviction: true,
/* Max Upload Size (bytes)
* this sets the maximum size of any one file uploaded to the server.
* anything larger than this size will be rejected
* defaults to 20MB if no value is provided
*/
//maxUploadSize: 20 * 1024 * 1024,
/* Users with premium accounts (those with a plan included in their customLimit)
* can benefit from an increased upload size limit. By default they are restricted to the same
* upload size as any other registered user.
*
*/
//premiumUploadSize: 100 * 1024 * 1024,
/* =====================
* DATABASE VOLUMES
* ===================== */
/*
* We need this config entry, else CryptPad will try to mkdir
* some stuff into Nix store apparently...
*/
base: '/mnt/data',
/*
* CryptPad stores each document in an individual file on your hard drive.
* Specify a directory where files should be stored.
* It will be created automatically if it does not already exist.
*/
filePath: '/mnt/datastore/',
/* CryptPad offers the ability to archive data for a configurable period
* before deleting it, allowing a means of recovering data in the event
* that it was deleted accidentally.
*
* To set the location of this archive directory to a custom value, change
* the path below:
*/
archivePath: '/mnt/data/archive',
/* CryptPad allows logged in users to request that particular documents be
* stored by the server indefinitely. This is called 'pinning'.
* Pin requests are stored in a pin-store. The location of this store is
* defined here.
*/
pinPath: '/mnt/data/pins',
/* if you would like the list of scheduled tasks to be stored in
a custom location, change the path below:
*/
taskPath: '/mnt/data/tasks',
/* if you would like users' authenticated blocks to be stored in
a custom location, change the path below:
*/
blockPath: '/mnt/block',
/* CryptPad allows logged in users to upload encrypted files. Files/blobs
* are stored in a 'blob-store'. Set its location here.
*/
blobPath: '/mnt/blob',
/* CryptPad stores incomplete blobs in a 'staging' area until they are
* fully uploaded. Set its location here.
*/
blobStagingPath: '/mnt/data/blobstage',
decreePath: '/mnt/data/decrees',
/* CryptPad supports logging events directly to the disk in a 'logs' directory
* Set its location here, or set it to false (or nothing) if you'd rather not log
*/
logPath: false,
/* =====================
* Debugging
* ===================== */
/* CryptPad can log activity to stdout
* This may be useful for debugging
*/
logToStdout: true,
/* CryptPad can be configured to log more or less
* the various settings are listed below by order of importance
*
* silly, verbose, debug, feedback, info, warn, error
*
* Choose the least important level of logging you wish to see.
* For example, a 'silly' logLevel will display everything,
* while 'info' will display 'info', 'warn', and 'error' logs
*
* This will affect both logging to the console and the disk.
*/
logLevel: 'silly',
/* clients can use the /settings/ app to opt out of usage feedback
* which informs the server of things like how much each app is being
* used, and whether certain clientside features are supported by
* the client's browser. The intent is to provide feedback to the admin
* such that the service can be improved. Enable this with `true`
* and ignore feedback with `false` or by commenting the attribute
*
* You will need to set your logLevel to include 'feedback'. Set this
* to false if you'd like to exclude feedback from your logs.
*/
logFeedback: false,
/* CryptPad supports verbose logging
* (false by default)
*/
verbose: true,
/* Surplus information:
*
* 'installMethod' is included in server telemetry to voluntarily
* indicate how many instances are using unofficial installation methods
* such as Docker.
*
*/
installMethod: 'deuxfleurs.fr',
};

View file

@ -114,14 +114,7 @@ module.exports = {
adminKeys: [ adminKeys: [
"[quentin@pad.deuxfleurs.fr/EWtzm-CiqJnM9RZL9mj-YyTgAtX-Zh76sru1K5bFpN8=]", "[quentin@pad.deuxfleurs.fr/EWtzm-CiqJnM9RZL9mj-YyTgAtX-Zh76sru1K5bFpN8=]",
"[adrn@pad.deuxfleurs.fr/PxDpkPwd-jDJWkfWdAzFX7wtnLpnPlBeYZ4MmoEYS6E=]", "[adrn@pad.deuxfleurs.fr/PxDpkPwd-jDJWkfWdAzFX7wtnLpnPlBeYZ4MmoEYS6E=]",
"[lx@pad.deuxfleurs.fr/FwQzcXywx1FIb83z6COB7c3sHnz8rNSDX1xhjPuH3Fg=]", "[lx@pad.deuxfleurs.fr/FwQzcXywx1FIb83z6COB7c3sHnz8rNSDX1xhjPuH3Fg=]"
"[trinity-1686a@pad.deuxfleurs.fr/Pu6Ef03jEsAGBbZI6IOdKd6+5pORD5N51QIYt4-Ys1c=]",
"[Jill@pad.deuxfleurs.fr/tLW7W8EVNB2KYETXEaOYR+HmNiBQtZj7u+SOxS3hGmg=]",
"[vincent@pad.deuxfleurs.fr/07FQiE8w1iztRWwzbRJzEy3xIqnNR31mUFjLNiGXjwU=]",
"[boris@pad.deuxfleurs.fr/kHo5LIhSxDFk39GuhGRp+XKlMjNe+lWfFWM75cINoTQ=]",
"[maximilien@pad.deuxfleurs.fr/UoXHLejYRUjvX6t55hAQKpjMdU-3ecg4eDhAeckZmyE=]",
"[armael@pad.deuxfleurs.fr/CIKMvNdFxGavwTmni0TnR3x9GM0ypgx3DMcFyzppplU=]",
"[bjonglez@pad.deuxfleurs.fr/+RRzwcLPj5ZCWELUXMjmt3u+-lvYnyhpDt4cqAn9nh8=]"
], ],
/* ===================== /* =====================
@ -190,18 +183,12 @@ module.exports = {
* DATABASE VOLUMES * DATABASE VOLUMES
* ===================== */ * ===================== */
/*
* We need this config entry, else CryptPad will try to mkdir
* some stuff into Nix store apparently...
*/
base: '/mnt/data',
/* /*
* CryptPad stores each document in an individual file on your hard drive. * CryptPad stores each document in an individual file on your hard drive.
* Specify a directory where files should be stored. * Specify a directory where files should be stored.
* It will be created automatically if it does not already exist. * It will be created automatically if it does not already exist.
*/ */
filePath: '/mnt/datastore/', filePath: './root/mnt/datastore/',
/* CryptPad offers the ability to archive data for a configurable period /* CryptPad offers the ability to archive data for a configurable period
* before deleting it, allowing a means of recovering data in the event * before deleting it, allowing a means of recovering data in the event
@ -210,36 +197,36 @@ module.exports = {
* To set the location of this archive directory to a custom value, change * To set the location of this archive directory to a custom value, change
* the path below: * the path below:
*/ */
archivePath: '/mnt/data/archive', archivePath: './root/mnt/data/archive',
/* CryptPad allows logged in users to request that particular documents be /* CryptPad allows logged in users to request that particular documents be
* stored by the server indefinitely. This is called 'pinning'. * stored by the server indefinitely. This is called 'pinning'.
* Pin requests are stored in a pin-store. The location of this store is * Pin requests are stored in a pin-store. The location of this store is
* defined here. * defined here.
*/ */
pinPath: '/mnt/data/pins', pinPath: './root/mnt/data/pins',
/* if you would like the list of scheduled tasks to be stored in /* if you would like the list of scheduled tasks to be stored in
a custom location, change the path below: a custom location, change the path below:
*/ */
taskPath: '/mnt/data/tasks', taskPath: './root/mnt/data/tasks',
/* if you would like users' authenticated blocks to be stored in /* if you would like users' authenticated blocks to be stored in
a custom location, change the path below: a custom location, change the path below:
*/ */
blockPath: '/mnt/block', blockPath: './root/mnt/block',
/* CryptPad allows logged in users to upload encrypted files. Files/blobs /* CryptPad allows logged in users to upload encrypted files. Files/blobs
* are stored in a 'blob-store'. Set its location here. * are stored in a 'blob-store'. Set its location here.
*/ */
blobPath: '/mnt/blob', blobPath: './root/mnt/blob',
/* CryptPad stores incomplete blobs in a 'staging' area until they are /* CryptPad stores incomplete blobs in a 'staging' area until they are
* fully uploaded. Set its location here. * fully uploaded. Set its location here.
*/ */
blobStagingPath: '/mnt/data/blobstage', blobStagingPath: './root/mnt/data/blobstage',
decreePath: '/mnt/data/decrees', decreePath: './root/mnt/data/decrees',
/* CryptPad supports logging events directly to the disk in a 'logs' directory /* CryptPad supports logging events directly to the disk in a 'logs' directory
* Set its location here, or set it to false (or nothing) if you'd rather not log * Set its location here, or set it to false (or nothing) if you'd rather not log

View file

@ -1,80 +0,0 @@
job "cryptpad-debug" {
datacenters = ["neptune"]
type = "service"
group "cryptpad" {
count = 1
network {
port "http" {
to = 3000
}
}
restart {
attempts = 10
delay = "30s"
}
task "main" {
driver = "docker"
constraint {
attribute = "${attr.unique.hostname}"
operator = "="
value = "courgette"
}
config {
image = "armael/cryptpad:2024.9.0"
ports = [ "http" ]
volumes = [
"/mnt/ssd/cryptpad-debug:/mnt",
"secrets/config-debug.js:/cryptpad/config.js",
]
}
env {
CRYPTPAD_CONFIG = "/cryptpad/config.js"
}
template {
data = file("../config/config-debug.js")
destination = "secrets/config-debug.js"
}
/* Disabled because it requires modifications to the docker image and I do not want to invest the time yet
template {
data = file("../config/application_config-debug.js")
destination = "secrets/config-debug.js"
}
*/
resources {
memory = 1000
cpu = 500
}
service {
name = "cryptpad-debug"
port = "http"
tags = [
"tricot pad-debug.deuxfleurs.fr",
"tricot pad-sandbox-debug.deuxfleurs.fr",
"tricot-add-header Cross-Origin-Resource-Policy cross-origin",
"tricot-add-header Cross-Origin-Embedder-Policy require-corp",
"tricot-add-header Access-Control-Allow-Origin *",
"tricot-add-header Access-Control-Allow-Credentials true",
"d53-cname pad-debug.deuxfleurs.fr",
"d53-cname pad-sandbox-debug.deuxfleurs.fr",
]
check {
type = "http"
path = "/"
interval = "10s"
timeout = "2s"
}
}
}
}
}

View file

@ -22,20 +22,20 @@ job "cryptpad" {
constraint { constraint {
attribute = "${attr.unique.hostname}" attribute = "${attr.unique.hostname}"
operator = "=" operator = "="
value = "courgette" value = "concombre"
} }
config { config {
image = "kokakiwi/cryptpad:2024.9.0" image = "superboum/cryptpad:0p3s44hjh4s1x55kbwkmywmwmx4wfyb8"
ports = [ "http" ] ports = [ "http" ]
volumes = [ volumes = [
"/mnt/ssd/cryptpad:/mnt", "/mnt/ssd/cryptpad:/mnt",
"secrets/config.js:/cryptpad/config.js", "secrets/config.js:/etc/cryptpad/config.js",
] ]
} }
env { env {
CRYPTPAD_CONFIG = "/cryptpad/config.js" CRYPTPAD_CONFIG = "/etc/cryptpad/config.js"
} }
template { template {
@ -63,10 +63,6 @@ job "cryptpad" {
"tricot pad-sandbox.deuxfleurs.fr", "tricot pad-sandbox.deuxfleurs.fr",
"tricot-add-header Cross-Origin-Resource-Policy cross-origin", "tricot-add-header Cross-Origin-Resource-Policy cross-origin",
"tricot-add-header Cross-Origin-Embedder-Policy require-corp", "tricot-add-header Cross-Origin-Embedder-Policy require-corp",
"tricot-add-header Access-Control-Allow-Origin *",
"tricot-add-header Access-Control-Allow-Credentials true",
"d53-cname pad.deuxfleurs.fr",
"d53-cname pad-sandbox.deuxfleurs.fr",
] ]
check { check {
type = "http" type = "http"

View file

@ -0,0 +1,10 @@
dbs:
- path: /ephemeral/drone.db
replicas:
- url: s3://{{ key "secrets/drone-ci/s3_db_bucket" | trimSpace }}/drone.db
region: garage
endpoint: https://garage.deuxfleurs.fr
access-key-id: {{ key "secrets/drone-ci/s3_ak" | trimSpace }}
secret-access-key: {{ key "secrets/drone-ci/s3_sk" | trimSpace }}
force-path-style: true
sync-interval: 60s

View file

@ -0,0 +1,138 @@
job "drone-ci" {
datacenters = ["neptune", "scorpio"]
type = "service"
group "server" {
count = 1
network {
port "web_port" {
to = 80
}
}
task "restore-db" {
lifecycle {
hook = "prestart"
sidecar = false
}
driver = "docker"
config {
image = "litestream/litestream:0.3.9"
args = [
"restore", "-config", "/etc/litestream.yml", "/ephemeral/drone.db"
]
volumes = [
"../alloc/data:/ephemeral",
"secrets/litestream.yml:/etc/litestream.yml"
]
}
template {
data = file("../config/litestream.yml")
destination = "secrets/litestream.yml"
}
resources {
memory = 200
cpu = 100
}
}
task "drone_server" {
driver = "docker"
config {
image = "drone/drone:2.14.0"
ports = [ "web_port" ]
volumes = [
"../alloc/data:/ephemeral",
]
}
template {
data = <<EOH
DRONE_GITEA_SERVER=https://git.deuxfleurs.fr
DRONE_GITEA_CLIENT_ID={{ key "secrets/drone-ci/oauth_client_id" }}
DRONE_GITEA_CLIENT_SECRET={{ key "secrets/drone-ci/oauth_client_secret" }}
DRONE_RPC_SECRET={{ key "secrets/drone-ci/rpc_secret" }}
DRONE_SERVER_HOST=drone.deuxfleurs.fr
DRONE_SERVER_PROTO=https
DRONE_DATABASE_SECRET={{ key "secrets/drone-ci/db_enc_secret" }}
DRONE_COOKIE_SECRET={{ key "secrets/drone-ci/cookie_secret" }}
AWS_ACCESS_KEY_ID={{ key "secrets/drone-ci/s3_ak" }}
AWS_SECRET_ACCESS_KEY={{ key "secrets/drone-ci/s3_sk" }}
AWS_DEFAULT_REGION=garage
AWS_REGION=garage
DRONE_S3_BUCKET={{ key "secrets/drone-ci/s3_storage_bucket" }}
DRONE_S3_ENDPOINT=https://garage.deuxfleurs.fr
DRONE_S3_PATH_STYLE=true
DRONE_DATABASE_DRIVER=sqlite3
DRONE_DATABASE_DATASOURCE=/ephemeral/drone.db
DRONE_USER_CREATE=username:lx-admin,admin:true
DRONE_REGISTRATION_CLOSED=true
DRONE_LOGS_DEBUG=true
DRONE_LOGS_TRACE=true
EOH
destination = "secrets/env"
env = true
}
resources {
cpu = 100
memory = 200
}
service {
name = "drone"
tags = [
"drone",
"tricot drone.deuxfleurs.fr",
"d53-cname drone.deuxfleurs.fr",
]
port = "web_port"
address_mode = "host"
check {
type = "http"
protocol = "http"
port = "web_port"
path = "/"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "600s"
ignore_warnings = false
}
}
}
}
task "replicate-db" {
driver = "docker"
config {
image = "litestream/litestream:0.3.9"
entrypoint = [ "/bin/sh" ]
args = [
"-c",
"echo sleeping; sleep 60; echo launching; litestream replicate -config /etc/litestream.yml"
]
volumes = [
"../alloc/data:/ephemeral",
"secrets/litestream.yml:/etc/litestream.yml"
]
}
template {
data = file("../config/litestream.yml")
destination = "secrets/litestream.yml"
}
resources {
memory = 200
cpu = 100
}
}
}
}

View file

@ -0,0 +1,69 @@
## Install Debian
We recommend Debian Bullseye
## Install Docker CE from docker.io
Do not use the docker engine shipped by Debian
Doc:
- https://docs.docker.com/engine/install/debian/
- https://docs.docker.com/compose/install/
On a fresh install, as root:
```bash
apt-get remove -y docker docker-engine docker.io containerd runc
apt-get update
apt-get install apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```
## Install the runner
*This is our Nix runner version 2, previously we had another way to start Nix runners. This one has a proper way to handle concurrency, require less boilerplate, and should be safer and more idiomatic.*
```bash
wget https://git.deuxfleurs.fr/Deuxfleurs/infrastructure/raw/branch/main/app/drone-ci/integration/nix.conf
wget https://git.deuxfleurs.fr/Deuxfleurs/infrastructure/raw/branch/main/app/drone-ci/integration/docker-compose.yml
# Edit the docker-compose.yml to adapt its variables to your needs,
# especially the capacitiy value and its name.
COMPOSE_PROJECT_NAME=drone DRONE_SECRET=xxx docker-compose up -d
```
That's all folks.
## Check if a given job is built by your runner
```bash
export URL=https://drone.deuxfleurs.fr
export REPO=Deuxfleurs/garage
export BUILD=1312
curl ${URL}/api/repos/${REPO}/builds/${BUILD} \
| jq -c '[.stages[] | { name: .name, machine: .machine }]'
```
It will give you the following result:
```json
[{"name":"default","machine":"1686a"},{"name":"release-linux-x86_64","machine":"vimaire"},{"name":"release-linux-i686","machine":"carcajou"},{"name":"release-linux-aarch64","machine":"caribou"},{"name":"release-linux-armv6l","machine":"cariacou"},{"name":"refresh-release-page","machine":null}]
```
## Random note
*This part might be deprecated!*
This setup is done mainly to allow nix builds with some cache.
To use the cache in Drone, you must set your repository as trusted.
The command line tool does not work (it says it successfully set your repository as trusted but it did nothing):
the only way to set your repository as trusted is to connect on the DB and set the `repo_trusted` field of your repo to true.

View file

@ -0,0 +1,54 @@
version: '3.4'
services:
nix-daemon:
image: nixpkgs/nix:nixos-22.05
restart: always
command: nix-daemon
privileged: true
volumes:
- "nix:/nix"
- "./nix.conf:/etc/nix/nix.conf:ro"
drone-runner:
image: drone/drone-runner-docker:1.8.2
restart: always
environment:
- DRONE_RPC_PROTO=https
- DRONE_RPC_HOST=drone.deuxfleurs.fr
- DRONE_RPC_SECRET=${DRONE_SECRET}
- DRONE_RUNNER_CAPACITY=3
- DRONE_DEBUG=true
- DRONE_LOGS_TRACE=true
- DRONE_RPC_DUMP_HTTP=true
- DRONE_RPC_DUMP_HTTP_BODY=true
- DRONE_RUNNER_NAME=i_forgot_to_change_my_runner_name
- DRONE_RUNNER_LABELS=nix-daemon:1
# we should put "nix:/nix:ro but it is not supported by
# drone-runner-docker because the dependency envconfig does
# not support having two colons (:) in the same stanza.
# Without the RO flag (or using docker userns), build isolation
# is broken.
# https://discourse.drone.io/t/allow-mounting-a-host-volume-as-read-only/10071
# https://github.com/kelseyhightower/envconfig/pull/153
#
# A workaround for isolation is to configure docker with a userns,
# so even if the folder is writable to root, it is not to any non
# privileged docker daemon ran by drone!
- DRONE_RUNNER_VOLUMES=drone_nix:/nix
- DRONE_RUNNER_ENVIRON=NIX_REMOTE:daemon
ports:
- "3000:3000/tcp"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
drone-gc:
image: drone/gc:latest
restart: always
environment:
- GC_DEBUG=true
- GC_CACHE=10gb
- GC_INTERVAL=10m
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
volumes:
nix:

View file

@ -0,0 +1,48 @@
# Drone's secrets
[secrets."drone-ci/rpc_secret"]
type = 'command'
command = 'openssl rand -hex 16'
# don't rotate, it would break all runners
[secrets."drone-ci/cookie_secret"]
type = 'command'
rotate = true
command = 'openssl rand -hex 16'
[secrets."drone-ci/db_enc_secret"]
type = 'command'
command = 'openssl rand -hex 16'
# don't rotate, it is used to encrypt data which we would lose if we change this
# Oauth config for gitea
[secrets."drone-ci/oauth_client_secret"]
type = 'user'
description = 'OAuth client secret (for gitea)'
[secrets."drone-ci/oauth_client_id"]
type = 'user'
description = 'OAuth client ID (on Gitea)'
# S3 config for Git LFS storage
[secrets."drone-ci/s3_db_bucket"]
type = 'constant'
value = 'drone-db'
[secrets."drone-ci/s3_sk"]
type = 'user'
description = 'S3 (garage) secret key for Drone'
[secrets."drone-ci/s3_ak"]
type = 'user'
description = 'S3 (garage) access key for Drone'
[secrets."drone-ci/s3_storage_bucket"]
type = 'constant'
value = 'drone-storage'

View file

@ -5,5 +5,3 @@
*@pointecouteau.com smtp._domainkey.deuxfleurs.fr *@pointecouteau.com smtp._domainkey.deuxfleurs.fr
*@maycausesideeffects.com smtp._domainkey.deuxfleurs.fr *@maycausesideeffects.com smtp._domainkey.deuxfleurs.fr
*@e-x-t-r-a-c-t.me smtp._domainkey.deuxfleurs.fr *@e-x-t-r-a-c-t.me smtp._domainkey.deuxfleurs.fr
*@courderec.re smtp._domainkey.deuxfleurs.fr
*@trinity.fr.eu.org smtp._domainkey.deuxfleurs.fr

View file

@ -83,14 +83,11 @@ smtpd_forbid_unauth_pipelining = yes
smtpd_discard_ehlo_keywords = chunking smtpd_discard_ehlo_keywords = chunking
smtpd_forbid_bare_newline = yes smtpd_forbid_bare_newline = yes
smtpd_client_connection_rate_limit = 2
#=== #===
# Rate limiting # Rate limiting
#=== #===
smtpd_client_connection_rate_limit = 2
# do not rate-limit ourselves
# in particular, useful for forgejo who opens a lot of SMTP connections
smtpd_client_event_limit_exceptions = $mynetworks /etc/postfix/rate-limit-exceptions
slow_destination_recipient_limit = 20 slow_destination_recipient_limit = 20
slow_destination_concurrency_limit = 2 slow_destination_concurrency_limit = 2

View file

@ -1,6 +1,5 @@
job "email-android7" { job "email-android7" {
# Should not run on the same site as email.hcl (port conflict in diplonat) datacenters = ["neptune"]
datacenters = ["scorpio", "bespin"]
type = "service" type = "service"
priority = 100 priority = 100
@ -42,7 +41,7 @@ job "email-android7" {
resources { resources {
cpu = 50 cpu = 50
memory = 200 memory = 50
} }
service { service {
@ -96,7 +95,7 @@ job "email-android7" {
resources { resources {
cpu = 50 cpu = 50
memory = 200 memory = 50
} }
service { service {

View file

@ -1,6 +1,5 @@
job "email" { job "email" {
# Should not run on the same site as email-android7.hcl (port conflict in diplonat) datacenters = ["scorpio"]
datacenters = ["neptune"]
type = "service" type = "service"
priority = 65 priority = 65
@ -32,7 +31,7 @@ job "email" {
constraint { constraint {
attribute = "${attr.unique.hostname}" attribute = "${attr.unique.hostname}"
operator = "=" operator = "="
value = "celeri" value = "ananas"
} }
config { config {
@ -382,29 +381,6 @@ job "email" {
destination = "secrets/postfix/transport" destination = "secrets/postfix/transport"
} }
template {
# Collect machine IPs from the cluster.
# We use intermediate maps to ensure we get a sorted list with no duplicates,
# so that it is robust wrt. changes in the order of the output of ls or
# addition of new machines in an existing site.
# (scratch.MapValues returns the list of *values* in the map, sorted by *key*)
data = <<EOH
{{- range ls "diplonat/autodiscovery/ipv4" }}
{{- with $a := .Value | parseJSON }}
{{- scratch.MapSet "ipv4" $a.address $a.address }}
{{- end }}
{{- end -}}
{{- range ls "diplonat/autodiscovery/ipv6" }}
{{- with $a := .Value | parseJSON }}
{{- scratch.MapSet "ipv6" $a.address $a.address }}
{{- end }}
{{- end -}}
{{- range scratch.MapValues "ipv4" }}{{ . }} {{ end }}
{{- range scratch.MapValues "ipv6" }}[{{ . }}] {{ end }}
EOH
destination = "secrets/postfix/rate-limit-exceptions"
}
# --- secrets --- # --- secrets ---
template { template {
data = "{{ with $d := key \"tricot/certs/smtp.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}" data = "{{ with $d := key \"tricot/certs/smtp.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}"

View file

@ -6,8 +6,6 @@ db_engine = "lmdb"
replication_mode = "3" replication_mode = "3"
metadata_auto_snapshot_interval = "24h"
# IPv6 config using the ipv6 address statically defined in Nomad's node metadata # IPv6 config using the ipv6 address statically defined in Nomad's node metadata
# make sure to put back double { and } if re-enabling this # make sure to put back double { and } if re-enabling this
#rpc_bind_addr = "[{ env "meta.public_ipv6" }]:3901" #rpc_bind_addr = "[{ env "meta.public_ipv6" }]:3901"

View file

@ -26,7 +26,7 @@ job "garage" {
task "server" { task "server" {
driver = "docker" driver = "docker"
config { config {
image = "superboum/garage:v1.0.0-rc1-hotfix-red-ftr-wquorum" image = "dxflrs/garage:v0.9.0"
command = "/garage" command = "/garage"
args = [ "server" ] args = [ "server" ]
network_mode = "host" network_mode = "host"
@ -80,9 +80,9 @@ job "garage" {
#### Configuration for service ports: admin port (internal use only) #### Configuration for service ports: admin port (internal use only)
service { service {
name = "garage-admin"
port = "admin" port = "admin"
address_mode = "host" address_mode = "host"
name = "garage-admin"
# Check that Garage is alive and answering TCP connections # Check that Garage is alive and answering TCP connections
check { check {
type = "tcp" type = "tcp"
@ -96,19 +96,18 @@ job "garage" {
} }
} }
#### Configuration for service ports: externally available ports (S3 API, K2V, web) #### Configuration for service ports: externally available ports (API, web)
service { service {
name = "garage-api"
tags = [ tags = [
"garage_api", "garage_api",
"tricot garage.deuxfleurs.fr", "tricot garage.deuxfleurs.fr",
"tricot *.garage.deuxfleurs.fr", "tricot *.garage.deuxfleurs.fr",
"tricot-on-demand-tls-ask http://garage-admin.service.prod.consul:3903/check",
"tricot-site-lb", "tricot-site-lb",
] ]
port = "s3" port = "s3"
address_mode = "host" address_mode = "host"
name = "garage-api"
# Check 1: Garage is alive and answering TCP connections # Check 1: Garage is alive and answering TCP connections
check { check {
name = "garage-api-live" name = "garage-api-live"
@ -133,39 +132,6 @@ job "garage" {
} }
service { service {
name = "garage-k2v"
tags = [
"garage_k2v",
"tricot k2v.deuxfleurs.fr",
"tricot-site-lb",
]
port = "k2v"
address_mode = "host"
# Check 1: Garage is alive and answering TCP connections
check {
name = "garage-k2v-live"
type = "tcp"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
# Check 2: Garage is in a healthy state and requests should be routed here
check {
name = "garage-k2v-healthy"
port = "admin"
type = "http"
path = "/health"
interval = "60s"
timeout = "5s"
}
}
service {
name = "garage-web"
tags = [ tags = [
"garage-web", "garage-web",
"tricot * 1", "tricot * 1",
@ -178,6 +144,7 @@ job "garage" {
] ]
port = "web" port = "web"
address_mode = "host" address_mode = "host"
name = "garage-web"
# Check 1: Garage is alive and answering TCP connections # Check 1: Garage is alive and answering TCP connections
check { check {
name = "garage-web-live" name = "garage-web-live"
@ -216,6 +183,39 @@ job "garage" {
port = "web" port = "web"
on_update = "ignore" on_update = "ignore"
} }
service {
tags = [
"garage_k2v",
"tricot k2v.deuxfleurs.fr",
"tricot-site-lb",
]
port = "k2v"
address_mode = "host"
name = "garage-k2v"
# Check 1: Garage is alive and answering TCP connections
check {
name = "garage-k2v-live"
type = "tcp"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
# Check 2: Garage is in a healthy state and requests should be routed here
check {
name = "garage-k2v-healthy"
port = "admin"
type = "http"
path = "/health"
interval = "60s"
timeout = "5s"
}
}
} }
} }
} }

View file

@ -1,5 +1,5 @@
job "guichet" { job "guichet" {
datacenters = ["neptune", "jupiter", "corrin", "bespin"] datacenters = [ "neptune", "scorpio" ]
type = "service" type = "service"
priority = 90 priority = 90
@ -14,7 +14,7 @@ job "guichet" {
driver = "docker" driver = "docker"
config { config {
image = "dxflrs/guichet:m1gzk1r00xp0kz566fwbpc87z7haq7xj" image = "dxflrs/guichet:m1gzk1r00xp0kz566fwbpc87z7haq7xj"
args = [ "server", "-config", "/etc/config.json" ] args = [ "server", "-config", "/etc/config.json" ]
readonly_rootfs = true readonly_rootfs = true
ports = [ "web_port" ] ports = [ "web_port" ]
volumes = [ volumes = [
@ -35,8 +35,8 @@ job "guichet" {
name = "guichet" name = "guichet"
tags = [ tags = [
"guichet", "guichet",
"tricot guichet.staging.deuxfleurs.org", "tricot guichet.deuxfleurs.fr",
"d53-cname guichet.staging.deuxfleurs.org", "d53-cname guichet.deuxfleurs.fr",
] ]
port = "web_port" port = "web_port"
address_mode = "host" address_mode = "host"

View file

@ -1,62 +0,0 @@
job "guichet" {
datacenters = [ "neptune", "scorpio" ]
type = "service"
priority = 90
group "guichet" {
count = 1
network {
port "web_port" { to = 9991 }
}
task "guichet" {
driver = "docker"
config {
image = "dxflrs/guichet:0x4y7bj1qb8w8hckvpbzlgyxh63j66ij"
args = [ "server", "-config", "/etc/config.json" ]
readonly_rootfs = true
ports = [ "web_port" ]
volumes = [
"secrets/config.json:/etc/config.json"
]
}
template {
data = file("../config/guichet/config.json.tpl")
destination = "secrets/config.json"
}
resources {
# limite de mémoire un peu élevée par précaution.
# avec 200M, j'ai observé guichet se faire OOM-killed au moment
# un nouvel utilisateur clique sur un lien d'invitation
# fraichement généré.
memory = 300
}
service {
name = "guichet"
tags = [
"guichet",
"tricot guichet.deuxfleurs.fr",
"d53-cname guichet.deuxfleurs.fr",
]
port = "web_port"
address_mode = "host"
check {
type = "tcp"
port = "web_port"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
}
}
}

View file

@ -6,17 +6,16 @@ services:
context: ./jitsi-meet context: ./jitsi-meet
args: args:
# https://github.com/jitsi/jitsi-meet # https://github.com/jitsi/jitsi-meet
MEET_TAG: stable/jitsi-meet_9646 MEET_TAG: stable/jitsi-meet_8252
NODE_MAJOR_VERSION: 22 image: superboum/amd64_jitsi_meet:v6
image: superboum/amd64_jitsi_meet:v7
jitsi-conference-focus: jitsi-conference-focus:
build: build:
context: ./jitsi-conference-focus context: ./jitsi-conference-focus
args: args:
# https://github.com/jitsi/jicofo # https://github.com/jitsi/jicofo
JICOFO_TAG: stable/jitsi-meet_9646 JICOFO_TAG: stable/jitsi-meet_8252
image: superboum/amd64_jitsi_conference_focus:v11 image: superboum/amd64_jitsi_conference_focus:v10
jitsi-videobridge: jitsi-videobridge:
build: build:
@ -24,13 +23,13 @@ services:
args: args:
# https://github.com/jitsi/jitsi-videobridge # https://github.com/jitsi/jitsi-videobridge
# note: JVB is not tagged with non-stable tags # note: JVB is not tagged with non-stable tags
JVB_TAG: stable/jitsi-meet_9646 JVB_TAG: stable/jitsi-meet_8252
image: superboum/amd64_jitsi_videobridge:v22 image: superboum/amd64_jitsi_videobridge:v21
jitsi-xmpp: jitsi-xmpp:
build: build:
context: ./jitsi-xmpp context: ./jitsi-xmpp
args: args:
MEET_TAG: stable/jitsi-meet_9646 MEET_TAG: stable/jitsi-meet_8252
PROSODY_VERSION: 0.12.3-1 PROSODY_VERSION: 1nightly191-1~bookworm
image: superboum/amd64_jitsi_xmpp:v12 image: superboum/amd64_jitsi_xmpp:v11

View file

@ -1,9 +1,8 @@
FROM debian:bookworm AS builder FROM debian:bookworm AS builder
ARG NODE_MAJOR_VERSION
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y curl && \ apt-get install -y curl && \
curl -sL https://deb.nodesource.com/setup_${NODE_MAJOR_VERSION}.x | bash - && \ curl -sL https://deb.nodesource.com/setup_19.x | bash - && \
apt-get install -y git nodejs make git unzip apt-get install -y git nodejs make git unzip
ARG MEET_TAG ARG MEET_TAG

View file

@ -6,7 +6,7 @@ if [ -z "${JITSI_NAT_LOCAL_IP}" ]; then
fi fi
if [ -z "${JITSI_NAT_PUBLIC_IP}" ]; then if [ -z "${JITSI_NAT_PUBLIC_IP}" ]; then
JITSI_NAT_PUBLIC_IP=$(curl -4 https://ifconfig.me) JITSI_NAT_PUBLIC_IP=$(curl https://ifconfig.me)
fi fi
echo "NAT config: ${JITSI_NAT_LOCAL_IP} -> ${JITSI_NAT_PUBLIC_IP}" echo "NAT config: ${JITSI_NAT_LOCAL_IP} -> ${JITSI_NAT_PUBLIC_IP}"

View file

@ -13,8 +13,8 @@ RUN apt-get update && \
apt-get install -y wget gnupg2 extrepo && \ apt-get install -y wget gnupg2 extrepo && \
extrepo enable prosody && \ extrepo enable prosody && \
apt-get update && \ apt-get update && \
apt-cache show prosody && \ apt-cache show prosody-0.12 && \
apt-get install -y prosody=${PROSODY_VERSION} lua-event apt-get install -y prosody-0.12=${PROSODY_VERSION} lua-event
RUN mkdir -p /usr/local/share/ca-certificates/ && \ RUN mkdir -p /usr/local/share/ca-certificates/ && \
ln -sf \ ln -sf \

View file

@ -368,8 +368,7 @@ var config = {
// Message to show the users. Example: 'The service will be down for // Message to show the users. Example: 'The service will be down for
// maintenance at 01:00 AM GMT, // maintenance at 01:00 AM GMT,
// Does only support plaintext. No line skip. // noticeMessage: '',
// noticeMessage: "Suite à une utilisation contraire à nos CGU, Deuxfleurs surveille activement cette instance Jitsi et enverra tout contenu illégal à la police. Pour toute question, commentaire ou suggestion, contactez moderation@deuxfleurs.fr . Following usage breaching our TOS, Deuxfleurs actively monitors this Jitsi instance and will send any illegal behavior to the Police. For any question, remark or suggestion, reach moderation@deuxfleurs.fr",
// Enables calendar integration, depends on googleApiApplicationClientID // Enables calendar integration, depends on googleApiApplicationClientID
// and microsoftApiApplicationClientID // and microsoftApiApplicationClientID

View file

@ -37,12 +37,6 @@ http {
access_log /dev/stdout; access_log /dev/stdout;
server_names_hash_bucket_size 64; server_names_hash_bucket_size 64;
# Log real IPs
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
real_ip_header X-Forwarded-For;
# inspired by https://raw.githubusercontent.com/jitsi/docker-jitsi-meet/master/web/rootfs/defaults/meet.conf # inspired by https://raw.githubusercontent.com/jitsi/docker-jitsi-meet/master/web/rootfs/defaults/meet.conf
server { server {
#listen 0.0.0.0:{{ env "NOMAD_PORT_https_port" }} ssl http2 default_server; #listen 0.0.0.0:{{ env "NOMAD_PORT_https_port" }} ssl http2 default_server;
@ -81,12 +75,6 @@ http {
alias /srv/jitsi-meet/$1/$2; alias /srv/jitsi-meet/$1/$2;
} }
# Disallow robots indexation
location = /robots.txt {
add_header Content-Type text/plain;
return 200 "User-agent: *\nDisallow: /\n";
}
# not used yet VVV # not used yet VVV
# colibri (JVB) websockets # colibri (JVB) websockets
#location ~ ^/colibri-ws/([a-zA-Z0-9-\.]+)/(.*) { #location ~ ^/colibri-ws/([a-zA-Z0-9-\.]+)/(.*) {
@ -97,16 +85,7 @@ http {
# tcp_nodelay on; # tcp_nodelay on;
#} #}
location ~* {{ key "secrets/jitsi/blacklist_regex" }} {
return 302 https://www.service-public.fr/particuliers/vosdroits/R17674;
}
location = /http-bind { location = /http-bind {
if ($args ~* {{ key "secrets/jitsi/blacklist_regex" }}) {
return 403 'forbidden';
}
# We add CORS to use a different frontend which is useful for load testing as we do not want to advertise too much our URL # We add CORS to use a different frontend which is useful for load testing as we do not want to advertise too much our URL
add_header 'Access-Control-Allow-Headers' 'content-type'; add_header 'Access-Control-Allow-Headers' 'content-type';
add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS'; add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS';

View file

@ -115,8 +115,7 @@ videobridge {
# (e.g. health or debug stats) # (e.g. health or debug stats)
private { private {
# See JettyBundleActivatorConfig in Jicoco for values # See JettyBundleActivatorConfig in Jicoco for values
host = 0.0.0.0 host = 127.0.0.1
port = {{ env "NOMAD_PORT_management_port" }}
} }
} }
octo { octo {

View file

@ -1,5 +1,5 @@
job "jitsi" { job "jitsi" {
datacenters = ["neptune", "scorpio", "corrin"] datacenters = ["neptune", "scorpio"]
type = "service" type = "service"
priority = 50 priority = 50
@ -20,7 +20,7 @@ job "jitsi" {
task "xmpp" { task "xmpp" {
driver = "docker" driver = "docker"
config { config {
image = "superboum/amd64_jitsi_xmpp:v12" image = "superboum/amd64_jitsi_xmpp:v11"
ports = [ "bosh_port", "xmpp_port" ] ports = [ "bosh_port", "xmpp_port" ]
network_mode = "host" network_mode = "host"
volumes = [ volumes = [
@ -101,7 +101,7 @@ EOF
task "front" { task "front" {
driver = "docker" driver = "docker"
config { config {
image = "superboum/amd64_jitsi_meet:v7" image = "superboum/amd64_jitsi_meet:v6"
network_mode = "host" network_mode = "host"
ports = [ "https_port" ] ports = [ "https_port" ]
volumes = [ volumes = [
@ -112,11 +112,6 @@ EOF
] ]
} }
logs {
max_files = 25
max_file_size = 10
}
template { template {
data = file("../config/config.js") data = file("../config/config.js")
destination = "secrets/config.js" destination = "secrets/config.js"
@ -168,7 +163,7 @@ EOF
task "jicofo" { task "jicofo" {
driver = "docker" driver = "docker"
config { config {
image = "superboum/amd64_jitsi_conference_focus:v11" image = "superboum/amd64_jitsi_conference_focus:v10"
network_mode = "host" network_mode = "host"
volumes = [ volumes = [
"secrets/certs/jitsi.crt:/usr/local/share/ca-certificates/jitsi.crt", "secrets/certs/jitsi.crt:/usr/local/share/ca-certificates/jitsi.crt",
@ -203,15 +198,14 @@ EOF
group "data_plane" { group "data_plane" {
network { network {
port "video_port" { static = 8080 } port "video_port" { static = 8080 }
port "management_port" { static = 8000 }
} }
task "videobridge" { task "videobridge" {
driver = "docker" driver = "docker"
config { config {
image = "superboum/amd64_jitsi_videobridge:v22" image = "superboum/amd64_jitsi_videobridge:v21"
network_mode = "host" network_mode = "host"
ports = [ "video_port", "management_port" ] ports = [ "video_port" ]
ulimit { ulimit {
nofile = "1048576:1048576" nofile = "1048576:1048576"
nproc = "65536:65536" nproc = "65536:65536"
@ -223,14 +217,11 @@ EOF
] ]
} }
template { env {
data = <<EOH # Our container can autodetect the public IP with the ifconfig.me service
{{ with $a := env "attr.unique.hostname" | printf "diplonat/autodiscovery/ipv4/%s" | key | parseJSON }} # However we would like to avoid relying on a 3rd party service for production use
JITSI_NAT_PUBLIC_IP = {{ $a.address }} # That's why I am setting the public IP address statically here VVVV
{{ end }} JITSI_NAT_PUBLIC_IP = "${meta.public_ipv4}"
EOH
destination = "secrets/jitsi-videobridge.env"
env = true
} }
template { template {
@ -260,16 +251,9 @@ EOF
port = "video_port" port = "video_port"
address_mode = "host" address_mode = "host"
name = "video-jitsi" name = "video-jitsi"
}
service {
tags = [ "jitsi" ]
port = "management_port"
address_mode = "host"
name = "management-video-jitsi"
check { check {
type = "tcp" type = "tcp"
port = "management_port" port = "video_port"
interval = "60s" interval = "60s"
timeout = "5s" timeout = "5s"
} }

View file

@ -52,7 +52,7 @@ But maybe this value is deprecated: the check is still here but it is not used a
start a maintainance container start a maintainance container
``` ```
docker run --rm -it -v `pwd`/prosody/certs/:/var/lib/prosody/ -v `pwd`/prosody/prosody.cfg.lua:/etc/prosody/prosody.cfg.lua:ro --user root superboum/amd64_jitsi_xmpp:v12 bash docker run --rm -it -v `pwd`/prosody/certs/:/var/lib/prosody/ -v `pwd`/prosody/prosody.cfg.lua:/etc/prosody/prosody.cfg.lua:ro --user root superboum/amd64_jitsi_xmpp:v11 bash
``` ```
then generate certificates from inside this container then generate certificates from inside this container

View file

@ -1,7 +1,7 @@
version: '3.4' version: '3.4'
services: services:
jitsi-xmpp: jitsi-xmpp:
image: superboum/amd64_jitsi_xmpp:v12 image: superboum/amd64_jitsi_xmpp:v11
volumes: volumes:
- "./prosody/prosody.cfg.lua:/etc/prosody/prosody.cfg.lua:ro" - "./prosody/prosody.cfg.lua:/etc/prosody/prosody.cfg.lua:ro"
- "./prosody/certs/jitsi.crt:/var/lib/prosody/jitsi.crt:ro" - "./prosody/certs/jitsi.crt:/var/lib/prosody/jitsi.crt:ro"
@ -11,19 +11,16 @@ services:
environment: environment:
- JICOFO_AUTH_PASSWORD=jicofopass - JICOFO_AUTH_PASSWORD=jicofopass
- JVB_AUTH_PASSWORD=jvbpass - JVB_AUTH_PASSWORD=jvbpass
ports:
- "5222:5222/tcp"
jitsi-conference-focus: jitsi-conference-focus:
image: superboum/amd64_jitsi_conference_focus:v11 image: superboum/amd64_jitsi_conference_focus:v10
volumes: volumes:
- "./prosody/certs/jitsi.crt:/usr/local/share/ca-certificates/jitsi.crt:ro" - "./prosody/certs/jitsi.crt:/usr/local/share/ca-certificates/jitsi.crt:ro"
- "./prosody/certs/auth.jitsi.crt:/usr/local/share/ca-certificates/auth.jitsi.crt:ro" - "./prosody/certs/auth.jitsi.crt:/usr/local/share/ca-certificates/auth.jitsi.crt:ro"
- "./jicofo/jicofo.conf:/etc/jitsi/jicofo.conf:ro" - "./jicofo/jicofo.conf:/etc/jitsi/jicofo.conf:ro"
jitsi-videobridge: jitsi-videobridge:
image: superboum/amd64_jitsi_videobridge:v22 image: superboum/amd64_jitsi_videobridge:v21
network_mode: "host"
volumes: volumes:
- "./prosody/certs/jitsi.crt:/usr/local/share/ca-certificates/jitsi.crt:ro" - "./prosody/certs/jitsi.crt:/usr/local/share/ca-certificates/jitsi.crt:ro"
- "./prosody/certs/auth.jitsi.crt:/usr/local/share/ca-certificates/auth.jitsi.crt:ro" - "./prosody/certs/auth.jitsi.crt:/usr/local/share/ca-certificates/auth.jitsi.crt:ro"
@ -34,7 +31,7 @@ services:
- "10000:10000/udp" - "10000:10000/udp"
jitsi-meet: jitsi-meet:
image: superboum/amd64_jitsi_meet:v7 image: superboum/amd64_jitsi_meet:v6
volumes: volumes:
- "./prosody/certs/jitsi.crt:/etc/nginx/jitsi.crt:ro" - "./prosody/certs/jitsi.crt:/etc/nginx/jitsi.crt:ro"
- "./prosody/certs/jitsi.key:/etc/nginx/jitsi.key:ro" - "./prosody/certs/jitsi.key:/etc/nginx/jitsi.key:ro"

View file

@ -62,7 +62,7 @@ videobridge {
configs { configs {
unique-xmpp-server { unique-xmpp-server {
hostname="172.17.0.1" hostname="jitsi-xmpp"
domain = "auth.jitsi" domain = "auth.jitsi"
username = "jvb" username = "jvb"
password = "jvbpass" password = "jvbpass"

View file

@ -22,7 +22,7 @@ var config = {
}, },
// BOSH URL. FIXME: use XEP-0156 to discover it. // BOSH URL. FIXME: use XEP-0156 to discover it.
bosh: '//[2a0c:e303:0:2a00::de6]/http-bind', bosh: '//192.168.1.143/http-bind',
// Websocket URL // Websocket URL
// websocket: 'wss://jitsi-meet.example.com/xmpp-websocket', // websocket: 'wss://jitsi-meet.example.com/xmpp-websocket',

View file

@ -1,14 +0,0 @@
# Informations relatives à la config Matrix
## Ressources
- La doc de Synapse est là : https://element-hq.github.io/synapse/latest/welcome_and_overview.html
### Métriques
- La page pour configurer les metrics : https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=metrics#metrics
- La page pour le tutoriel sur configurer les metrics avec Prometheus : https://element-hq.github.io/synapse/latest/metrics-howto.html?highlight=metrics#how-to-monitor-synapse-metrics-using-prometheus
---
> Avec Nix on n'aurait pas tous ces problèmes.

View file

@ -6,18 +6,18 @@ services:
context: ./riotweb context: ./riotweb
args: args:
# https://github.com/vector-im/element-web/releases # https://github.com/vector-im/element-web/releases
VERSION: v1.11.78 VERSION: 1.11.49
image: particallydone/amd64_elementweb:v36 image: lxpz/amd64_elementweb:v35
synapse: synapse:
build: build:
context: ./matrix-synapse context: ./matrix-synapse
args: args:
# https://github.com/matrix-org/synapse/releases # https://github.com/matrix-org/synapse/releases
VERSION: v1.104.0 VERSION: 1.95.1
# https://github.com/matrix-org/synapse-s3-storage-provider/commits/main # https://github.com/matrix-org/synapse-s3-storage-provider/commits/main
# Update with the latest commit on main each time you update the synapse version # Update with the latest commit on main each time you update the synapse version
# otherwise synapse may fail to launch due to incompatibility issues # otherwise synapse may fail to launch due to incompatibility issues
# see this issue for an example: https://github.com/matrix-org/synapse-s3-storage-provider/issues/64 # see this issue for an example: https://github.com/matrix-org/synapse-s3-storage-provider/issues/64
S3_VERSION: 2c46a764f700e6439afa11c00db827ddf21a9e89 S3_VERSION: v1.2.1
image: particallydone/amd64_synapse:v60 image: lxpz/amd64_synapse:v58

View file

@ -1,4 +1,4 @@
FROM amd64/debian:trixie AS builder FROM amd64/debian:bookworm as builder
ARG VERSION ARG VERSION
ARG S3_VERSION ARG S3_VERSION
@ -22,25 +22,21 @@ RUN apt-get update && \
libpq-dev \ libpq-dev \
virtualenv \ virtualenv \
libxslt1-dev \ libxslt1-dev \
git git && \
virtualenv /root/matrix-env -p /usr/bin/python3 && \
RUN virtualenv /root/matrix-env -p /usr/bin/python3 && \
. /root/matrix-env/bin/activate && \ . /root/matrix-env/bin/activate && \
pip3 install \ pip3 install \
https://github.com/element-hq/synapse/archive/${VERSION}.tar.gz#egg=matrix-synapse[matrix-synapse-ldap3,postgres,resources.consent,saml2,url_preview] && \ https://github.com/matrix-org/synapse/archive/v${VERSION}.tar.gz#egg=matrix-synapse[matrix-synapse-ldap3,postgres,resources.consent,saml2,url_preview] && \
pip3 install \ pip3 install \
git+https://github.com/matrix-org/synapse-s3-storage-provider.git@${S3_VERSION} git+https://github.com/matrix-org/synapse-s3-storage-provider.git@${S3_VERSION}
# WARNING: trixie n'est pas une LTS FROM amd64/debian:bookworm
# mais on est obligé d'avoir la même version que le builder
# et le builder veut une version de rustc qui n'est pas dans bookworm (dernière LTS at the time of writing)
FROM amd64/debian:trixie
RUN apt-get update && \ RUN apt-get update && \
apt-get -qq -y full-upgrade && \ apt-get -qq -y full-upgrade && \
apt-get install -y \ apt-get install -y \
python3 \ python3 \
python3-setuptools \ python3-distutils \
libffi8 \ libffi8 \
libjpeg62-turbo \ libjpeg62-turbo \
libssl3 \ libssl3 \

View file

@ -1,16 +1,13 @@
FROM amd64/debian:trixie as builder FROM amd64/debian:buster as builder
ARG VERSION ARG VERSION
WORKDIR /root WORKDIR /root
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y wget apt-get install -y wget && \
wget https://github.com/vector-im/element-web/releases/download/v${VERSION}/element-v${VERSION}.tar.gz && \
tar xf element-v${VERSION}.tar.gz && \
mv element-v${VERSION}/ riot/
RUN wget https://github.com/element-hq/element-web/releases/download/${VERSION}/element-${VERSION}.tar.gz && \
tar xf element-${VERSION}.tar.gz && \
mv element-${VERSION}/ riot/
# Le conteneur de superboum contient uniquement un serveur web de 5 lignes.
# Ca vous ennuie ? On peut publier Riot dans un bucket web Garage, tkt, ça sera Tricot qui servira.
FROM superboum/amd64_webserver:v3 FROM superboum/amd64_webserver:v3
COPY --from=builder /root/riot /srv/http COPY --from=builder /root/riot /srv/http

View file

@ -0,0 +1,73 @@
// Fichier de configuration pour exposer le service Matrix
// avec une version TLS compatible avec Android 7
// Voir https://git.deuxfleurs.fr/Deuxfleurs/nixcfg/src/branch/main/cluster/prod/app/email/integration
job "im-android7" {
datacenters = ["scorpio", "neptune"]
type = "service"
priority = 100
group "rsa-ecc-proxy" {
network {
port "api_port" { static = 18008 }
// port "web_port" { to = 8043 }
}
task "api-proxy" {
driver = "docker"
config {
image = "alpine/socat:1.8.0.0"
readonly_rootfs = true
ports = [ "api_port" ]
network_mode = "host"
args = [
"openssl-listen:18008,reuseaddr,fork,verify=0,bind=0.0.0.0,cert=/var/secrets/rsa.crt,key=/var/secrets/rsa.key",
"tcp:synapse.service.prod.consul:8008",
]
volumes = [
"secrets/certs:/var/secrets"
]
}
template {
data = "{{ key \"secrets/chat/tls-tls-proxy/rsa.crt\" }}"
destination = "secrets/certs/rsa.crt"
}
template {
data = "{{ key \"secrets/chat/tls-tls-proxy/rsa.key\" }}"
destination = "secrets/certs/rsa.key"
}
resources {
cpu = 50
memory = 50
}
service {
name = "im-android7"
port = "api_port"
address_mode = "host"
tags = [
"rsa-ecc-proxy",
"(diplonat (tcp_port 18008))",
"d53-a im-android7.deuxfleurs.fr",
# ipv6 is commented for now as socat does not listen on ipv6 now
# "d53-aaaa im-android7.deuxfleurs.fr"
]
check {
type = "tcp"
port = "api_port"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
}
}
}

View file

@ -15,7 +15,7 @@ job "matrix" {
driver = "docker" driver = "docker"
config { config {
image = "particallydone/amd64_synapse:v60" image = "lxpz/amd64_synapse:v58"
network_mode = "host" network_mode = "host"
readonly_rootfs = true readonly_rootfs = true
ports = [ "api_port" ] ports = [ "api_port" ]
@ -101,7 +101,7 @@ job "matrix" {
driver = "docker" driver = "docker"
config { config {
image = "particallydone/amd64_synapse:v60" image = "lxpz/amd64_synapse:v58"
readonly_rootfs = true readonly_rootfs = true
command = "/usr/local/bin/matrix-s3-async" command = "/usr/local/bin/matrix-s3-async"
work_dir = "/tmp" work_dir = "/tmp"
@ -137,7 +137,7 @@ EOH
task "riotweb" { task "riotweb" {
driver = "docker" driver = "docker"
config { config {
image = "particallydone/amd64_elementweb:v36" image = "lxpz/amd64_elementweb:v35"
ports = [ "web_port" ] ports = [ "web_port" ]
volumes = [ volumes = [
"secrets/config.json:/srv/http/config.json" "secrets/config.json:/srv/http/config.json"
@ -190,7 +190,7 @@ EOH
driver = "docker" driver = "docker"
config { config {
image = "ghcr.io/matrix-org/sliding-sync:v0.99.16" image = "ghcr.io/matrix-org/sliding-sync:v0.99.12"
ports = [ "syncv3_api", "syncv3_metrics" ] ports = [ "syncv3_api", "syncv3_metrics" ]
} }

View file

@ -26,16 +26,6 @@ scrape_configs:
cert_file: /etc/prometheus/consul-client.crt cert_file: /etc/prometheus/consul-client.crt
key_file: /etc/prometheus/consul-client.key key_file: /etc/prometheus/consul-client.key
- job_name: 'jitsi-videobridge'
consul_sd_configs:
- server: 'https://localhost:8501'
services:
- 'management-video-jitsi'
tls_config:
ca_file: /etc/prometheus/consul-ca.crt
cert_file: /etc/prometheus/consul-client.crt
key_file: /etc/prometheus/consul-client.key
- job_name: 'garage' - job_name: 'garage'
authorization: authorization:
type: Bearer type: Bearer

View file

@ -19,7 +19,7 @@ job "telemetry-service" {
driver = "docker" driver = "docker"
config { config {
image = "litestream/litestream:0.3.13" image = "litestream/litestream:0.3.9"
args = [ args = [
"restore", "-config", "/etc/litestream.yml", "/ephemeral/grafana.db" "restore", "-config", "/etc/litestream.yml", "/ephemeral/grafana.db"
] ]
@ -45,7 +45,7 @@ job "telemetry-service" {
task "grafana" { task "grafana" {
driver = "docker" driver = "docker"
config { config {
image = "grafana/grafana:10.3.4" image = "grafana/grafana:10.0.3"
network_mode = "host" network_mode = "host"
ports = [ "grafana" ] ports = [ "grafana" ]
volumes = [ volumes = [
@ -108,7 +108,7 @@ EOH
task "replicate-db" { task "replicate-db" {
driver = "docker" driver = "docker"
config { config {
image = "litestream/litestream:0.3.13" image = "litestream/litestream:0.3.7"
args = [ args = [
"replicate", "-config", "/etc/litestream.yml" "replicate", "-config", "/etc/litestream.yml"
] ]

View file

@ -20,7 +20,7 @@ job "telemetry-storage" {
task "prometheus" { task "prometheus" {
driver = "docker" driver = "docker"
config { config {
image = "prom/prometheus:v2.50.1" image = "prom/prometheus:v2.46.0"
network_mode = "host" network_mode = "host"
ports = [ "prometheus" ] ports = [ "prometheus" ]
args = [ args = [
@ -70,8 +70,7 @@ job "telemetry-storage" {
} }
resources { resources {
memory = 1500 memory = 1000
memory_max = 4000
cpu = 1000 cpu = 1000
} }

View file

@ -1,5 +1,5 @@
job "telemetry-system" { job "telemetry-system" {
datacenters = ["neptune", "scorpio", "bespin", "corrin"] datacenters = ["neptune", "scorpio", "bespin"]
type = "system" type = "system"
priority = "100" priority = "100"
@ -12,7 +12,7 @@ job "telemetry-system" {
driver = "docker" driver = "docker"
config { config {
image = "quay.io/prometheus/node-exporter:v1.7.0" image = "quay.io/prometheus/node-exporter:v1.6.1"
network_mode = "host" network_mode = "host"
volumes = [ volumes = [
"/:/host:ro,rslave" "/:/host:ro,rslave"

View file

@ -1,160 +0,0 @@
job "woodpecker-ci" {
datacenters = ["neptune", "scorpio"]
type = "service"
group "server" {
count = 1
network {
port "web_port" {
static = 14080
to = 14080
}
port "grpc_port" {
static = 14090
to = 14090
}
port "grpc_tls_port" {
static = 14453
to = 14453
}
}
task "server" {
driver = "docker"
config {
image = "woodpeckerci/woodpecker-server:v2.7.1"
ports = [ "web_port", "grpc_port" ]
network_mode = "host"
}
template {
data = <<EOH
WOODPECKER_OPEN=true
WOODPECKER_ORGS=Deuxfleurs
WOODPECKER_ADMIN=lx
WOODPECKER_HOST=https://woodpecker.deuxfleurs.fr
WOODPECKER_AGENT_SECRET={{ key "secrets/woodpecker-ci/agent_secret" }}
# secret encryption is broken in woodpecker currently
# WOODPECKER_ENCRYPTION_KEY={{ key "secrets/woodpecker-ci/secrets_encryption_key" }}
WOODPECKER_SERVER_ADDR=[::]:14080
WOODPECKER_GRPC_ADDR=[::]:14090
# WOODPECKER_GRPC_SECRET={{ key "secrets/woodpecker-ci/grpc_secret" }}
WOODPECKER_DATABASE_DRIVER=postgres
WOODPECKER_DATABASE_DATASOURCE=postgres://woodpecker:{{ key "secrets/woodpecker-ci/db_password" | trimSpace }}@{{ env "meta.site" }}.psql-proxy.service.prod.consul:5432/woodpecker?sslmode=disable
WOODPECKER_GITEA=true
WOODPECKER_GITEA_URL=https://git.deuxfleurs.fr
WOODPECKER_GITEA_CLIENT={{ key "secrets/woodpecker-ci/oauth_client_id" }}
WOODPECKER_GITEA_SECRET={{ key "secrets/woodpecker-ci/oauth_client_secret" }}
WOODPECKER_LOG_LEVEL=debug
WOODPECKER_ENVIRONMENT=NIX_REMOTE:daemon
EOH
destination = "secrets/env"
env = true
}
resources {
cpu = 100
memory = 200
}
service {
name = "woodpecker"
tags = [
"woodpecker",
"tricot woodpecker.deuxfleurs.fr",
"d53-cname woodpecker.deuxfleurs.fr",
]
port = "web_port"
address_mode = "host"
/*
check {
type = "http"
protocol = "http"
port = "web_port"
path = "/"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "600s"
ignore_warnings = false
}
}
*/
}
service {
name = "woodpecker-grpc"
tags = [
"woodpecker-grpc",
]
port = "grpc_port"
address_mode = "host"
}
}
task "grpc_tls" {
driver = "docker"
config {
image = "nginx:1.25.3"
ports = [ "grpc_tls_port" ]
volumes = [
"secrets/ssl/certs:/etc/ssl/certs",
"secrets/ssl/private:/etc/ssl/private",
"secrets/conf/:/etc/nginx/",
]
network_mode = "host"
}
template {
data = <<EOH
events {}
http {
server {
listen 0.0.0.0:14453 ssl;
listen [::]:14453 ssl;
http2 on;
server_name woodpecker.deuxfleurs.fr;
resolver 127.0.0.1 valid=30s;
ssl_certificate "/etc/ssl/certs/woodpecker.cert";
ssl_certificate_key "/etc/ssl/certs/woodpecker.key";
location / {
grpc_pass grpc://woodpecker-grpc.service.prod.consul:14090;
}
}
}
EOH
destination = "secrets/conf/nginx.conf"
}
template {
data = "{{ with $d := key \"tricot/certs/woodpecker.deuxfleurs.fr\" | parseJSON }}{{ $d.key_pem }}{{ end }}"
destination = "secrets/ssl/certs/woodpecker.key"
}
template {
data = "{{ with $d := key \"tricot/certs/woodpecker.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}"
destination = "secrets/ssl/certs/woodpecker.cert"
}
service {
name = "woodpecker-grpc-tls"
tags = [
"woodpecker-grpc-tls",
"d53-a woodpecker-grpc.deuxfleurs.fr",
"d53-aaaa woodpecker-grpc.deuxfleurs.fr",
"(diplonat (tcp_port 14453))"
]
port = "grpc_tls_port"
address_mode = "host"
}
}
}
}

View file

@ -1,54 +0,0 @@
## Install Debian
We recommend Debian Bullseye
## Install Docker CE from docker.io
Do not use the docker engine shipped by Debian
Doc:
- https://docs.docker.com/engine/install/debian/
- https://docs.docker.com/compose/install/
On a fresh install, as root:
```bash
# Remove all pre-existing packages
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do apt-get remove $pkg; done
# Add Docker's official GPG key:
apt-get update
apt-get install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
# Install Docker
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
## Install the runner
```bash
wget https://git.deuxfleurs.fr/Deuxfleurs/nixcfg/raw/branch/main/cluster/prod/app/woodpecker-ci/integration/nix.conf
wget https://git.deuxfleurs.fr/Deuxfleurs/nixcfg/raw/branch/main/cluster/prod/app/woodpecker-ci/integration/docker-compose.yml
```
Create a new Agent for your runner in the Woodpecker admin, and copy the agent secret value.
Edit `docker-compose.yml` and insert your agent secret as the value for WOODPECKER_AGENT_SECRET.
Update other values including hostname and max workflows for your runner.
```bash
COMPOSE_PROJECT_NAME=woodpecker docker-compose up -d
```
That's all folks.

View file

@ -1,33 +0,0 @@
version: '3.4'
services:
nix-daemon:
image: nixpkgs/nix:nixos-22.05
restart: always
command: nix-daemon
privileged: true
volumes:
- "nix:/nix"
- "./nix.conf:/etc/nix/nix.conf:ro"
woodpecker-runner:
image: woodpeckerci/woodpecker-agent:v2.4.1
restart: always
environment:
# -- change these for each agent
- WOODPECKER_HOSTNAME=i_forgot_to_change_my_runner_name
- WOODPECKER_AGENT_SECRET=xxxx
- WOODPECKER_MAX_WORKFLOWS=4
# -- if not using COMPOSE_PROJECT_NAME=woodpecker, change name of volume to mount
- WOODPECKER_BACKEND_DOCKER_VOLUMES=woodpecker_nix:/nix:ro
# -- should not need change
- WOODPECKER_SERVER=woodpecker-grpc.deuxfleurs.fr:14453
- WOODPECKER_HEALTHCHECK=false
- WOODPECKER_GRPC_SECURE=true
- WOODPECKER_LOG_LEVEL=info
- WOODPECKER_DEBUG_PRETTY=true
- WOODPECKER_ENVIRONMENT=NIX_REMOTE:daemon
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
volumes:
nix:

View file

@ -11,21 +11,20 @@
siteName = "neptune"; siteName = "neptune";
publicKey = "VvXT0fPDfWsHxumZqVShpS33dJQAdpJ1E79ZbCBJP34="; publicKey = "VvXT0fPDfWsHxumZqVShpS33dJQAdpJ1E79ZbCBJP34=";
address = "10.83.1.1"; address = "10.83.1.1";
endpoint = "82.67.87.112:33731"; endpoint = "77.207.15.215:33731";
}; };
"courgette" = { "courgette" = {
siteName = "neptune"; siteName = "neptune";
publicKey = "goTkBJGmzrGDOAjUcdH9G0JekipqSMoaYQdB6IHnzi0="; publicKey = "goTkBJGmzrGDOAjUcdH9G0JekipqSMoaYQdB6IHnzi0=";
address = "10.83.1.2"; address = "10.83.1.2";
endpoint = "82.67.87.112:33732"; endpoint = "77.207.15.215:33732";
}; };
"celeri" = { "celeri" = {
siteName = "neptune"; siteName = "neptune";
publicKey = "oZDAb8LoLW87ktUHyFFec0VaIar97bqq47mGbdVqJ0U="; publicKey = "oZDAb8LoLW87ktUHyFFec0VaIar97bqq47mGbdVqJ0U=";
address = "10.83.1.3"; address = "10.83.1.3";
endpoint = "82.67.87.112:33733"; endpoint = "77.207.15.215:33733";
}; };
/*
"dahlia" = { "dahlia" = {
siteName = "orion"; siteName = "orion";
publicKey = "EtRoWBYCdjqgXX0L+uWLg8KxNfIK8k9OTh30tL19bXU="; publicKey = "EtRoWBYCdjqgXX0L+uWLg8KxNfIK8k9OTh30tL19bXU=";
@ -44,24 +43,23 @@
address = "10.83.2.3"; address = "10.83.2.3";
endpoint = "82.66.80.201:33733"; endpoint = "82.66.80.201:33733";
}; };
*/
"df-ykl" = { "df-ykl" = {
siteName = "bespin"; siteName = "bespin";
publicKey = "bIjxey/VhBgVrLa0FxN/KISOt2XFmQeSh1MPivUq9gg="; publicKey = "bIjxey/VhBgVrLa0FxN/KISOt2XFmQeSh1MPivUq9gg=";
address = "10.83.3.1"; address = "10.83.3.1";
endpoint = "109.130.116.21:33731"; endpoint = "109.136.55.235:33731";
}; };
"df-ymf" = { "df-ymf" = {
siteName = "bespin"; siteName = "bespin";
publicKey = "pUIKv8UBl586O7DBrHBsb9BgNU7WlYQ2r2RSNkD+JAQ="; publicKey = "pUIKv8UBl586O7DBrHBsb9BgNU7WlYQ2r2RSNkD+JAQ=";
address = "10.83.3.2"; address = "10.83.3.2";
endpoint = "109.130.116.21:33732"; endpoint = "109.136.55.235:33732";
}; };
"df-ymk" = { "df-ymk" = {
siteName = "bespin"; siteName = "bespin";
publicKey = "VBmpo15iIJP7250NAsF+ryhZc3j+8TZFnE1Djvn5TXI="; publicKey = "VBmpo15iIJP7250NAsF+ryhZc3j+8TZFnE1Djvn5TXI=";
address = "10.83.3.3"; address = "10.83.3.3";
endpoint = "109.130.116.21:33733"; endpoint = "109.136.55.235:33733";
}; };
"abricot" = { "abricot" = {
siteName = "scorpio"; siteName = "scorpio";
@ -75,42 +73,8 @@
address = "10.83.4.2"; address = "10.83.4.2";
endpoint = "82.65.41.110:33742"; endpoint = "82.65.41.110:33742";
}; };
"onion" = {
siteName = "dathomir";
publicKey = "gpeqalqAUaYlMuebv3glQeZyE64+OpkyIHFhfStJQA4=";
address = "10.83.5.1";
endpoint = "82.64.238.84:33740";
};
"oseille" = {
siteName = "dathomir";
publicKey = "T87GzAQt02i00iOMbEm7McA/VL9OBrG/kCrgoNh5MmY=";
address = "10.83.5.2";
endpoint = "82.64.238.84:33741";
};
"io" = {
siteName = "dathomir";
publicKey = "3+VvWJtABOAd6zUCMROhqGbNtkQRtoIkVmYn0M81jQw=";
address = "10.83.5.3";
endpoint = "82.64.238.84:33742";
};
"ortie" = {
siteName = "dathomir";
publicKey = "tbx2mvt3TN3Xd+ermwwZ6it80VWT5949cKH9BRFgvzE=";
address = "10.83.5.4";
endpoint = "82.64.238.84:33743";
};
"pamplemousse" = {
siteName = "corrin";
publicKey = "6y5GrNXEql12AObuSfOHGxxUKpdlcyapu+juLYOEBhc=";
address = "10.83.6.1";
endpoint = "45.81.62.36:33731";
};
}; };
# Pin Nomad version
services.nomad.package = pkgs.nomad_1_6;
nixpkgs.config.allowUnfree = true; # Accept nomad's BSL license
# Bootstrap IPs for Consul cluster, # Bootstrap IPs for Consul cluster,
# these are IPs on the Wireguard overlay # these are IPs on the Wireguard overlay
services.consul.extraConfig.retry_join = [ services.consul.extraConfig.retry_join = [
@ -154,19 +118,6 @@
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEve02acr522psrPxeElkwIPw2pc6QWtsUVZoaigqwZZ" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEve02acr522psrPxeElkwIPw2pc6QWtsUVZoaigqwZZ"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/h+rxR2o+vN0hUWQPdpO7YY9aaKxO3ZRnUh9QiKBE7" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/h+rxR2o+vN0hUWQPdpO7YY9aaKxO3ZRnUh9QiKBE7"
]; ];
armael = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJOoPghSM72AVp1zATgQzeLkuoGuP9uUTTAtwliyWoix"
];
marion = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKzOhSTEOudBWCHi5wHc6MP0xjJJhuIDZEcx+hP6kz9N"
];
darkgallium = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJX0A2P59or83EKhh32o8XumGz0ToTEsoq89hMbMtr7h"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB540H9kn+Ocs4Wjc1Y3f3OkHFYEqc5IM/FiCyoVVoh3"
];
kokakiwi = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPTsEgcOtb2bij+Ih8eg8ZqO7d3IMiWykv6deMzlSSS kokakiwi@kira"
];
}; };
# For Garage external communication # For Garage external communication

View file

@ -9,9 +9,3 @@ concombre.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL3N0QOFNGkC
courgette.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPCXJeo6yeQeTN7D7OZwLd8zbyU1jWywlhQ29yyk7x+G courgette.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPCXJeo6yeQeTN7D7OZwLd8zbyU1jWywlhQ29yyk7x+G
abricot.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPhHUQtc5lukPMFkiWf/sTgaUpwNFXHCJoQKu4ooRFy+ abricot.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPhHUQtc5lukPMFkiWf/sTgaUpwNFXHCJoQKu4ooRFy+
ananas.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHs0zAyBy70oyV56qaMaMAKR7VjEDnsm5LEyZJbM95BL ananas.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHs0zAyBy70oyV56qaMaMAKR7VjEDnsm5LEyZJbM95BL
onion.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINjBQ67fxwuDDzRPveTko/Sgf0cev3tIvlr3CfAmhF0C
oseille.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAgQdQ5UVFFn+DXN90ut9+V7NtEopQJnES3r8soKTZW4
io.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIvgCJ7Jew7ou1RZuaT41Sd+ucZAgxUwtdieqNqoC3+T
ortie.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMqtfIPLk8a5tM6Upj7GQwlIS16nBPrZYVXE2FVlO2Yn
pamplemousse.machine.deuxfleurs.fr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAI0M5qny9yQ6LNzWqPfSlOWwTYpvxQtuSpFiOb6aVtA
2001:912:1ac0:2200::201 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAI0M5qny9yQ6LNzWqPfSlOWwTYpvxQtuSpFiOb6aVtA

View file

@ -1,11 +0,0 @@
{ ... }:
{
boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/sda";
services.openssh.ports = [ 22 33603 ];
deuxfleurs.hostName = "io";
deuxfleurs.staticIPv4.address = "192.168.1.36";
deuxfleurs.staticIPv6.address = "2a01:e0a:5e4:1d0:52e5:49ff:fe5c:5f35";
}

View file

@ -1 +0,0 @@
../site/dathomir.nix

View file

@ -1,12 +0,0 @@
{ ... }:
{
boot.loader.systemd-boot.enable = true;
boot.loader.timeout = 20;
boot.loader.efi.canTouchEfiVariables = true;
services.openssh.ports = [ 22 33601 ];
deuxfleurs.hostName = "onion";
deuxfleurs.staticIPv4.address = "192.168.1.34";
deuxfleurs.staticIPv6.address = "2a01:e0a:5e4:1d0:223:24ff:feb0:e866";
}

View file

@ -1 +0,0 @@
../site/dathomir.nix

View file

@ -1,12 +0,0 @@
{ ... }:
{
boot.loader.systemd-boot.enable = true;
boot.loader.timeout = 20;
boot.loader.efi.canTouchEfiVariables = true;
services.openssh.ports = [ 22 33604 ];
deuxfleurs.hostName = "ortie";
deuxfleurs.staticIPv4.address = "192.168.1.37";
deuxfleurs.staticIPv6.address = "2a01:e0a:5e4:1d0:223:24ff:feb0:1b9";
}

View file

@ -1 +0,0 @@
../site/dathomir.nix

View file

@ -1,12 +0,0 @@
{ ... }:
{
boot.loader.systemd-boot.enable = true;
boot.loader.timeout = 20;
boot.loader.efi.canTouchEfiVariables = true;
services.openssh.ports = [ 22 33602 ];
deuxfleurs.hostName = "oseille";
deuxfleurs.staticIPv4.address = "192.168.1.35";
deuxfleurs.staticIPv6.address = "2a01:e0a:5e4:1d0:223:24ff:feaf:f90b";
}

View file

@ -1 +0,0 @@
../site/dathomir.nix

View file

@ -1,14 +0,0 @@
# Configuration file local to this node
{ config, pkgs, ... }:
{
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.timeout = 5;
boot.loader.efi.canTouchEfiVariables = true;
deuxfleurs.hostName = "pamplemousse";
deuxfleurs.staticIPv4.address = "192.168.5.201";
deuxfleurs.staticIPv6.address = "2001:912:1ac0:2200::201";
}

View file

@ -1 +0,0 @@
../site/corrin.nix

View file

@ -26,19 +26,73 @@ curl -vv -X PUT http://localhost:8500/v1/catalog/register -H "Content-Type: app
{ {
"Datacenter": "prod", "Datacenter": "prod",
"Node": "spoutnik", "Node": "spoutnik",
"Address": "192.168.1.51", "Address": "192.168.1.60",
"NodeMeta": { "NodeMeta": {
"site": "scorpio", "site": "scorpio",
"cname_target": "scorpio.site.deuxfleurs.fr." "cname_target": "scorpio.site.deuxfleurs.fr."
}, },
"Service": { "Service": {
"Service": "adrien-nginx", "Service": "adrien-nginx",
"Tags": [ "Tags": ["tricot-https *.luxeylab.net"],
"tricot-https *.luxeylab.net", "Address": "192.168.1.60",
"tricot-https *.zinz.dev"
],
"Address": "192.168.1.51",
"Port": 443 "Port": 443
} }
} }
EOF EOF
# Orsay (neptune): Alex's personnal stuff
curl -vv -X PUT http://localhost:8500/v1/catalog/register -H "Content-Type: application/json" --data @- <<EOF
{
"Datacenter": "prod",
"Node": "lindy",
"Address": "192.168.1.184",
"NodeMeta": {
"site": "neptune",
"cname_target": "neptune.site.deuxfleurs.fr."
},
"Service": {
"Service": "lx-apimdev",
"Tags": ["tricot apimdev.adnab.me"],
"Address": "192.168.1.184",
"Port": 8910
}
}
EOF
curl -vv -X PUT http://localhost:8500/v1/catalog/register -H "Content-Type: application/json" --data @- <<EOF
{
"Datacenter": "prod",
"Node": "lindy",
"Address": "192.168.1.184",
"NodeMeta": {
"site": "neptune",
"cname_target": "neptune.site.deuxfleurs.fr."
},
"Service": {
"Service": "lx-apimtest",
"Tags": ["tricot apimtest.adnab.me"],
"Address": "192.168.1.184",
"Port": 8920
}
}
EOF
curl -vv -X PUT http://localhost:8500/v1/catalog/register -H "Content-Type: application/json" --data @- <<EOF
{
"Datacenter": "prod",
"Node": "www.isomorphis.me",
"Address": "192.168.1.24",
"NodeMeta": {
"site": "neptune",
"cname_target": "neptune.site.deuxfleurs.fr."
},
"Service": {
"Service": "isomorphis.me-web",
"Tags": ["tricot *.isomorphis.me"],
"Address": "192.168.1.24",
"Port": 5000
}
}
EOF

View file

@ -1,8 +0,0 @@
{ config, pkgs, ... }:
{
deuxfleurs.siteName = "corrin";
deuxfleurs.staticIPv4.defaultGateway = "192.168.5.1";
deuxfleurs.cnameTarget = "corrin.site.deuxfleurs.fr.";
deuxfleurs.publicIPv4 = "45.81.62.36";
}

View file

@ -1,7 +0,0 @@
{ ... }:
{
deuxfleurs.siteName = "dathomir";
deuxfleurs.cnameTarget = "dathomir.site.deuxfleurs.fr";
deuxfleurs.publicIPv4 = "82.64.238.84";
deuxfleurs.staticIPv4.defaultGateway = "192.168.1.1";
}

View file

@ -2,7 +2,7 @@
{ {
deuxfleurs.siteName = "neptune"; deuxfleurs.siteName = "neptune";
deuxfleurs.staticIPv4.defaultGateway = "192.168.1.254"; deuxfleurs.staticIPv4.defaultGateway = "192.168.1.1";
deuxfleurs.cnameTarget = "neptune.site.deuxfleurs.fr."; deuxfleurs.cnameTarget = "neptune.site.deuxfleurs.fr.";
deuxfleurs.publicIPv4 = "82.67.87.112"; deuxfleurs.publicIPv4 = "77.207.15.215";
} }

View file

@ -1,49 +1,35 @@
UserKnownHostsFile ./cluster/prod/known_hosts UserKnownHostsFile ./cluster/prod/known_hosts
Host concombre Host concombre
HostName concombre.machine.deuxfleurs.fr HostName concombre.machine.deuxfleurs.fr
Host courgette Host courgette
HostName courgette.machine.deuxfleurs.fr HostName courgette.machine.deuxfleurs.fr
Host celeri Host celeri
HostName celeri.machine.deuxfleurs.fr HostName celeri.machine.deuxfleurs.fr
Host dahlia Host dahlia
HostName dahlia.machine.deuxfleurs.fr HostName dahlia.machine.deuxfleurs.fr
Host diplotaxis Host diplotaxis
HostName diplotaxis.machine.deuxfleurs.fr HostName diplotaxis.machine.deuxfleurs.fr
Host doradille Host doradille
HostName doradille.machine.deuxfleurs.fr HostName doradille.machine.deuxfleurs.fr
Host df-ykl Host df-ykl
HostName df-ykl.machine.deuxfleurs.fr HostName df-ykl.machine.deuxfleurs.fr
Host df-ymf Host df-ymf
HostName df-ymf.machine.deuxfleurs.fr HostName df-ymf.machine.deuxfleurs.fr
Host df-ymk Host df-ymk
HostName df-ymk.machine.deuxfleurs.fr HostName df-ymk.machine.deuxfleurs.fr
Host abricot Host abricot
HostName abricot.machine.deuxfleurs.fr HostName abricot.machine.deuxfleurs.fr
Host ananas Host ananas
HostName ananas.machine.deuxfleurs.fr HostName ananas.machine.deuxfleurs.fr
Host onion
HostName onion.machine.deuxfleurs.fr
Host oseille
HostName oseille.machine.deuxfleurs.fr
Host io
HostName io.machine.deuxfleurs.fr
Host ortie
HostName ortie.machine.deuxfleurs.fr
Host pamplemousse
HostName 2001:912:1ac0:2200::201

View file

@ -1,5 +1,5 @@
job "albatros" { job "albatros" {
datacenters = ["neptune", "dathomir", "corrin", "bespin"] datacenters = ["neptune", "jupiter", "corrin", "bespin"]
type = "service" type = "service"
priority = 90 priority = 90

View file

@ -2,7 +2,7 @@ job "builder" {
namespace = "ci" namespace = "ci"
type = "batch" type = "batch"
datacenters = ["neptune", "dathomir", "corrin", "bespin"] datacenters = ["neptune", "jupiter", "corrin", "bespin"]
priority = 100 priority = 100
parameterized { parameterized {

View file

@ -1,100 +0,0 @@
job "core-bottin" {
datacenters = ["neptune", "jupiter", "corrin", "bespin"]
type = "system"
priority = 90
update {
max_parallel = 1
stagger = "1m"
}
group "bottin" {
constraint {
distinct_property = "${meta.site}"
value = "1"
}
network {
port "ldap_port" {
static = 389
to = 389
}
}
task "bottin" {
driver = "docker"
config {
image = "dxflrs/bottin:7h18i30cckckaahv87d3c86pn4a7q41z"
network_mode = "host"
readonly_rootfs = true
ports = [ "ldap_port" ]
volumes = [
"secrets/config.json:/config.json",
"secrets:/etc/bottin",
]
}
restart {
interval = "5m"
attempts = 10
delay = "15s"
mode = "delay"
}
resources {
memory = 100
memory_max = 200
}
template {
data = file("../config/bottin/config.json.tpl")
destination = "secrets/config.json"
}
template {
data = "{{ key \"secrets/consul/consul.crt\" }}"
destination = "secrets/consul.crt"
}
template {
data = "{{ key \"secrets/consul/consul-client.crt\" }}"
destination = "secrets/consul-client.crt"
}
template {
data = "{{ key \"secrets/consul/consul-client.key\" }}"
destination = "secrets/consul-client.key"
}
template {
data = <<EOH
CONSUL_HTTP_ADDR=https://consul.service.staging.consul:8501
CONSUL_HTTP_SSL=true
CONSUL_CACERT=/etc/bottin/consul.crt
CONSUL_CLIENT_CERT=/etc/bottin/consul-client.crt
CONSUL_CLIENT_KEY=/etc/bottin/consul-client.key
EOH
destination = "secrets/env"
env = true
}
service {
tags = [ "${meta.site}" ]
port = "ldap_port"
address_mode = "host"
name = "bottin"
check {
type = "tcp"
port = "ldap_port"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
}
}
}

View file

@ -1,5 +1,5 @@
job "core-d53" { job "core-d53" {
datacenters = ["neptune", "dathomir", "corrin", "bespin"] datacenters = ["neptune", "jupiter", "corrin", "bespin"]
type = "service" type = "service"
priority = 90 priority = 90

View file

@ -1,5 +1,5 @@
job "core-diplonat" { job "core-diplonat" {
datacenters = ["neptune", "dathomir", "corrin", "bespin"] datacenters = ["neptune", "jupiter", "corrin", "bespin"]
type = "system" type = "system"
priority = 90 priority = 90

View file

@ -1,5 +1,5 @@
job "core-tricot" { job "core-tricot" {
datacenters = ["neptune", "dathomir", "corrin", "bespin"] datacenters = ["neptune", "jupiter", "corrin", "bespin"]
type = "system" type = "system"
priority = 90 priority = 90
@ -21,25 +21,20 @@ job "core-tricot" {
} }
task "server" { task "server" {
driver = "docker" driver = "nix2"
config { config {
image = "armael/tricot:8sa24l6pxdppb5gq0nnj9kvcl9mijliy-block_user_agent" packages = [
network_mode = "host" "git+https://git.deuxfleurs.fr/Deuxfleurs/tricot.git?ref=redirect&rev=b76b6dcbcc47ebc61848389a6b0d5d4e8d8cde48"
readonly_rootfs = true
ports = [ "http_port", "https_port" ]
volumes = [
"secrets:/etc/tricot",
] ]
ulimit { command = "tricot"
nofile = "65535:65535" # cap_add = [ "net_bind_service" ] # this doesn't work for whatever reason, so we need to put user = "root" instead
}
} }
user = "root"
resources { resources {
cpu = 500 cpu = 500
memory = 200 memory = 200
memory_max = 500
} }
restart { restart {
@ -51,17 +46,17 @@ job "core-tricot" {
template { template {
data = "{{ key \"secrets/consul/consul-ca.crt\" }}" data = "{{ key \"secrets/consul/consul-ca.crt\" }}"
destination = "secrets/consul-ca.crt" destination = "etc/tricot/consul-ca.crt"
} }
template { template {
data = "{{ key \"secrets/consul/consul-client.crt\" }}" data = "{{ key \"secrets/consul/consul-client.crt\" }}"
destination = "secrets/consul-client.crt" destination = "etc/tricot/consul-client.crt"
} }
template { template {
data = "{{ key \"secrets/consul/consul-client.key\" }}" data = "{{ key \"secrets/consul/consul-client.key\" }}"
destination = "secrets/consul-client.key" destination = "etc/tricot/consul-client.key"
} }
template { template {
@ -76,7 +71,6 @@ TRICOT_CONSUL_CLIENT_KEY=/etc/tricot/consul-client.key
TRICOT_HTTP_BIND_ADDR=[::]:80 TRICOT_HTTP_BIND_ADDR=[::]:80
TRICOT_HTTPS_BIND_ADDR=[::]:443 TRICOT_HTTPS_BIND_ADDR=[::]:443
TRICOT_METRICS_BIND_ADDR=[::]:9334 TRICOT_METRICS_BIND_ADDR=[::]:9334
TRICOT_WARMUP_CERT_MEMORY_STORE=true
RUST_LOG=tricot=debug RUST_LOG=tricot=debug
RUST_BACKTRACE=1 RUST_BACKTRACE=1
EOH EOH
@ -88,6 +82,9 @@ EOH
name = "tricot-http" name = "tricot-http"
port = "http_port" port = "http_port"
tags = [ tags = [
"d53-aaaa ${attr.unique.hostname}.machine.staging.deuxfleurs.org",
"d53-aaaa ${meta.site}.site.staging.deuxfleurs.org",
"d53-aaaa staging.deuxfleurs.org",
"(diplonat (tcp_port 80))" "(diplonat (tcp_port 80))"
] ]
address_mode = "host" address_mode = "host"
@ -97,10 +94,7 @@ EOH
name = "tricot-https" name = "tricot-https"
port = "https_port" port = "https_port"
tags = [ tags = [
"(diplonat (tcp_port 443))", "(diplonat (tcp_port 443))"
"d53-aaaa ${attr.unique.hostname}.machine.staging.deuxfleurs.org",
"d53-aaaa ${meta.site}.site.staging.deuxfleurs.org",
"d53-aaaa staging.deuxfleurs.org"
] ]
address_mode = "host" address_mode = "host"
} }

View file

@ -1,8 +1,3 @@
[secrets."directory/ldap_base_dn"]
type = 'user'
description = 'LDAP base DN for everything'
example = 'dc=example,dc=com'
[secrets."d53/gandi_api_key"] [secrets."d53/gandi_api_key"]
type = 'user' type = 'user'
description = 'Gandi API key' description = 'Gandi API key'

View file

@ -1,15 +1,12 @@
{ {
"http_bind_addr": ":9991", "http_bind_addr": ":9991",
"ldap_server_addr": "ldap://{{ env "meta.site" }}.bottin.service.staging.consul:389", "ldap_server_addr": "ldap://bottin.service.staging.consul:389",
"base_dn": "{{ key "secrets/directory/ldap_base_dn" }}", "base_dn": "{{ key "secrets/directory/ldap_base_dn" }}",
"user_base_dn": "ou=users,{{ key "secrets/directory/ldap_base_dn" }}", "user_base_dn": "ou=users,{{ key "secrets/directory/ldap_base_dn" }}",
"user_name_attr": "cn", "user_name_attr": "cn",
"group_base_dn": "ou=groups,{{ key "secrets/directory/ldap_base_dn" }}", "group_base_dn": "ou=groups,{{ key "secrets/directory/ldap_base_dn" }}",
"group_name_attr": "cn", "group_name_attr": "cn",
"mailing_list_base_dn": "ou=mailing_lists,ou=groups,{{ key "secrets/directory/ldap_base_dn" }}",
"mailing_list_name_attr": "cn",
"mailing_list_guest_user_base_dn": "ou=guests,ou=users,{{ key "secrets/directory/ldap_base_dn" }}",
"invitation_base_dn": "ou=invitations,{{ key "secrets/directory/ldap_base_dn" }}", "invitation_base_dn": "ou=invitations,{{ key "secrets/directory/ldap_base_dn" }}",
"invitation_name_attr": "cn", "invitation_name_attr": "cn",

View file

@ -0,0 +1,133 @@
job "directory" {
datacenters = ["neptune", "jupiter", "corrin", "bespin"]
type = "service"
priority = 90
constraint {
attribute = "${attr.cpu.arch}"
value = "amd64"
}
group "bottin" {
count = 1
network {
port "ldap_port" {
static = 389
}
}
task "bottin" {
driver = "nix2"
config {
packages = [
"git+https://git.deuxfleurs.fr/Deuxfleurs/bottin.git?ref=main&rev=9cab98d2cee386ece54b000bbdf2346da8b55eed"
]
command = "bottin"
}
user = "root" # needed to bind port 389
resources {
memory = 100
}
template {
data = file("../config/bottin/config.json.tpl")
destination = "config.json"
}
template {
data = "{{ key \"secrets/consul/consul-ca.crt\" }}"
destination = "etc/bottin/consul-ca.crt"
}
template {
data = "{{ key \"secrets/consul/consul-client.crt\" }}"
destination = "etc/bottin/consul-client.crt"
}
template {
data = "{{ key \"secrets/consul/consul-client.key\" }}"
destination = "etc/bottin/consul-client.key"
}
template {
data = <<EOH
CONSUL_HTTP_ADDR=https://localhost:8501
CONSUL_HTTP_SSL=true
CONSUL_CACERT=/etc/bottin/consul-ca.crt
CONSUL_CLIENT_CERT=/etc/bottin/consul-client.crt
CONSUL_CLIENT_KEY=/etc/bottin/consul-client.key
EOH
destination = "secrets/env"
env = true
}
service {
tags = ["bottin"]
port = "ldap_port"
name = "bottin"
check {
type = "tcp"
port = "ldap_port"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
}
}
group "guichet" {
count = 1
network {
port "web_port" { static = 9991 }
}
task "guichet" {
driver = "nix2"
config {
packages = [
"git+https://git.deuxfleurs.fr/Deuxfleurs/guichet.git?ref=main&rev=10bdee10cf6947ec6dd0ba5040d7274d6c3316a7"
]
command = "guichet"
}
template {
data = file("../config/guichet/config.json.tpl")
destination = "config.json"
}
resources {
memory = 200
}
service {
name = "guichet"
tags = [
"guichet",
"tricot guichet.staging.deuxfleurs.org",
"d53-cname guichet.staging.deuxfleurs.org",
]
port = "web_port"
check {
type = "tcp"
port = "web_port"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
}
}
}

View file

@ -1,51 +1,51 @@
# General configuration [secrets."directory/ldap_base_dn"]
[secrets."directory/guichet/web_hostname"]
type = 'user' type = 'user'
description = 'Public hostname from which Guichet is accessible via HTTP (e.g. guichet.example.com)' description = 'LDAP base DN for everything'
example = 'dc=example,dc=com'
# Mailing configuration
[secrets."directory/guichet/smtp_user"] [secrets."directory/guichet/smtp_user"]
type = 'user' type = 'user'
description = 'SMTP username' description = 'SMTP username'
[secrets."directory/guichet/s3_access_key"]
type = 'user'
description = 'Garage access key for Guichet profile pictures'
[secrets."directory/guichet/s3_endpoint"]
type = 'user'
description = 'S3 endpoint URL'
[secrets."directory/guichet/s3_region"]
type = 'user'
description = 'S3 region'
[secrets."directory/guichet/smtp_pass"] [secrets."directory/guichet/smtp_pass"]
type = 'user' type = 'user'
description = 'SMTP password' description = 'SMTP password'
[secrets."directory/guichet/web_hostname"]
type = 'user'
description = 'Public hostname from which Guichet is accessible via HTTP'
example = 'guichet.example.com'
[secrets."directory/guichet/s3_bucket"]
type = 'user'
description = 'S3 bucket in which to store data files (such as profile pictures)'
[secrets."directory/guichet/smtp_server"] [secrets."directory/guichet/smtp_server"]
type = 'user' type = 'user'
description = 'SMTP server address (hostname:port)' description = 'SMTP server address (hostname:port)'
[secrets."directory/guichet/s3_secret_key"]
type = 'user'
description = 'Garage secret key for Guichet profile pictures'
[secrets."directory/guichet/mail_from"] [secrets."directory/guichet/mail_from"]
type = 'user' type = 'user'
description = 'E-mail address from which to send welcome emails to new users' description = 'E-mail address from which to send welcome emails to new users'
[secrets."directory/guichet/mail_domain"] [secrets."directory/guichet/mail_domain"]
type = 'user' type = 'user'
description = 'E-mail domain for new users (e.g. example.com)' description = 'E-mail domain for new users'
example = 'example.com'
# S3 configuration
[secrets."directory/guichet/s3_endpoint"]
type = 'user'
description = 'S3 endpoint URL'
[secrets."directory/guichet/s3_bucket"]
type = 'user'
description = 'S3 bucket in which to store data files (such as profile pictures)'
[secrets."directory/guichet/s3_region"]
type = 'user'
description = 'S3 region'
[secrets."directory/guichet/s3_access_key"]
type = 'user'
description = 'Garage access key for Guichet profile pictures'
[secrets."directory/guichet/s3_secret_key"]
type = 'user'
description = 'Garage secret key for Guichet profile pictures'

View file

@ -25,7 +25,6 @@ tls_skip_verify = true
[s3_api] [s3_api]
s3_region = "garage-staging" s3_region = "garage-staging"
api_bind_addr = "0.0.0.0:3990" api_bind_addr = "0.0.0.0:3990"
root_domain = ".garage.staging.deuxfleurs.org"
[k2v_api] [k2v_api]
api_bind_addr = "0.0.0.0:3993" api_bind_addr = "0.0.0.0:3993"

View file

@ -1,12 +1,13 @@
job "garage-staging" { job "garage-staging" {
datacenters = [ "neptune", "dathomir", "corrin", "bespin" ]
type = "system" type = "system"
priority = 90 priority = 90
datacenters = [ "neptune", "jupiter", "corrin", "bespin" ]
update { update {
max_parallel = 2 max_parallel = 1
min_healthy_time = "60s" stagger = "1m"
min_healthy_time = "10s"
} }
group "garage-staging" { group "garage-staging" {
@ -18,52 +19,49 @@ job "garage-staging" {
port "admin" { static = 3909 } port "admin" { static = 3909 }
} }
update {
max_parallel = 10
min_healthy_time = "30s"
healthy_deadline = "5m"
}
task "server" { task "server" {
driver = "docker" driver = "nix2"
config { config {
image = "superboum/garage:v1.0.0-rc1-hotfix-red-ftr-wquorum" packages = [
command = "/garage" "#bash", # so that we can enter a shell inside container
args = [ "server" ] "#coreutils",
network_mode = "host" # garage v0.9.1-rc
volumes = [ "git+https://git.deuxfleurs.fr/Deuxfleurs/garage.git?ref=main&rev=9cfeea389a1274d4d3c1f4b7072b0c056af410ef",
"/mnt/storage/garage-staging/data:/data",
"/mnt/ssd/garage-staging/meta:/meta",
"secrets/garage.toml:/etc/garage.toml",
"secrets:/etc/garage",
] ]
logging { command = "garage"
type = "journald" args = [ "server" ]
bind = {
"/mnt/storage/garage-staging/data" = "/data",
"/mnt/ssd/garage-staging/meta" = "/meta",
} }
} }
env = { env = {
RUST_LOG = "garage=info,garage_api=debug", RUST_LOG = "garage=debug",
} }
# files currently owned by root, we don't want to chown everything
user = "root"
template { template {
data = file("../config/garage.toml") data = file("../config/garage.toml")
destination = "secrets/garage.toml" destination = "etc/garage.toml"
} }
template { template {
data = "{{ key \"secrets/consul/consul-ca.crt\" }}" data = "{{ key \"secrets/consul/consul-ca.crt\" }}"
destination = "secrets/consul-ca.crt" destination = "etc/garage/consul-ca.crt"
} }
template { template {
data = "{{ key \"secrets/consul/consul-client.crt\" }}" data = "{{ key \"secrets/consul/consul-client.crt\" }}"
destination = "secrets/consul-client.crt" destination = "etc/garage/consul-client.crt"
} }
template { template {
data = "{{ key \"secrets/consul/consul-client.key\" }}" data = "{{ key \"secrets/consul/consul-client.key\" }}"
destination = "secrets/consul-client.key" destination = "etc/garage/consul-client.key"
} }
resources { resources {
@ -75,68 +73,22 @@ job "garage-staging" {
kill_signal = "SIGINT" kill_signal = "SIGINT"
kill_timeout = "20s" kill_timeout = "20s"
restart {
interval = "5m"
attempts = 10
delay = "1m"
mode = "delay"
}
service { service {
name = "garage-staging-rpc" name = "garage-staging-rpc"
tags = ["garage-staging-rpc"] tags = ["garage-staging-rpc"]
port = "rpc" port = "rpc"
} }
#### Configuration for service ports: admin port (internal use only)
service {
name = "garage-staging-admin"
tags = [
"garage-staging-admin",
]
port = "admin"
check {
name = "garage-tcp-liveness-check"
type = "tcp"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
#### Configuration for service ports: externally available ports (S3 API, K2V, web)
service { service {
name = "garage-staging-s3-api" name = "garage-staging-s3-api"
tags = [ tags = [
"garage-staging-api", "garage-staging-api",
"tricot garage.staging.deuxfleurs.org", "tricot garage.staging.deuxfleurs.org",
"tricot *.garage.staging.deuxfleurs.org",
"tricot-add-header Access-Control-Allow-Origin *", "tricot-add-header Access-Control-Allow-Origin *",
"tricot-on-demand-tls-ask http://garage-staging-admin.service.staging.consul:3909/check",
"tricot-site-lb", "tricot-site-lb",
] ]
port = "s3" port = "s3"
# Check 1: Garage is alive and answering TCP connections
check { check {
name = "garage-staging-api-live"
type = "tcp"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
# Check 2: Garage is in a healthy state and requests should be routed here
check {
name = "garage-staging-api-healthy"
port = "admin" port = "admin"
type = "http" type = "http"
path = "/health" path = "/health"
@ -154,21 +106,7 @@ job "garage-staging" {
"tricot-site-lb", "tricot-site-lb",
] ]
port = "k2v" port = "k2v"
# Check 1: Garage is alive and answering TCP connections
check { check {
name = "garage-staging-k2v-live"
type = "tcp"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
# Check 2: Garage is in a healthy state and requests should be routed here
check {
name = "garage-staging-k2v-healthy"
port = "admin" port = "admin"
type = "http" type = "http"
path = "/health" path = "/health"
@ -181,37 +119,14 @@ job "garage-staging" {
name = "garage-staging-web" name = "garage-staging-web"
tags = [ tags = [
"garage-staging-web", "garage-staging-web",
"tricot * 1",
"tricot *.web.staging.deuxfleurs.org", "tricot *.web.staging.deuxfleurs.org",
"tricot staging.deuxfleurs.org", "tricot staging.deuxfleurs.org",
"tricot matrix.home.adnab.me/.well-known/matrix/server", "tricot matrix.home.adnab.me/.well-known/matrix/server",
"tricot-add-header Strict-Transport-Security max-age=63072000; includeSubDomains; preload",
"tricot-add-header X-Frame-Options SAMEORIGIN",
"tricot-add-header X-XSS-Protection 1; mode=block",
"tricot-add-header X-Content-Type-Options nosniff",
"tricot-add-header Access-Control-Allow-Origin *", "tricot-add-header Access-Control-Allow-Origin *",
"tricot-on-demand-tls-ask http://garage-staging-admin.service.staging.consul:3909/check",
"tricot-site-lb", "tricot-site-lb",
"tricot-block-user-agent Claude-Web",
"tricot-block-user-agent ClaudeBot",
"tricot-block-user-agent anthropic-ai",
] ]
port = "web" port = "web"
# Check 1: Garage is alive and answering TCP connections
check { check {
name = "garage-staging-web-live"
type = "tcp"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
# Check 2: Garage is in a healthy state and requests should be routed here
check {
name = "garage-staging-web-healthy"
port = "admin" port = "admin"
type = "http" type = "http"
path = "/health" path = "/health"
@ -219,6 +134,44 @@ job "garage-staging" {
timeout = "5s" timeout = "5s"
} }
} }
service {
name = "garage-staging-admin"
tags = [
"garage-staging-admin",
]
port = "admin"
check {
name = "garage-admin-health-check"
type = "http"
path = "/health"
interval = "60s"
timeout = "5s"
check_restart {
limit = 10
grace = "90s"
ignore_warnings = true
}
}
check {
name = "garage-tcp-liveness-check"
type = "tcp"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = true
}
}
}
restart {
interval = "5m"
attempts = 10
delay = "1m"
mode = "delay"
}
} }
} }
} }

View file

@ -33,7 +33,7 @@ job "im" {
] ]
command = "litestream" command = "litestream"
args = [ args = [
"restore", "-config", "/etc/litestream.yml", "/ephemeral/homeserver.db" "restore", "-v", "-config", "/etc/litestream.yml", "/ephemeral/homeserver.db"
] ]
bind = { bind = {
"../alloc/data" = "/ephemeral", "../alloc/data" = "/ephemeral",
@ -55,7 +55,6 @@ job "im" {
task "synapse" { task "synapse" {
driver = "nix2" driver = "nix2"
config { config {
nixpkgs = "github:nixos/nixpkgs/nixos-23.11"
packages = [ packages = [
"#cacert", "#cacert",
"#bash", "#bash",

View file

@ -38,27 +38,3 @@ scrape_configs:
ca_file: /etc/prom/consul.crt ca_file: /etc/prom/consul.crt
cert_file: /etc/prom/consul-client.crt cert_file: /etc/prom/consul-client.crt
key_file: /etc/prom/consul-client.key key_file: /etc/prom/consul-client.key
# see https://prometheus.io/docs/prometheus/latest/configuration/configuration/#static_config
# and https://www.nomadproject.io/api-docs/metrics
# and https://learn.hashicorp.com/tutorials/nomad/prometheus-metrics
# dashboard at https://grafana.com/grafana/dashboards/3800
- job_name: 'nomad'
scrape_interval: 10s
metrics_path: "/v1/metrics"
params:
format: ['prometheus']
scheme: 'https'
tls_config:
ca_file: /etc/prom/nomad-ca.crt
cert_file: /etc/prom/nomad-client.crt
key_file: /etc/prom/nomad-client.key
insecure_skip_verify: true
consul_sd_configs:
- server: 'https://localhost:8501'
services:
- 'nomad-client'
tls_config:
ca_file: /etc/prom/consul.crt
cert_file: /etc/prom/consul-client.crt
key_file: /etc/prom/consul-client.key

Some files were not shown because too many files have changed in this diff Show more