Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

99 changed files with 1007 additions and 1376 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "docker/static/goStatic"]
path = app/build/static/goStatic
url = https://github.com/PierreZ/goStatic
[submodule "docker/blog/quentin.dufour.io"]
path = docker/blog-quentin/quentin.dufour.io
url = git@gitlab.com:superboum/quentin.dufour.io.git

View file

@ -1,8 +1,31 @@
deuxfleurs.fr
=============
**OBSOLETION NOTICE:** We are progressively migrating our stack to NixOS, to replace Ansible. Most of the files present in this repository are outdated or obsolete,
the current code for our infrastructure is at: <https://git.deuxfleurs.fr/Deuxfleurs/nixcfg>.
*Many things are still missing here, including a proper documentation. Please stay nice, it is a volunter project. Feel free to open pull/merge requests to improve it. Thanks.*
## Our abstraction stack
We try to build a generic abstraction stack between our different resources (CPU, RAM, disk, etc.) and our services (Chat, Storage, etc.), we develop our own tools when needed:
* **[garage](https://git.deuxfleurs.fr/Deuxfleurs/garage/):** S3-compatible lightweight object store for self-hosted geo-distributed deployments (we also have a legacy glusterfs cluster)
* **[diplonat](https://git.deuxfleurs.fr/Deuxfleurs/diplonat):** network automation (firewalling, upnp igd)
* **[bottin](https://git.deuxfleurs.fr/Deuxfleurs/bottin):** authentication and authorization (LDAP protocol, consul backend)
* **[guichet](https://git.deuxfleurs.fr/Deuxfleurs/guichet):** a dashboard for our users and administrators
* **ansible:** physical node configuration
* **nomad:** schedule containers and handle their lifecycle
* **consul:** distributed key value store + lock + service discovery
* **stolon + postgresql:** distributed relational database
* **docker:** package, distribute and isolate applications
Some services we provide:
* **Websites:** garage (static) + fediverse blog (plume)
* **Chat:** Synapse + Element Web (Matrix protocol)
* **Email:** Postfix SMTP + Dovecot IMAP + opendkim DKIM + Sogo webmail (legacy) | Alps webmail (experimental)
* **Storage:** Seafile (legacy) | Nextcloud (experimental)
* **Visio:** Jitsi
As a generic abstraction is provided, deploying new services should be easy.
## I am lost, how this repo works?
@ -19,3 +42,69 @@ To ease the development, we make the choice of a fully integrated environment
3. `op_guide`: Guides to explain you operations you can do cluster wide (like configuring postgres)
## Start hacking
### Deploying/Updating new services is done from your machine
*The following instructions are provided for ops that already have access to the servers (meaning: their SSH public key is known by the cluster).*
Deploy Nomad on your machine:
```bash
export NOMAD_VER=1.0.1
wget https://releases.hashicorp.com/nomad/${NOMAD_VER}/nomad_${NOMAD_VER}_linux_amd64.zip
unzip nomad_${NOMAD_VER}_linux_amd64.zip
sudo mv nomad /usr/local/bin
rm nomad_${NOMAD_VER}_linux_amd64.zip
```
Deploy Consul on your machine:
```bash
export CONSUL_VER=1.9.0
wget https://releases.hashicorp.com/consul/${CONSUL_VER}/consul_${CONSUL_VER}_linux_amd64.zip
unzip consul_${CONSUL_VER}_linux_amd64.zip
sudo mv consul /usr/local/bin
rm consul_${CONSUL_VER}_linux_amd64.zip
```
Create an alias (and put it in your `.bashrc`) to bind APIs on your machine:
```
alias bind_df="ssh \
-p110 \
-N \
-L 1389:bottin2.service.2.cluster.deuxfleurs.fr:389 \
-L 4646:127.0.0.1:4646 \
-L 5432:psql-proxy.service.2.cluster.deuxfleurs.fr:5432 \
-L 8082:traefik-admin.service.2.cluster.deuxfleurs.fr:8082 \
-L 8500:127.0.0.1:8500 \
<a server from the cluster>"
```
and run:
bind_df
Adrien uses `.ssh/config` configuration instead. I works basically the same. Here it goes:
```
# in ~/.ssh/config
Host deuxfleurs
User adrien
Hostname deuxfleurs.fr
# If you don't use the default ~/.ssh/id_rsa to connect to Deuxfleurs
IdentityFile <some_key_path>
PubKeyAuthentication yes
ForwardAgent No
LocalForward 1389 bottin2.service.2.cluster.deuxfleurs.fr:389
LocalForward 4646 127.0.0.1:4646
LocalForward 5432 psql-proxy.service.2.cluster.deuxfleurs.fr:5432
LocalForward 8082 traefik-admin.service.2.cluster.deuxfleurs.fr:8082
LocalForward 8500 127.0.0.1:8500
```
Now, to connect, do the following:
ssh deuxfleurs -N

View file

@ -0,0 +1,22 @@
FROM golang:buster as builder
WORKDIR /root
RUN git clone https://filippo.io/age && cd age/cmd/age && go build -o age .
FROM amd64/debian:buster
COPY --from=builder /root/age/cmd/age/age /usr/local/bin/age
RUN apt-get update && \
apt-get -qq -y full-upgrade && \
apt-get install -y rsync wget openssh-client postgresql-client && \
apt-get clean && \
rm -f /var/lib/apt/lists/*_*
RUN mkdir -p /root/.ssh
WORKDIR /root
COPY do_backup.sh /root/do_backup.sh
CMD "/root/do_backup.sh"

View file

@ -0,0 +1,40 @@
#!/bin/sh
set -x -e
cd /root
chmod 0600 .ssh/id_ed25519
cat > .ssh/config <<EOF
Host backuphost
HostName $TARGET_SSH_HOST
Port $TARGET_SSH_PORT
User $TARGET_SSH_USER
EOF
echo "export sql"
export PGPASSWORD=$REPL_PSQL_PWD
pg_basebackup \
--pgdata=- \
--format=tar \
--max-rate=1M \
--no-slot \
--wal-method=none \
--gzip \
--compress=8 \
--checkpoint=spread \
--progress \
--verbose \
--status-interval=10 \
--username=$REPL_PSQL_USER \
--port=5432 \
--host=psql-proxy.service.2.cluster.deuxfleurs.fr | \
age -r "$(cat /root/.ssh/id_ed25519.pub)" | \
ssh backuphost "cat > $TARGET_SSH_DIR/matrix/db-$(date --iso-8601=minute).gz.age"
MATRIX_MEDIA="/mnt/glusterfs/chat/matrix/synapse/media"
echo "export local_content"
tar -vzcf - ${MATRIX_MEDIA} | \
age -r "$(cat /root/.ssh/id_ed25519.pub)" | \
ssh backuphost "cat > $TARGET_SSH_DIR/matrix/media-$(date --iso-8601=minute).gz.age"

View file

@ -1 +0,0 @@
result

View file

@ -1,8 +0,0 @@
## Build
```bash
docker load < $(nix-build docker.nix)
docker push superboum/backup-psql:???
```

View file

@ -1,106 +0,0 @@
#!/usr/bin/env python3
import shutil,sys,os,datetime,minio,subprocess
working_directory = "."
if 'CACHE_DIR' in os.environ: working_directory = os.environ['CACHE_DIR']
required_space_in_bytes = 20 * 1024 * 1024 * 1024
bucket = os.environ['AWS_BUCKET']
key = os.environ['AWS_ACCESS_KEY_ID']
secret = os.environ['AWS_SECRET_ACCESS_KEY']
endpoint = os.environ['AWS_ENDPOINT']
pubkey = os.environ['CRYPT_PUBLIC_KEY']
psql_host = os.environ['PSQL_HOST']
psql_user = os.environ['PSQL_USER']
s3_prefix = str(datetime.datetime.now())
files = [ "backup_manifest", "base.tar.gz", "pg_wal.tar.gz" ]
clear_paths = [ os.path.join(working_directory, f) for f in files ]
crypt_paths = [ os.path.join(working_directory, f) + ".age" for f in files ]
s3_keys = [ s3_prefix + "/" + f for f in files ]
def abort(msg):
for p in clear_paths + crypt_paths:
if os.path.exists(p):
print(f"Remove {p}")
os.remove(p)
if msg: sys.exit(msg)
else: print("success")
# Check we have enough space on disk
if shutil.disk_usage(working_directory).free < required_space_in_bytes:
abort(f"Not enough space on disk at path {working_directory} to perform a backup, aborting")
# Check postgres password is set
if 'PGPASSWORD' not in os.environ:
abort(f"You must pass postgres' password through the environment variable PGPASSWORD")
# Check our working directory is empty
if len(os.listdir(working_directory)) != 0:
abort(f"Working directory {working_directory} is not empty, aborting")
# Check Minio
client = minio.Minio(endpoint, key, secret)
if not client.bucket_exists(bucket):
abort(f"Bucket {bucket} does not exist or its access is forbidden, aborting")
# Perform the backup locally
try:
ret = subprocess.run(["pg_basebackup",
f"--host={psql_host}",
f"--username={psql_user}",
f"--pgdata={working_directory}",
f"--format=tar",
"--wal-method=stream",
"--gzip",
"--compress=6",
"--progress",
"--max-rate=5M",
])
if ret.returncode != 0:
abort(f"pg_basebackup exited, expected return code 0, got {ret.returncode}. aborting")
except Exception as e:
abort(f"pg_basebackup raised exception {e}. aborting")
# Check that the expected files are here
for p in clear_paths:
print(f"Checking that {p} exists locally")
if not os.path.exists(p):
abort(f"File {p} expected but not found, aborting")
# Cipher them
for c, e in zip(clear_paths, crypt_paths):
print(f"Ciphering {c} to {e}")
try:
ret = subprocess.run(["age", "-r", pubkey, "-o", e, c])
if ret.returncode != 0:
abort(f"age exit code is {ret}, 0 expected. aborting")
except Exception as e:
abort(f"aged raised an exception. {e}. aborting")
# Upload the backup to S3
for p, k in zip(crypt_paths, s3_keys):
try:
print(f"Uploading {p} to {k}")
result = client.fput_object(bucket, k, p)
print(
"created {0} object; etag: {1}, version-id: {2}".format(
result.object_name, result.etag, result.version_id,
),
)
except Exception as e:
abort(f"Exception {e} occured while upload {p}. aborting")
# Check that the files have been uploaded
for k in s3_keys:
try:
print(f"Checking that {k} exists remotely")
result = client.stat_object(bucket, k)
print(
"last-modified: {0}, size: {1}".format(
result.last_modified, result.size,
),
)
except Exception as e:
abort(f"{k} not found on S3. {e}. aborting")
abort(None)

View file

@ -1,8 +0,0 @@
{
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";
};
}

View file

@ -1,37 +0,0 @@
let
common = import ./common.nix;
pkgs = import common.pkgsSrc {};
python-with-my-packages = pkgs.python3.withPackages (p: with p; [
minio
]);
in
pkgs.stdenv.mkDerivation {
name = "backup-psql";
src = pkgs.lib.sourceFilesBySuffices ./. [ ".py" ];
buildInputs = [
python-with-my-packages
pkgs.age
pkgs.postgresql_14
];
buildPhase = ''
cat > backup-psql <<EOF
#!${pkgs.bash}/bin/bash
export PYTHONPATH=${python-with-my-packages}/${python-with-my-packages.sitePackages}
export PATH=${python-with-my-packages}/bin:${pkgs.age}/bin:${pkgs.postgresql_14}/bin
${python-with-my-packages}/bin/python3 $out/lib/backup-psql.py
EOF
chmod +x backup-psql
'';
installPhase = ''
mkdir -p $out/{bin,lib}
cp *.py $out/lib/backup-psql.py
cp backup-psql $out/bin/backup-psql
'';
}

View file

@ -1,11 +0,0 @@
let
common = import ./common.nix;
app = import ./default.nix;
pkgs = import common.pkgsSrc {};
in
pkgs.dockerTools.buildImage {
name = "superboum/backup-psql-docker";
config = {
Cmd = [ "${app}/bin/backup-psql" ];
};
}

View file

@ -1,171 +0,0 @@
job "backup_daily" {
datacenters = ["dc1"]
type = "batch"
priority = "60"
periodic {
cron = "@daily"
// Do not allow overlapping runs.
prohibit_overlap = true
}
group "backup-dovecot" {
constraint {
attribute = "${attr.unique.hostname}"
operator = "="
value = "digitale"
}
task "main" {
driver = "docker"
config {
image = "restic/restic:0.12.1"
entrypoint = [ "/bin/sh", "-c" ]
args = [ "restic backup /mail && restic forget --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ]
volumes = [
"/mnt/ssd/mail:/mail"
]
}
template {
data = <<EOH
AWS_ACCESS_KEY_ID={{ key "secrets/email/dovecot/backup_aws_access_key_id" }}
AWS_SECRET_ACCESS_KEY={{ key "secrets/email/dovecot/backup_aws_secret_access_key" }}
RESTIC_REPOSITORY={{ key "secrets/email/dovecot/backup_restic_repository" }}
RESTIC_PASSWORD={{ key "secrets/email/dovecot/backup_restic_password" }}
EOH
destination = "secrets/env_vars"
env = true
}
resources {
cpu = 500
memory = 200
}
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
}
}
group "backup-plume" {
constraint {
attribute = "${attr.unique.hostname}"
operator = "="
value = "digitale"
}
task "main" {
driver = "docker"
config {
image = "restic/restic:0.12.1"
entrypoint = [ "/bin/sh", "-c" ]
args = [ "restic backup /plume && restic forget --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ]
volumes = [
"/mnt/ssd/plume/media:/plume"
]
}
template {
data = <<EOH
AWS_ACCESS_KEY_ID={{ key "secrets/plume/backup_aws_access_key_id" }}
AWS_SECRET_ACCESS_KEY={{ key "secrets/plume/backup_aws_secret_access_key" }}
RESTIC_REPOSITORY={{ key "secrets/plume/backup_restic_repository" }}
RESTIC_PASSWORD={{ key "secrets/plume/backup_restic_password" }}
EOH
destination = "secrets/env_vars"
env = true
}
resources {
cpu = 500
memory = 200
}
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
}
}
group "backup-consul" {
task "consul-kv-export" {
driver = "docker"
lifecycle {
hook = "prestart"
sidecar = false
}
config {
image = "consul:1.11.2"
network_mode = "host"
entrypoint = [ "/bin/sh", "-c" ]
args = [ "/bin/consul kv export > $NOMAD_ALLOC_DIR/consul.json" ]
}
env {
CONSUL_HTTP_ADDR = "http://consul.service.2.cluster.deuxfleurs.fr:8500"
}
resources {
cpu = 200
memory = 200
}
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
}
task "restic-backup" {
driver = "docker"
config {
image = "restic/restic:0.12.1"
entrypoint = [ "/bin/sh", "-c" ]
args = [ "restic backup $NOMAD_ALLOC_DIR/consul.json && restic forget --keep-within 1m1d --keep-within-weekly 3m --keep-within-monthly 1y && restic prune --max-unused 50% --max-repack-size 2G && restic check" ]
}
template {
data = <<EOH
AWS_ACCESS_KEY_ID={{ key "secrets/backup/consul/backup_aws_access_key_id" }}
AWS_SECRET_ACCESS_KEY={{ key "secrets/backup/consul/backup_aws_secret_access_key" }}
RESTIC_REPOSITORY={{ key "secrets/backup/consul/backup_restic_repository" }}
RESTIC_PASSWORD={{ key "secrets/backup/consul/backup_restic_password" }}
EOH
destination = "secrets/env_vars"
env = true
}
resources {
cpu = 200
memory = 200
}
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
}
}
}

View file

@ -0,0 +1,62 @@
job "backup_manual_matrix" {
datacenters = ["dc1"]
type = "batch"
task "backup-matrix" {
driver = "docker"
config {
image = "superboum/backup_matrix:4"
volumes = [
"secrets/id_ed25519:/root/.ssh/id_ed25519",
"secrets/id_ed25519.pub:/root/.ssh/id_ed25519.pub",
"secrets/known_hosts:/root/.ssh/known_hosts",
"/mnt/glusterfs/chat/matrix/synapse/media:/mnt/glusterfs/chat/matrix/synapse/media"
]
network_mode = "host"
}
env {
CONSUL_HTTP_ADDR = "http://consul.service.2.cluster.deuxfleurs.fr:8500"
}
template {
data = <<EOH
TARGET_SSH_USER={{ key "secrets/backup/target_ssh_user" }}
TARGET_SSH_PORT={{ key "secrets/backup/target_ssh_port" }}
TARGET_SSH_HOST={{ key "secrets/backup/target_ssh_host" }}
TARGET_SSH_DIR={{ key "secrets/backup/target_ssh_dir" }}
REPL_PSQL_USER={{ key "secrets/postgres/keeper/pg_repl_username" }}
REPL_PSQL_PWD={{ key "secrets/postgres/keeper/pg_repl_pwd" }}
EOH
destination = "secrets/env_vars"
env = true
}
template {
data = "{{ key \"secrets/backup/id_ed25519\" }}"
destination = "secrets/id_ed25519"
}
template {
data = "{{ key \"secrets/backup/id_ed25519.pub\" }}"
destination = "secrets/id_ed25519.pub"
}
template {
data = "{{ key \"secrets/backup/target_ssh_fingerprint\" }}"
destination = "secrets/known_hosts"
}
resources {
memory = 200
}
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
}
}

View file

@ -1,55 +0,0 @@
job "backup_weekly" {
datacenters = ["dc1"]
type = "batch"
priority = "60"
periodic {
cron = "@weekly"
// Do not allow overlapping runs.
prohibit_overlap = true
}
group "backup-psql" {
task "main" {
driver = "docker"
config {
image = "superboum/backup-psql-docker:gyr3aqgmhs0hxj0j9hkrdmm1m07i8za2"
volumes = [
// Mount a cache on the hard disk to avoid filling the SSD
"/mnt/storage/tmp_bckp_psql:/mnt/cache"
]
}
template {
data = <<EOH
CACHE_DIR=/mnt/cache
AWS_BUCKET=backups-pgbasebackup
AWS_ENDPOINT=s3.deuxfleurs.shirokumo.net
AWS_ACCESS_KEY_ID={{ key "secrets/backup/psql/aws_access_key_id" }}
AWS_SECRET_ACCESS_KEY={{ key "secrets/backup/psql/aws_secret_access_key" }}
CRYPT_PUBLIC_KEY={{ key "secrets/backup/psql/crypt_public_key" }}
PSQL_HOST=psql-proxy.service.2.cluster.deuxfleurs.fr
PSQL_USER={{ key "secrets/postgres/keeper/pg_repl_username" }}
PGPASSWORD={{ key "secrets/postgres/keeper/pg_repl_pwd" }}
EOH
destination = "secrets/env_vars"
env = true
}
resources {
cpu = 200
memory = 200
}
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
}
}
}

View file

@ -1 +0,0 @@
USER Backup AWS access key ID

View file

@ -1 +0,0 @@
USER Backup AWS secret access key

View file

@ -1 +0,0 @@
USER Restic password to encrypt backups

View file

@ -1 +0,0 @@
USER Restic repository, eg. s3:https://s3.garage.tld

View file

@ -1 +0,0 @@
USER Minio access key

View file

@ -1 +0,0 @@
USER Minio secret key

View file

@ -1 +0,0 @@
USER a private key to decript backups from age

View file

@ -1 +0,0 @@
USER A public key to encypt backups with age

View file

@ -13,21 +13,14 @@ job "bagage" {
network {
port "web_port" { to = 8080 }
port "ssh_port" {
static = 2222
to = 2222
}
}
task "server" {
driver = "docker"
config {
image = "superboum/amd64_bagage:v11"
readonly_rootfs = false
volumes = [
"secrets/id_rsa:/id_rsa"
]
ports = [ "web_port", "ssh_port" ]
image = "superboum/amd64_bagage:v8"
readonly_rootfs = true
ports = [ "web_port" ]
}
env {
@ -38,36 +31,19 @@ job "bagage" {
memory = 500
}
template {
data = "{{ key \"secrets/bagage/id_rsa\" }}"
destination = "secrets/id_rsa"
}
service {
name = "bagage-ssh"
port = "ssh_port"
address_mode = "host"
tags = [
"bagage",
"(diplonat (tcp_port 2222))"
]
}
service {
name = "bagage-webdav"
name = "bagage"
tags = [
"bagage",
"traefik.enable=true",
"traefik.frontend.entryPoints=https,http",
"traefik.frontend.rule=Host:bagage.deuxfleurs.fr",
"tricot bagage.deuxfleurs.fr",
]
port = "web_port"
address_mode = "host"
check {
type = "tcp"
port = "web_port"
address_mode = "host"
interval = "60s"
timeout = "5s"
check_restart {

View file

@ -1 +0,0 @@
CMD ssh-keygen -q -f >(cat) -N "" <<< y 2>/dev/null 1>&2 ; true

View file

@ -1,50 +1,51 @@
job "core" {
datacenters = ["dc1", "neptune"]
type = "system"
priority = 90
datacenters = ["dc1"]
type = "system"
priority = 90
constraint {
attribute = "${attr.cpu.arch}"
value = "amd64"
}
constraint {
attribute = "${attr.cpu.arch}"
value = "amd64"
}
update {
max_parallel = 1
stagger = "1m"
}
update {
max_parallel = 1
stagger = "1m"
}
group "network" {
task "diplonat" {
driver = "docker"
group "network" {
task "diplonat" {
driver = "docker"
config {
image = "lxpz/amd64_diplonat:3"
network_mode = "host"
readonly_rootfs = true
privileged = true
}
config {
image = "darkgallium/amd64_diplonat:v3"
network_mode = "host"
readonly_rootfs = true
privileged = true
}
restart {
interval = "30m"
attempts = 2
delay = "15s"
mode = "delay"
}
restart {
interval = "30m"
attempts = 2
delay = "15s"
mode = "delay"
}
template {
data = <<EOH
template {
data = <<EOH
DIPLONAT_PRIVATE_IP={{ env "attr.unique.network.ip-address" }}
DIPLONAT_REFRESH_TIME=60
DIPLONAT_EXPIRATION_TIME=300
DIPLONAT_CONSUL_NODE_NAME={{ env "attr.unique.hostname" }}
RUST_LOG=debug
EOH
destination = "secrets/env"
env = true
}
destination = "secrets/env"
env = true
}
resources {
memory = 40
}
}
}
resources {
memory = 40
}
}
}
}

View file

@ -1,2 +0,0 @@
docker load < $(nix-build docker.nix)
docker push superboum/cryptpad:???

View file

@ -1,8 +0,0 @@
{
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";
};
}

View file

@ -1,10 +0,0 @@
let
common = import ./common.nix;
pkgs = import common.pkgsSrc {};
in
pkgs.dockerTools.buildImage {
name = "superboum/cryptpad";
config = {
Cmd = [ "${pkgs.cryptpad}/bin/cryptpad" ];
};
}

View file

@ -1,283 +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: 'http://localhost:3000',
/* 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://some-other-domain.xyz",
/* 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: [
//"[cryptpad-user1@my.awesome.website/YZgXQxKR0Rcb6r6CmxHPdAGLVludrAF2lEnkbx1vVOo=]",
],
*/
/* =====================
* 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
* ===================== */
/*
* 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: './root/tmp/mut/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: './root/tmp/mut/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: './root/tmp/mut/data/pins',
/* if you would like the list of scheduled tasks to be stored in
a custom location, change the path below:
*/
taskPath: './root/tmp/mut/data/tasks',
/* if you would like users' authenticated blocks to be stored in
a custom location, change the path below:
*/
blockPath: './root/tmp/mut/block',
/* CryptPad allows logged in users to upload encrypted files. Files/blobs
* are stored in a 'blob-store'. Set its location here.
*/
blobPath: './root/tmp/mut/blob',
/* CryptPad stores incomplete blobs in a 'staging' area until they are
* fully uploaded. Set its location here.
*/
blobStagingPath: './root/tmp/mut/data/blobstage',
decreePath: './root/tmp/mut/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: './root/tmp/mut/data/logs',
/* =====================
* 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: 'debug',
/* 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: 'unspecified',
};

View file

@ -4,7 +4,7 @@
"consul_host": "http://consul.service.2.cluster.deuxfleurs.fr:8500",
"log_level": "debug",
"acl": [
"*,dc=deuxfleurs,dc=fr::read:*:* !userpassword !user_secret !alternate_user_secrets !garage_s3_secret_key",
"*,dc=deuxfleurs,dc=fr::read:*:* !userpassword",
"*::read modify:SELF:*",
"ANONYMOUS::bind:*,ou=users,dc=deuxfleurs,dc=fr:",
"ANONYMOUS::bind:cn=admin,dc=deuxfleurs,dc=fr:",
@ -20,6 +20,10 @@
"*:cn=asso_deuxfleurs,ou=groups,dc=deuxfleurs,dc=fr:modifyAdd:cn=email,ou=groups,dc=deuxfleurs,dc=fr:*",
"*,ou=invitations,dc=deuxfleurs,dc=fr::modifyAdd:cn=email,ou=groups,dc=deuxfleurs,dc=fr:*",
"*:cn=asso_deuxfleurs,ou=groups,dc=deuxfleurs,dc=fr:modifyAdd:cn=seafile,ou=groups,dc=deuxfleurs,dc=fr:*",
"*,ou=invitations,dc=deuxfleurs,dc=fr::modifyAdd:cn=seafile,ou=groups,dc=deuxfleurs,dc=fr:*",
"*:cn=asso_deuxfleurs,ou=groups,dc=deuxfleurs,dc=fr:modifyAdd:cn=nextcloud,ou=groups,dc=deuxfleurs,dc=fr:*",
"*,ou=invitations,dc=deuxfleurs,dc=fr::modifyAdd:cn=seafile,ou=nextcloud,dc=deuxfleurs,dc=fr:*",
"cn=admin,dc=deuxfleurs,dc=fr::read add modify delete:*:*",
"*:cn=admin,ou=groups,dc=deuxfleurs,dc=fr:read add modify delete:*:*"

View file

@ -59,7 +59,6 @@ job "directory" {
}
}
/*
group "guichet" {
count = 1
@ -70,7 +69,7 @@ job "directory" {
task "guichet" {
driver = "docker"
config {
image = "dxflrs/guichet:6y7pv4kgfsn02iijj55kf5af0rbksgrn"
image = "superboum/guichet_amd64:15"
readonly_rootfs = true
ports = [ "web_port" ]
volumes = [
@ -94,7 +93,6 @@ job "directory" {
"traefik.enable=true",
"traefik.frontend.entryPoints=https,http",
"traefik.frontend.rule=Host:guichet.deuxfleurs.fr",
"tricot guichet.deuxfleurs.fr",
]
port = "web_port"
address_mode = "host"
@ -112,6 +110,5 @@ job "directory" {
}
}
}
*/
}

View file

@ -7,21 +7,18 @@ services:
context: ./im/build/riotweb
args:
# https://github.com/vector-im/riot-web/releases
VERSION: 1.10.15
image: superboum/amd64_riotweb:v30
VERSION: 1.8.4
image: superboum/amd64_riotweb:v24
synapse:
build:
context: ./im/build/matrix-synapse
args:
# https://github.com/matrix-org/synapse/releases
VERSION: 1.61.1
VERSION: 1.42.0
# 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
# 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
S3_VERSION: ffd3fa477321608e57d27644197e721965e0e858
image: superboum/amd64_synapse:v53
S3_VERSION: 3c3fafd6a2624f05fd396d9e003501bf8bef7b2e
image: superboum/amd64_synapse:v47
# Email
sogo:
@ -50,16 +47,16 @@ services:
context: ./jitsi/build/jitsi-meet
args:
# https://github.com/jitsi/jitsi-meet
MEET_TAG: stable/jitsi-meet_6826
image: superboum/amd64_jitsi_meet:v5
MEET_TAG: jitsi-meet_5463
image: superboum/amd64_jitsi_meet:v4
jitsi-conference-focus:
build:
context: ./jitsi/build/jitsi-conference-focus
args:
# https://github.com/jitsi/jicofo
JICOFO_TAG: stable/jitsi-meet_6826
image: superboum/amd64_jitsi_conference_focus:v9
JICOFO_TAG: jitsi-meet_5463
image: superboum/amd64_jitsi_conference_focus:v7
jitsi-videobridge:
build:
@ -67,23 +64,23 @@ services:
args:
# https://github.com/jitsi/jitsi-videobridge
# note: JVB is not tagged with non-stable tags
JVB_TAG: stable/jitsi-meet_6826
image: superboum/amd64_jitsi_videobridge:v20
JVB_TAG: stable/jitsi-meet_5390
image: superboum/amd64_jitsi_videobridge:v17
jitsi-xmpp:
build:
context: ./jitsi/build/jitsi-xmpp
args:
MEET_TAG: stable/jitsi-meet_6826
PROSODY_VERSION: 0.11.12-1
image: superboum/amd64_jitsi_xmpp:v10
MEET_TAG: jitsi-meet_5463
PROSODY_VERSION: 0.11.7-1~buster4
image: superboum/amd64_jitsi_xmpp:v9
plume:
build:
context: ./plume/build/plume
args:
VERSION: 8709f6cf9f8ff7e3c5ee7ea699ee7c778e92fefc
image: superboum/plume:v8
VERSION: 8c372aa6fcd05083601903d83b0fcb4915585a95
image: superboum/plume:v4
postfix:
build:
@ -97,12 +94,16 @@ services:
build:
args:
# https://github.com/sorintlab/stolon/releases
STOLON_VERSION: 3bb7499f815f77140551eb762b200cf4557f57d3
STOLON_VERSION: 057389f7e484ee1d5c1e1a7020256020e7413c87
context: ./postgres/build/postgres
image: superboum/amd64_postgres:v11
image: superboum/amd64_postgres:v9
backup-consul:
build:
context: ./backup/build/backup-consul
image: lxpz/backup_consul:12
backup-matrix:
build:
context: ./backup/build/backup-matrix
image: superboum/backup_matrix:4

View file

@ -14,7 +14,7 @@ job "drone-ci" {
task "drone_server" {
driver = "docker"
config {
image = "drone/drone:2.12.0"
image = "drone/drone:2.0.4"
ports = [ "web_port" ]
}
@ -38,7 +38,6 @@ DRONE_S3_PATH_STYLE=true
DRONE_DATABASE_DRIVER=postgres
DRONE_DATABASE_DATASOURCE=postgres://{{ key "secrets/drone-ci/db_user" }}:{{ key "secrets/drone-ci/db_pass" }}@psql-proxy.service.2.cluster.deuxfleurs.fr:5432/drone?sslmode=disable
DRONE_USER_CREATE=username:lx-admin,admin:true
DRONE_REGISTRATION_CLOSED=true
DRONE_LOGS_TEXT=true
DRONE_LOGS_PRETTY=true
DRONE_LOGS_DEBUG=true
@ -60,7 +59,6 @@ EOH
"traefik.enable=true",
"traefik.frontend.entryPoints=https,http",
"traefik.frontend.rule=Host:drone.deuxfleurs.fr",
"tricot drone.deuxfleurs.fr",
]
port = "web_port"
address_mode = "host"

View file

@ -1,69 +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
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

@ -1,54 +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"
drone-runner:
image: drone/drone-runner-docker:latest
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

@ -1,9 +0,0 @@
substituters = https://cache.nixos.org https://nix.web.deuxfleurs.fr
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nix.web.deuxfleurs.fr:eTGL6kvaQn6cDR/F9lDYUIP9nCVR/kkshYfLDJf1yKs=
max-jobs = auto
cores = 0
log-lines = 200
filter-syscalls = true
sandbox = true
keep-outputs = true
keep-derivations = true

View file

@ -15,6 +15,5 @@ RUN go build -a -o /usr/local/bin/alps ./cmd/alps
FROM scratch
COPY --from=builder /usr/local/bin/alps /alps
COPY --from=builder /tmp/alps/themes /themes
COPY --from=builder /tmp/alps/plugins /plugins
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
ENTRYPOINT ["/alps"]

View file

@ -21,9 +21,8 @@ compatibility_level = 2
#===
# TLS parameters
#===
smtpd_tls_cert_file=/etc/ssl/postfix.crt
smtpd_tls_key_file=/etc/ssl/postfix.key
smtpd_tls_dh1024_param_file=auto
smtpd_tls_cert_file=/etc/ssl/certs/postfix.crt
smtpd_tls_key_file=/etc/ssl/private/postfix.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

View file

@ -28,12 +28,6 @@ job "email" {
task "server" {
driver = "docker"
constraint {
attribute = "${attr.unique.hostname}"
operator = "="
value = "digitale"
}
config {
image = "superboum/amd64_dovecot:v6"
readonly_rootfs = false
@ -44,7 +38,7 @@ job "email" {
"secrets/ssl/certs:/etc/ssl/certs",
"secrets/ssl/private:/etc/ssl/private",
"secrets/conf/:/etc/dovecot/",
"/mnt/ssd/mail:/var/mail/",
"/mnt/glusterfs/email/mail:/var/mail/",
]
}
@ -149,14 +143,12 @@ job "email" {
# ----- secrets ------
template {
# data = "{{ key \"secrets/email/dovecot/dovecot.crt\" }}"
data = "{{ with $d := key \"tricot/certs/imap.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}"
data = "{{ key \"secrets/email/dovecot/dovecot.crt\" }}"
destination = "secrets/ssl/certs/dovecot.crt"
perms = "400"
}
template {
# data = "{{ key \"secrets/email/dovecot/dovecot.key\" }}"
data = "{{ with $d := key \"tricot/certs/imap.deuxfleurs.fr\" | parseJSON }}{{ $d.key_pem }}{{ end }}"
data = "{{ key \"secrets/email/dovecot/dovecot.key\" }}"
destination = "secrets/ssl/private/dovecot.key"
perms = "400"
}
@ -261,7 +253,8 @@ job "email" {
command = "postfix"
args = [ "start-fg" ]
volumes = [
"secrets/ssl:/etc/ssl",
"secrets/ssl/certs:/etc/ssl/certs",
"secrets/ssl/private:/etc/ssl/private",
"secrets/postfix:/etc/postfix-conf",
"/dev/log:/dev/log"
]
@ -382,16 +375,14 @@ job "email" {
# --- secrets ---
template {
# data = "{{ key \"secrets/email/postfix/postfix.crt\" }}"
data = "{{ with $d := key \"tricot/certs/smtp.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}"
destination = "secrets/ssl/postfix.crt"
data = "{{ key \"secrets/email/postfix/postfix.crt\" }}"
destination = "secrets/ssl/certs/postfix.crt"
perms = "400"
}
template {
# data = "{{ key \"secrets/email/postfix/postfix.key\" }}"
data = "{{ with $d := key \"tricot/certs/smtp.deuxfleurs.fr\" | parseJSON }}{{ $d.key_pem }}{{ end }}"
destination = "secrets/ssl/postfix.key"
data = "{{ key \"secrets/email/postfix/postfix.key\" }}"
destination = "secrets/ssl/private/postfix.key"
perms = "400"
}
}
@ -432,8 +423,7 @@ job "email" {
"alps",
"traefik.enable=true",
"traefik.frontend.entryPoints=https,http",
"traefik.frontend.rule=Host:alps.deuxfleurs.fr",
"tricot alps.deuxfleurs.fr",
"traefik.frontend.rule=Host:alps.deuxfleurs.fr"
]
check {
type = "tcp"
@ -487,9 +477,7 @@ job "email" {
"sogo",
"traefik.enable=true",
"traefik.frontend.entryPoints=https,http",
"traefik.frontend.rule=Host:www.sogo.deuxfleurs.fr,sogo.deuxfleurs.fr;PathPrefix:/",
"tricot www.sogo.deuxfleurs.fr",
"tricot sogo.deuxfleurs.fr",
"traefik.frontend.rule=Host:www.sogo.deuxfleurs.fr,sogo.deuxfleurs.fr;PathPrefix:/"
]
check {
type = "tcp"

View file

@ -1 +0,0 @@
USER AWS Acces Key ID

View file

@ -1 +0,0 @@
USER AWS Secret Access key

View file

@ -1 +0,0 @@
USER Restic backup password to encrypt data

View file

@ -1 +0,0 @@
USER Restic Repository URL, check op_guide/backup-minio to see the format

View file

@ -1,60 +0,0 @@
job "frontend" {
datacenters = ["dc1", "neptune"]
type = "service"
priority = 90
group "tricot" {
network {
port "http_port" { static = 80 }
port "https_port" { static = 443 }
}
task "server" {
driver = "docker"
config {
image = "lxpz/amd64_tricot:37"
network_mode = "host"
readonly_rootfs = true
ports = [ "http_port", "https_port" ]
}
resources {
cpu = 2000
memory = 500
}
restart {
interval = "30m"
attempts = 2
delay = "15s"
mode = "delay"
}
template {
data = <<EOH
TRICOT_NODE_NAME={{ env "attr.unique.hostname" }}
TRICOT_LETSENCRYPT_EMAIL=alex@adnab.me
TRICOT_ENABLE_COMPRESSION=true
RUST_LOG=tricot=debug
EOH
destination = "secrets/env"
env = true
}
service {
name = "tricot-http"
port = "http_port"
tags = [ "(diplonat (tcp_port 80))" ]
address_mode = "host"
}
service {
name = "tricot-https"
port = "https_port"
tags = [ "(diplonat (tcp_port 443))" ]
address_mode = "host"
}
}
}
}

View file

@ -1,24 +1,29 @@
block_size = 1048576
metadata_dir = "/meta"
data_dir = "/data"
metadata_dir = "/garage/meta"
data_dir = "/garage/data"
replication_mode = "3"
rpc_bind_addr = "[::]:3901"
rpc_secret = "{{ key "secrets/garage/rpc_secret" | trimSpace }}"
sled_cache_capacity = 536870912
sled_sync_interval_ms = 10000
consul_host = "consul.service.2.cluster.deuxfleurs.fr:8500"
consul_service_name = "garage-rpc"
bootstrap_peers = []
max_concurrent_rpc_requests = 12
[rpc_tls]
ca_cert = "/garage/garage-ca.crt"
node_cert = "/garage/garage.crt"
node_key = "/garage/garage.key"
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".garage.deuxfleurs.fr"
[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.deuxfleurs.fr"
[admin]
api_bind_addr = "[::1]:3903"
index = "index.html"

View file

@ -1,5 +1,5 @@
job "garage" {
datacenters = ["dc1", "saturne", "neptune"]
datacenters = ["dc1", "belair", "saturne"]
type = "system"
priority = 80
@ -25,14 +25,15 @@ job "garage" {
driver = "docker"
config {
advertise_ipv6_address = true
image = "dxflrs/amd64_garage:v0.7.1"
command = "/garage"
args = [ "server" ]
image = "lxpz/garage_amd64:v0.3.0.1"
network_mode = "host"
volumes = [
"/mnt/storage/garage/data:/data",
"/mnt/ssd/garage/meta:/meta",
"secrets/garage.toml:/etc/garage.toml",
"/mnt/storage/garage/data:/garage/data",
"/mnt/ssd/garage/meta:/garage/meta",
"secrets/garage.toml:/garage/config.toml",
"secrets/garage-ca.crt:/garage/garage-ca.crt",
"secrets/garage.crt:/garage/garage.crt",
"secrets/garage.key:/garage/garage.key",
]
logging {
type = "journald"
@ -44,8 +45,22 @@ job "garage" {
destination = "secrets/garage.toml"
}
# --- secrets ---
template {
data = "{{ key \"secrets/garage/garage-ca.crt\" }}"
destination = "secrets/garage-ca.crt"
}
template {
data = "{{ key \"secrets/garage/garage.crt\" }}"
destination = "secrets/garage.crt"
}
template {
data = "{{ key \"secrets/garage/garage.key\" }}"
destination = "secrets/garage.key"
}
resources {
memory = 1500
memory = 800
cpu = 1000
}
@ -55,8 +70,9 @@ job "garage" {
service {
tags = [
"garage_api",
"tricot garage.deuxfleurs.fr",
"tricot *.garage.deuxfleurs.fr",
"traefik.enable=true",
"traefik.frontend.entryPoints=https,http",
"traefik.frontend.rule=Host:garage.deuxfleurs.fr"
]
port = 3900
address_mode = "driver"
@ -94,32 +110,6 @@ job "garage" {
}
}
service {
tags = [
"garage-web",
"tricot * 1",
"tricot-add-header Content-Security-Policy default-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://code.jquery.com/; frame-ancestors 'self'",
"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",
]
port = 3902
address_mode = "driver"
name = "garage-web"
check {
type = "tcp"
port = 3902
address_mode = "driver"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
restart {
interval = "30m"
attempts = 10

View file

@ -0,0 +1 @@
USER_LONG garage-ca.crt (generated with Garage's genkeys.sh script)

View file

@ -0,0 +1 @@
USER_LONG garage-ca.key (generated with Garage's genkeys.sh script)

View file

@ -0,0 +1 @@
USER_LONG garage.crt (generated with Garage's genkeys.sh script)

View file

@ -0,0 +1 @@
USER_LONG garage.key (generated with Garage's genkeys.sh script)

View file

@ -1 +0,0 @@
CMD_ONCE openssl rand -hex 32

View file

@ -59,7 +59,7 @@ listeners:
x_forwarded: false
resources:
- names: [client, federation]
- names: [client]
compress: true
- port: 8448
@ -83,7 +83,6 @@ listeners:
# Database configuration
database:
name: psycopg2
allow_unsafe_locale: false
args:
user: {{ key "secrets/chat/synapse/postgres_user" | trimSpace }}
password: {{ key "secrets/chat/synapse/postgres_pwd" | trimSpace }}

View file

@ -15,7 +15,7 @@ job "im" {
driver = "docker"
config {
image = "superboum/amd64_synapse:v53"
image = "superboum/amd64_synapse:v47"
network_mode = "host"
readonly_rootfs = true
ports = [ "client_port", "federation_port" ]
@ -95,10 +95,11 @@ job "im" {
address_mode = "host"
tags = [
"matrix",
"tricot im.deuxfleurs.fr/_matrix 100",
"tricot im.deuxfleurs.fr:443/_matrix 100",
"tricot im.deuxfleurs.fr/_synapse 100",
"tricot-add-header Access-Control-Allow-Origin *",
"traefik.enable=true",
"traefik.frontend.entryPoints=https",
"traefik.frontend.rule=Host:im.deuxfleurs.fr;PathPrefix:/_matrix,/_synapse",
"traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Origin: *",
"traefik.frontend.priority=100"
]
check {
type = "tcp"
@ -119,8 +120,10 @@ job "im" {
address_mode = "host"
tags = [
"matrix",
"tricot deuxfleurs.fr/_matrix 100",
"tricot deuxfleurs.fr:443/_matrix 100",
"traefik.enable=true",
"traefik.frontend.entryPoints=https",
"traefik.frontend.rule=Host:deuxfleurs.fr;PathPrefix:/_matrix",
"traefik.frontend.priority=100"
]
}
}
@ -130,7 +133,7 @@ job "im" {
driver = "docker"
config {
image = "superboum/amd64_synapse:v53"
image = "superboum/amd64_synapse:v47"
readonly_rootfs = true
command = "/usr/local/bin/matrix-s3-async"
work_dir = "/tmp"
@ -174,7 +177,7 @@ EOH
task "server" {
driver = "docker"
config {
image = "superboum/amd64_riotweb:v30"
image = "superboum/amd64_riotweb:v24"
ports = [ "web_port" ]
volumes = [
"secrets/config.json:/srv/http/config.json"
@ -193,8 +196,10 @@ EOH
service {
tags = [
"webstatic",
"tricot im.deuxfleurs.fr 10",
"tricot riot.deuxfleurs.fr 10",
"traefik.enable=true",
"traefik.frontend.entryPoints=https",
"traefik.frontend.rule=Host:im.deuxfleurs.fr,riot.deuxfleurs.fr;PathPrefix:/",
"traefik.frontend.priority=10"
]
port = "web_port"
address_mode = "host"

View file

@ -1,4 +1,4 @@
FROM debian:bookworm AS builder
FROM debian:buster AS builder
# unzip is required when executing the mvn package command
RUN apt-get update && \
@ -15,7 +15,7 @@ RUN mvn package -DskipTests -Dassembly.skipAssembly=false
RUN unzip target/jicofo-1.1-SNAPSHOT-archive.zip && \
mv jicofo-1.1-SNAPSHOT /srv/build
FROM debian:bookworm
FROM debian:buster
RUN apt-get update && \
apt-get install -y openjdk-11-jre-headless ca-certificates

View file

@ -3,7 +3,6 @@
update-ca-certificates -f
exec java \
-Dlog4j2.formatMsgNoLookups=true \
-Djdk.tls.ephemeralDHKeySize=2048 \
-Djava.util.logging.config.file=/usr/share/jicofo/lib/logging.properties \
-Dconfig.file=/etc/jitsi/jicofo.conf \

View file

@ -1,8 +1,8 @@
FROM debian:bookworm AS builder
FROM debian:buster AS builder
RUN apt-get update && \
apt-get install -y curl && \
curl -sL https://deb.nodesource.com/setup_16.x | bash - && \
curl -sL https://deb.nodesource.com/setup_14.x | bash - && \
apt-get install -y git nodejs make git unzip
ARG MEET_TAG
@ -12,7 +12,7 @@ WORKDIR jitsi-meet
RUN npm install && \
make
FROM debian:bookworm
FROM debian:buster
COPY --from=builder /jitsi-meet /srv/jitsi-meet
RUN apt-get update && \

View file

@ -0,0 +1,31 @@
From b327e580ab83110cdb52bc1d11687a096b8fc1df Mon Sep 17 00:00:00 2001
From: Quentin Dufour <quentin@dufour.io>
Date: Mon, 1 Feb 2021 07:16:50 +0100
Subject: [PATCH] Disable legacy parameters
---
jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt | 8 --------
1 file changed, 8 deletions(-)
diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
index df71f480..8f0ef9a5 100644
--- a/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
+++ b/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
@@ -62,14 +62,6 @@ fun main(args: Array<String>) {
// to be passed.
System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.JavaUtilLog")
- // Before initializing the application programming interfaces (APIs) of
- // Jitsi Videobridge, set any System properties which they use and which
- // may be specified by the command-line arguments.
- System.setProperty(
- Videobridge.REST_API_PNAME,
- cmdLine.getOptionValue("--apis").contains(Videobridge.REST_API).toString()
- )
-
// Reload the Typesafe config used by ice4j, because the original was initialized before the new system
// properties were set.
JitsiConfig.reloadNewConfig()
--
2.25.1

View file

@ -1,40 +0,0 @@
From 01507442620e5a57624c921b508eac7d572440d0 Mon Sep 17 00:00:00 2001
From: Quentin Dufour <quentin@deuxfleurs.fr>
Date: Tue, 25 Jan 2022 14:46:22 +0100
Subject: [PATCH] Remove deprecated argument
---
.../main/kotlin/org/jitsi/videobridge/Main.kt | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
index 4f6cb78..3db00f2 100644
--- a/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
+++ b/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
@@ -52,23 +52,6 @@ import org.jitsi.videobridge.websocket.singleton as webSocketServiceSingleton
fun main(args: Array<String>) {
val logger = LoggerImpl("org.jitsi.videobridge.Main")
- // We only support command line arguments for backward compatibility. The --apis options is the last one supported,
- // and it is only used to enable/disable the REST API (XMPP is only controlled through the config files).
- // TODO: fully remove support for --apis
- CmdLine().apply {
- parse(args)
- getOptionValue("--apis")?.let {
- logger.warn(
- "A deprecated command line argument (--apis) is present. Please use the config file to control the " +
- "REST API instead (see rest.md). Support for --apis will be removed in a future version."
- )
- System.setProperty(
- Videobridge.REST_API_PNAME,
- it.contains(Videobridge.REST_API).toString()
- )
- }
- }
-
setupMetaconfigLogger()
setSystemPropertyDefaults()
--
2.33.1

View file

@ -1,4 +1,4 @@
FROM debian:bookworm AS builder
FROM debian:buster AS builder
RUN apt-get update && \
apt-get install -y git unzip maven openjdk-11-jdk-headless
@ -8,15 +8,15 @@ RUN git clone --depth 1 --branch ${JVB_TAG} https://github.com/jitsi/jitsi-video
WORKDIR jitsi-videobridge
COPY *.patch .
RUN git apply 0001-Remove-deprecated-argument.patch
RUN git apply 0001-Disable-legacy-parameters.patch
RUN mvn package -DskipTests
RUN unzip jvb/target/jitsi-videobridge*.zip && \
mv jitsi-videobridge-*-SNAPSHOT build
FROM debian:bookworm
FROM debian:buster
RUN apt-get update && \
apt-get install -y openjdk-11-jre-headless curl iproute2
apt-get install -y openjdk-11-jre-headless curl
COPY --from=builder /jitsi-videobridge/build /usr/share/jvb
COPY jvb_run /usr/local/bin/jvb_run

View file

@ -12,7 +12,6 @@ fi
echo "NAT config: ${JITSI_NAT_LOCAL_IP} -> ${JITSI_NAT_PUBLIC_IP}"
exec java \
-Dlog4j2.formatMsgNoLookups=true \
-Djdk.tls.ephemeralDHKeySize=2048 \
-Djava.util.logging.config.file=/usr/share/jvb/lib/logging.properties \
-Dconfig.file=/etc/jitsi/videobridge.conf \

View file

@ -1,4 +1,4 @@
FROM debian:bookworm as builder
FROM debian:buster as builder
RUN apt-get update && \
apt-get install -y git unzip
@ -6,7 +6,7 @@ RUN apt-get update && \
ARG MEET_TAG
RUN git clone --depth 1 --branch ${MEET_TAG} https://github.com/jitsi/jitsi-meet/
FROM debian:bookworm
FROM debian:buster
ARG PROSODY_VERSION
RUN apt-get update && \

View file

@ -1,5 +1,5 @@
# some doc: https://www.nginx.com/resources/wiki/start/topics/examples/full/
error_log /dev/stderr info;
error_log /dev/stderr;
events {}
@ -39,10 +39,8 @@ http {
# inspired by https://raw.githubusercontent.com/jitsi/docker-jitsi-meet/master/web/rootfs/defaults/meet.conf
server {
#listen 0.0.0.0:{{ env "NOMAD_PORT_https_port" }} ssl http2 default_server;
#listen [::]:{{ env "NOMAD_PORT_https_port" }} ssl http2 default_server;
listen 0.0.0.0:{{ env "NOMAD_PORT_https_port" }} default_server;
listen [::]:{{ env "NOMAD_PORT_https_port" }} default_server;
listen 0.0.0.0:{{ env "NOMAD_PORT_https_port" }} ssl http2 default_server;
listen [::]:{{ env "NOMAD_PORT_https_port" }} ssl http2 default_server;
client_max_body_size 0;
server_name _;
@ -50,8 +48,8 @@ http {
ssi on;
ssi_types application/x-javascript application/javascript;
#ssl_certificate /etc/nginx/jitsi.crt;
#ssl_certificate_key /etc/nginx/jitsi.key;
ssl_certificate /etc/nginx/jitsi.crt;
ssl_certificate_key /etc/nginx/jitsi.key;
root /srv/jitsi-meet;
index index.html;
error_page 404 /static/404.html;
@ -92,7 +90,7 @@ http {
add_header 'Access-Control-Allow-Origin' '*';
proxy_pass http://{{ env "NOMAD_ADDR_bosh_port" }}/http-bind;
proxy_set_header X-Forwarded-For \$remote_addr;
#proxy_set_header Host \$http_host;
proxy_set_header Host \$http_host;
}
# not used yet VVV

View file

@ -21,7 +21,7 @@ job "jitsi" {
task "xmpp" {
driver = "docker"
config {
image = "superboum/amd64_jitsi_xmpp:v10"
image = "superboum/amd64_jitsi_xmpp:v9"
ports = [ "bosh_port", "xmpp_port" ]
network_mode = "host"
volumes = [
@ -102,7 +102,7 @@ EOF
task "front" {
driver = "docker"
config {
image = "superboum/amd64_jitsi_meet:v5"
image = "superboum/amd64_jitsi_meet:v4"
network_mode = "host"
ports = [ "https_port" ]
volumes = [
@ -144,8 +144,7 @@ EOF
"traefik.enable=true",
"traefik.frontend.entryPoints=https",
"traefik.frontend.rule=Host:jitsi.deuxfleurs.fr;PathPrefix:/",
"traefik.protocol=https",
"tricot jitsi.deuxfleurs.fr",
"traefik.protocol=https"
]
port = "https_port"
address_mode = "host"
@ -167,7 +166,7 @@ EOF
task "jicofo" {
driver = "docker"
config {
image = "superboum/amd64_jitsi_conference_focus:v9"
image = "superboum/amd64_jitsi_conference_focus:v7"
network_mode = "host"
volumes = [
"secrets/certs/jitsi.crt:/usr/local/share/ca-certificates/jitsi.crt",
@ -201,7 +200,7 @@ EOF
task "videobridge" {
driver = "docker"
config {
image = "superboum/amd64_jitsi_videobridge:v20"
image = "superboum/amd64_jitsi_videobridge:v17"
network_mode = "host"
ports = [ "video_port" ]
ulimit {

View file

@ -1,44 +0,0 @@
# Bridge accounts on various services
[rocketchat]
[rocketchat.dravedev]
Server = "https://rocketchat.drave.quebec:443"
Login = "{{ key "secrets/matterbridge/rocketchat.drave.quebec_user" | trimSpace }}"
Password = "{{ key "secrets/matterbridge/rocketchat.drave.quebec_pass" | trimSpace }}"
PrefixMessagesWithNick=false
RemoteNickFormat="{NICK}"
[matrix]
[matrix.deuxfleurs]
Server = "https://im.deuxfleurs.fr"
Login = "{{ key "secrets/matterbridge/im.deuxfleurs.fr_user" | trimSpace }}"
Password = "{{ key "secrets/matterbridge/im.deuxfleurs.fr_pass" | trimSpace }}"
PrefixMessagesWithNick=true
RemoteNickFormat="<{NICK}> "
[discord]
[discord.la-console]
Token = "{{ key "secrets/matterbridge/discord.com_token" | trimSpace }}"
Server = "872244032443678730"
RemoteNickFormat="{NICK}"
PrefixMessagesWithNick=false
AutoWebhooks = true
# Rooms we are bridging
[[gateway]]
name = "rfid"
enable = true
[[gateway.inout]]
account = "rocketchat.dravedev"
channel = "rfid"
[[gateway.inout]]
account = "matrix.deuxfleurs"
channel = "#rfid:deuxfleurs.fr"
[[gateway.inout]]
account = "discord.la-console"
channel = "rfid"

View file

@ -1,40 +0,0 @@
job "matterbridge" {
datacenters = ["dc1"]
type = "service"
priority = 90
constraint {
attribute = "${attr.cpu.arch}"
value = "amd64"
}
group "main" {
count = 1
task "bridge" {
driver = "docker"
config {
image = "42wim/matterbridge:1.23"
readonly_rootfs = true
volumes = [
"secrets/matterbridge.toml:/etc/matterbridge/matterbridge.toml"
]
}
resources {
memory = 200
}
template {
data = file("../config/matterbridge.toml")
destination = "secrets/matterbridge.toml"
}
restart {
attempts = 10
delay = "30s"
}
}
}
}

View file

@ -41,8 +41,7 @@ EOH
"platoo",
"traefik.enable=true",
"traefik.frontend.entryPoints=https",
"traefik.frontend.rule=Host:platoo.deuxfleurs.fr;PathPrefix:/",
"tricot platoo.deuxfleurs.fr",
"traefik.frontend.rule=Host:platoo.deuxfleurs.fr;PathPrefix:/"
]
port = "web_port"
address_mode = "host"

View file

@ -1,4 +1,4 @@
FROM rust:1.58.1-slim-bullseye as builder
FROM rust:1.54.0-slim-bullseye as builder
RUN apt-get update && \
apt-get install -y \
@ -10,7 +10,6 @@ RUN apt-get update && \
libpq-dev \
gettext \
git \
python \
curl \
gcc \
make \
@ -26,11 +25,11 @@ WORKDIR /opt/plume
RUN git checkout ${VERSION}
WORKDIR /opt/plume/script
RUN chmod a+x ./wasm-deps.sh && ./wasm-deps.sh
RUN chmod a+x ./wasm-deps.sh && sleep 1 && ./wasm-deps.sh
WORKDIR /opt/plume
RUN cargo install wasm-pack
RUN chmod a+x ./script/plume-front.sh && ./script/plume-front.sh
RUN chmod a+x ./script/plume-front.sh && sleep 1 && ./script/plume-front.sh
RUN cargo install --path ./ --force --no-default-features --features postgres
RUN cargo install --path plume-cli --force --no-default-features --features postgres
RUN cargo clean
@ -41,14 +40,13 @@ FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
libpq5 \
libssl1.1 \
rclone \
fuse
libssl1.1
WORKDIR /app
COPY --from=builder /opt/plume /app
COPY --from=builder /usr/local/cargo/bin/plm /usr/local/bin/
COPY --from=builder /usr/local/cargo/bin/plume /usr/local/bin/
COPY plm-start /usr/local/bin/
CMD ["plume"]
CMD ["plm-start"]

View file

@ -0,0 +1,9 @@
#!/bin/bash
until plm migration run;
do sleep 2;
done
plm search init
plm instance new --domain "$DOMAIN_NAME" --name "$INSTANCE_NAME" --private
plume

View file

@ -1,4 +1,4 @@
job "plume-blog" {
job "plume" {
datacenters = ["dc1"]
type = "service"
@ -15,22 +15,16 @@ job "plume-blog" {
}
task "plume" {
constraint {
attribute = "${attr.unique.hostname}"
operator = "="
value = "digitale"
}
driver = "docker"
config {
image = "superboum/plume:v8"
image = "superboum/plume:v4"
network_mode = "host"
ports = [ "web_port" ]
#command = "cat"
#args = [ "/dev/stdout" ]
volumes = [
"/mnt/ssd/plume/search_index:/app/search_index",
"/mnt/ssd/plume/media:/app/static/media"
"/mnt/glusterfs/plume/media:/app/static/media",
"/mnt/glusterfs/plume/search:/app/search_index"
]
}
@ -41,7 +35,7 @@ job "plume-blog" {
}
resources {
memory = 500
memory = 300
cpu = 100
}
@ -52,7 +46,6 @@ job "plume-blog" {
"traefik.enable=true",
"traefik.frontend.entryPoints=https,http",
"traefik.frontend.rule=Host:plume.deuxfleurs.fr",
"tricot plume.deuxfleurs.fr",
]
port = "web_port"
address_mode = "host"
@ -70,12 +63,6 @@ job "plume-blog" {
}
}
}
restart {
interval = "30m"
attempts = 20
delay = "15s"
mode = "delay"
}
}
}
}

View file

@ -1 +0,0 @@
USER Backup AWS access key ID

View file

@ -1 +0,0 @@
USER Backup AWS secret access key

View file

@ -1 +0,0 @@
USER Restic password to encrypt backups

View file

@ -1 +0,0 @@
USER Restic repository, eg. s3:https://s3.garage.tld

View file

@ -1,4 +1,4 @@
FROM golang:1.19.0-bullseye AS builder
FROM golang:1.13-buster AS builder
ARG STOLON_VERSION
WORKDIR /stolon
@ -9,7 +9,7 @@ COPY 0001-Add-max-rate-to-pg_basebackup.patch .
RUN git apply 0001-Add-max-rate-to-pg_basebackup.patch
RUN make && chmod +x /stolon/bin/*
FROM postgres:14.5-bullseye
FROM postgres:13.3-buster
COPY --from=builder /stolon/bin /usr/local/bin
USER postgres
ENTRYPOINT []

View file

@ -93,12 +93,6 @@ job "postgres13.3" {
"--pg-su-password", "${PG_SU_PWD}",
"--pg-repl-username", "${PG_REPL_USER}",
"--pg-repl-password", "${PG_REPL_PWD}",
/*
The postgres daemon accepts 0.0.0.0, ::, and * here but not Stolon.
Otherwise you will have the following error and your cluster will be broken (no replication)
WARN cmd/keeper.go:1979 provided --pg-listen-address "*": is not an ip address but a hostname. This will be advertized to the other components and may have undefined behaviors if resolved differently by other hosts
WARN cmd/keeper.go:1984 cannot resolve provided --pg-listen-address "*": lookup *: no such host
*/
"--pg-listen-address", "${attr.unique.network.ip-address}",
"--pg-port", "${NOMAD_PORT_psql_port}",
"--pg-bin-path", "/usr/lib/postgresql/13/bin/"

View file

@ -1,3 +1,3 @@
python-consul==1.1.0
python-ldap==3.4.0
python-ldap==3.3.1
passlib==1.7.4

View file

@ -1,15 +0,0 @@
{
pkgs ? import <nixpkgs> {}
}:
with pkgs; mkShell {
nativeBuildInputs = [
nomad
docker-compose
python39Packages.pip
python39Packages.ldap
python39Packages.consul
python39Packages.passlib
];
}

View file

@ -0,0 +1,59 @@
InsecureSkipVerify = true
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.admin]
address = ":8082"
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
compress = true
[entryPoints.https.tls]
minVersion = "VersionTLS12"
cipherSuites = [
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
]
[ping]
entrypoint = "admin"
[retry]
[acme]
email = "quentin@dufour.io"
storage = "traefik/acme/account"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
[api]
entryPoint = "admin"
dashboard = true
[consul]
endpoint = "172.17.0.1:8500"
watch = true
prefix = "traefik"
[consulCatalog]
endpoint = "172.17.0.1:8500"
prefix = "traefik"
domain = "web.deuxfleurs.fr"
exposedByDefault = false
[metrics]
[metrics.prometheus]
# -- below is for traefik 1.7 see https://doc.traefik.io/traefik/v1.7/configuration/metrics/
entryPoint = "admin"

View file

@ -0,0 +1,72 @@
job "frontend" {
datacenters = ["dc1"]
type = "service"
priority = 80
group "traefik" {
network {
port "http_port" { static = 80 }
port "https_port" { static = 443 }
port "admin_port" { static = 8082 }
}
task "server" {
driver = "docker"
config {
image = "amd64/traefik:1.7.20"
readonly_rootfs = true
network_mode = "host"
volumes = [
"secrets/traefik.toml:/etc/traefik/traefik.toml",
]
ports = [ "http_port", "https_port", "admin_port" ]
}
resources {
memory = 265
}
template {
data = file("../config/traefik.toml")
destination = "secrets/traefik.toml"
}
service {
name = "traefik-http"
port = "http_port"
tags = [ "(diplonat (tcp_port 80))" ]
address_mode = "host"
}
service {
name = "traefik-https"
port = "https_port"
tags = [ "(diplonat (tcp_port 443))" ]
address_mode = "host"
}
service {
name = "traefik-admin"
port = "admin_port"
address_mode = "host"
check {
type = "http"
protocol = "http"
port = 8082
address_mode = "driver"
path = "/ping"
interval = "60s"
timeout = "5s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = false
}
}
}
}
}
}

View file

@ -1,3 +0,0 @@
All documents from our operations guide have been moved to <https://guide.deuxfleurs.fr/operations/> (or in Git repository `guide.deuxfleurs.fr`).
Tous les documents de notre guide des opérations ont été déplacés sur <https://guide.deuxfleurs.fr/operations/> (ou dans le dépôt Git `guide.deuxfleurs.fr`).

View file

@ -0,0 +1,26 @@
## 1. Create a LDAP user and assign a password for your service
Go to guichet.deuxfleurs.fr
1. Everything takes place in `ou=services,ou=users,dc=deuxfleurs,dc=fr`
2. Create a new user, like `johny`
3. Generate a random password with `openssl rand -base64 32`
4. Hash it with `slappasswd`
5. Add a `userpassword` entry with the hash
This step can also be done using the automated tool `secretmgr.py` in the app folder.
## 2. Connect to postgres with the admin users
```bash
# 1. Launch ssh tunnel given in the README
# 2. Make sure you have postregsql client installed locally
psql -h localhost -U postgres -W postgres
```
## 3. Create the binded users with LDAP in postgres + the database
```sql
CREATE USER johny;
CREATE DATABASE amazingapp OWNER johny;
```

View file

@ -0,0 +1,72 @@
Spawn container:
```bash
docker run -t -i superboum/arm32v7_postgres:v6
# OR
docker run -t -i superboum/amd64_postgres:v1
```
Init with:
```
stolonctl \
--cluster-name pissenlit \
--store-backend=consul \
--store-endpoints http://consul.service.2.cluster.deuxfleurs.fr:8500 \
init \
'{ "initMode": "new", "pgHBA": [ "host all postgres all md5", "host replication replicator all md5", "host all all all ldap ldapserver=bottin.service.2.cluster.deuxfleurs.fr ldapbasedn=\"ou=users,dc=deuxfleurs, dc=fr\" ldapbinddn=\"<bind_dn>\" ldapbindpasswd=\"<bind_pwd>\" ldapsearchattribute=\"cn\"" ] }'
```
Then set appropriate permission on host:
```
chown -R 102:102 /mnt/storage/postgres/
```
(102 is the id of the postgres user used in Docker)
It might be improved by staying with root, then chmoding in an entrypoint and finally switching to user 102 before executing user's command.
Moreover it would enable the usage of the user namespace that shift the UIDs.
## Upgrading the cluster
To retreive the current stolon config:
```
stolonctl spec --cluster-name pissenlit --store-backend consul --store-endpoints http://consul.service.2.cluster.deuxfleurs.fr:8500
```
The important part for the LDAP:
```
{
"pgHBA": [
"host all postgres all md5",
"host replication replicator all md5",
"host all all all ldap ldapserver=bottin.service.2.cluster.deuxfleurs.fr ldapbasedn=\"ou=users,dc=deuxfleurs,dc=fr\" ldapbinddn=\"cn=admin,dc=deuxfleurs,dc=fr\" ldapbindpasswd=\"<REDACTED>\" ldapsearchattribute=\"cn\""
]
}
```
Once a patch is writen:
```
stolonctl --cluster-name pissenlit --store-backend consul --store-endpoints http://consul.service.2.cluster.deuxfleurs.fr:8500 update --patch -f /tmp/patch.json
```
## Log
- 2020-12-18 Activate pg\_rewind in stolon
```
stolonctl --cluster-name pissenlit --store-backend consul --store-endpoints http://consul.service.2.cluster.deuxfleurs.fr:8500 update --patch '{ "usePgrewind" : true }'
```
- 2021-03-14 Increase proxy timeout to cope with consul latency spikes
```
stolonctl --cluster-name pissenlit --store-backend consul --store-endpoints http://consul.service.2.cluster.deuxfleurs.fr:8500 update --patch '{ "proxyTimeout" : "120s" }'
```

View file

@ -0,0 +1,60 @@
# How to setup NextCloud
## First setup
It's complicated.
First, create a service user `nextcloud` and a database `nextcloud` it owns. Also create a Garage access key and bucket `nextcloud` it is allowed to use.
Fill in the following Consul keys with actual values:
```
secrets/nextcloud/db_user
secrets/nextcloud/db_pass
secrets/nextcloud/garage_access_key
secrets/nextcloud/garage_secret_key
```
Create the following Consul keys with empty values:
```
secrets/nextcloud/instance_id
secrets/nextcloud/password_salt
secrets/nextcloud/secret
```
Start the nextcloud.hcl nomad service. Enter the container and call `occ maintenance:install` with the correct database parameters as user `www-data`.
A possibility: call the admin user `nextcloud` and give it the same password as the `nextcloud` service user.
Cat the newly generated `config.php` file and copy the instance id, password salt, and secret from there to Consul
(they were generated by the install script and we want to keep them).
Restart the Nextcloud Nomad server.
You should now be able to log in to Nextcloud using the admin user (`nextcloud` if you called it that).
Go to the apps settings and enable desired apps.
## Configure LDAP login
LDAP login has to be configured from the admin interface. First, enable the LDAP authentification application.
Go to settings > LDAP/AD integration. Enter the following parameters:
- ldap server: `bottin2.service.2.cluster.deuxfleurs.fr`
- bind user: `cn=nextcloud,ou=services,ou=users,dc=deuxfleurs,dc=fr`
- bind password: password of the nextcloud service user
- base DN for users: `ou=users,dc=deuxfleurs,dc=fr`
- check "manually enter LDAP filters"
- in the users tab, edit LDAP query and set it to `(&(|(objectclass=inetOrgPerson))(|(memberof=cn=nextcloud,ou=groups,dc=deuxfleurs,dc=fr)))`
- in the login attributes tab, edit LDAP query and set it to `(&(&(|(objectclass=inetOrgPerson))(|(memberof=cn=nextcloud,ou=groups,dc=deuxfleurs,dc=fr)))(|(|(mailPrimaryAddress=%uid)(mail=%uid))(|(cn=%uid))))`
- in the groups tab, edit the LDAP query and set it to `(|(objectclass=groupOfNames))`
- in the advanced tab, enter the "directory setting" section and check/modify the following:
- user display name field: `displayname`
- base user tree: `ou=users,dc=deuxfleurs,dc=fr`
- user search attribute: `cn`
- groupe display name field: `displayname`
- **base group tree**: `ou=groups,dc=deuxfleurs,dc=fr`
- group search attribute: `cn`
That should be it. Go to the login attributes tab and enter a username (which should have been added to the nextcloud group) to check that nextcloud is able to find it and allows it for login.

20
op_guide/plume/README.md Normal file
View file

@ -0,0 +1,20 @@
## Creating a new Plume user
1. Bind nomad on your machine with SSH (check the README file at the root of this repo)
2. Go to http://127.0.0.1:4646
3. Select `plume` -> click `exec` button (top right)
4. Select `plume` on the left panel
5. Press `enter` to get a bash shell
6. Run:
```bash
plm users new \
--username alice \
--display-name Alice \
--bio Just an internet user \
--email alice@example.com \
--password s3cr3t
```
That's all folks, now you can use your new account at https://plume.deuxfleurs.fr

View file

@ -0,0 +1,45 @@
Le 20 janvier free a changé mon IP, un peu comme partout en France.
Ça concerne l'IPv4 et le préfixe IPv6.
Ici le bon vieux Bortzmoinsbien qui tweet : https://twitter.com/bortzmeyer/status/1351434290916155394
Max a update tout de suite l'IPv4 mais avec un TTL de 4h le temps de propagation est grand.
J'ai réduit les entrées sur les IP à 300 secondes, soit 5 minutes, le minimum chez Gandi, à voir si c'est une bonne idée.
Reste à update les IPv6, moins critiques pour le front facing mais utilisées pour le signaling en interne...
## Le fameux signaling
Ça pose un gros problème avec Nomad (et en moindre mesure avec Consul).
En effet, Nomad utilise l'IPv6 pour communiquer, il faut donc changer les IPs de tous les noeuds.
Problème ! On peut pas faire la migration au fur et à mesure car, changeant d'IP, les noeuds ne seront plus en mesure de communiquer.
On n'a pas envie de supprimer le cluster et d'en créer un nouveau car ça voudrait dire tout redéployer ce qui est long également (tous les fichiers HCL pour Nomad, tout le KV pour consul).
On ne peut pas non plus la faire à la bourrin en stoppant tous les cluster, changer son IP, puis redémarrer.
Enfin si, Consul accepte mais pas Nomad, qui lui va chercher à communiquer avec les anciennes IP et n'arrivera jamais à un consensus.
Au passage j'en ai profité pour changer le nom des noeuds car la dernière fois, Nomad n'avait PAS DU TOUT apprécié qu'un noeud ayant le même nom change d'IP. Ceci dit, si on utilise de facto le `peers.json` c'est peut être pas problématique. À tester.
Du coup, après moult réflexions, la silver bullet c'est la fonction outage recovery de nomad (consul l'a aussi au besoin).
Elle est ici : https://learn.hashicorp.com/tutorials/consul/recovery-outage
En gros, il faut arrêter tous les nodes.
Ensuite créer un fichier à ce path : `/var/lib/nomad/server/raft/peers.json`
Ne vous laissez pas perturber par le fichier `peers.info` à côté, il ne faut pas le toucher.
Après la grande question c'est de savoir si le cluster est en Raft v2 ou Raft v3.
Bon ben nous on était en Raft v2. Si vous vous trompez, au redémarrage Nomad va crasher avec une sale erreur :
```
nomad: failed to start Raft: error="recovery failed to parse peers.json: json: cannot unmarshal string into Go value of type raft.configEntry"
```
(je me suis trompé bien sûr).
Voilà, après il ne vous reste plus qu'à redémarrer et suivre les logs, cherchez bien la ligne où il dit qu'il a trouvé le peers.json.
## Les trucs à pas oublier
- Reconfigurer le backend KV de traefik (à voir à utiliser des DNS plutôt du coup)
- Reconfigurer l'IPv4 publique annoncée à Jitsi
## Ce qui reste à faire
- Mettre à jour les entrées DNS IPv6, ce qui devrait créer :
- digitale.machine.deuxfleurs.fr
- datura.machine.deuxfleurs.fr
- drosera.machine.deuxfleurs.fr
- Mettre à jour l'instance garage sur io

View file

@ -0,0 +1,15 @@
```
curl http://127.0.0.1:8500/v1/kv/traefik/acme/account/object?raw > traefik.gzip
gunzip -c traefik.gzip > traefik.json
cat traefik.json | jq '.DomainsCertificate.Certs[] | .Certificate.Domain, .Domains.Main'
# "alps.deuxfleurs.fr"
# "alps.deuxfleurs.fr"
# "cloud.deuxfleurs.fr"
# "cloud.deuxfleurs.fr"
# chaque NDD doit apparaitre 2x à la suite sinon fix comme suit
cat traefik.json | jq > traefik-new.json
vim traefik-new.json
# enlever les certifs corrompus, traefik les renouvellera automatiquement au démarrage
gzip -c traefik-new.json > traefik-new.gzip
curl --request PUT --data-binary @traefik-new.gzip http://127.0.0.1:8500/v1/kv/traefik/acme/account/object
```

View file

@ -0,0 +1,93 @@
How to update Matrix?
=====================
## 1. Build the new containers
Often, I update Riot Web and Synapse at the same time.
* Open `app/docker-compose.yml` and locate `riot` (the Element Web service) and `synapse` (the Matrix Synapse server). There are two things you need to do for each service:
* Set the `VERSION` argument to the target service version (e.g. `1.26.0` for Synapse). This argument is then used to template the Dockerfile.
The `VERSION` value should match a github release, the link to the corresponding release page is put as a comment next to the variable in the compose file;
* Tag the image with a new incremented version tag. For example: `superboum/amd64_riotweb:v17` will become `superboum/amd64_riotweb:v18`.
We use the docker hub to store our images. So, if you are not `superboum` you must change the name with your own handle, eg. `john/amd64_riotweb:v18`. This requires that you registered an account (named `john`) on https://hub.docker.com.
So, from now we expect you have:
* changed the `VERSION` value and `image` name/tag of `riot`
* changed the `VERSION` value and `image` name/tag of `synapse`
From the `/app` folder, you can now simply build and push the new images:
```bash
docker-compose build riot synapse
```
And then send them to the docker hub:
```
docker-compose push riot synapse
```
Don't forget to commit and push your changes before doing anything else!
## 2. Deploy the new containers
Now, we will edit the deployment file `app/im/deploy/im.hcl`.
Find where the image is defined in the file, for example Element-web will look like that:
```hcl
group "riotweb" {
count = 1
task "server" {
driver = "docker"
config {
image = "superboum/amd64_riotweb:v17"
port_map {
web_port = 8043
}
```
And replace the `image =` entry with its new version created above.
Do the same thing for the `synapse` service.
Now, you need a way to access the cluster to deploy this file.
To do this, you must bind nomad on your machine through a SSH tunnel.
Check the end of [the parent `README.md`](../README.md) to do it.
If you have access to the Nomad web UI when entering http://127.0.0.1:4646
you are ready to go.
You must have installed the Nomad command line tool on your machine (also explained in [the parent `README.md`](../README.md)).
Now, on your machine and from the `app/im/deploy` folder, you must be able to run:
```
nomad plan im.hcl
```
Check that the proposed diff corresponds to what you have in mind.
If it seems OK, just copy paste the `nomad job run ... im.hcl` command proposed as part of the output of the `nomad plan` command.
From now, it will take around ~2 minutes to deploy the new images.
You can follow the deployment from the Nomad UI.
Bear in mind that, once the deployment is done on Nomad, you may still need to wait some minutes that Traefik refreshes its configuration.
If everythings worked as intended, you can commit and push your deployment file.
If something went wrong, you must rollback your deployment.
1. First, find a working deployment with [nomad job history](https://www.nomadproject.io/docs/commands/job/history)
2. Revert to this deployment with [nomad job revert](https://www.nomadproject.io/docs/commands/job/revert)
Now, if the deployment failed, you should probably investigate what went wrong offline.
I built a test stack with docker-compose in `app/<service>/integration` that should help you out (for now, test suites are only written for plume and jitsi).

View file

@ -4,12 +4,9 @@
For each machine, **one by one** do:
- Check that cluster is healthy
- Check garage
- check that all nodes are online `docker exec -ti xxx /garage status`
- check that tables are in sync `docker exec -ti 63a4d7ecd795 /garage repair --yes tables`
- check garage logs
- no unknown errors or resync should be in progress
- the following line must appear `INFO garage_util::background > Worker exited: Repair worker`
- Check gluster
- `sudo gluster peer status`
- `sudo gluster volume status all` (check Online Col, only `Y` must appear)
- Check that Nomad is healthy
- `nomad server members`
- `nomad node status`
@ -20,5 +17,5 @@ For each machine, **one by one** do:
- Run `nomad node drain -enable -force -self`
- Reboot
- Run `nomad node drain -self -disable`
- Check that cluster is healthy (basically the whole first point)
- Check that cluster is healthy

View file

@ -14,12 +14,6 @@
- role: network
tags: net
- hosts: extra_nodes
serial: 1
roles:
- role: common
tags: base
- role: users
tags: account
- role: network
tags: net
# UNSAFE!! This section configures glusterfs. Once done, don't run it ever again as it may break stuff.
# - role: storage
# tags: sto

View file

@ -7,7 +7,7 @@ cluster_nodes:
ipv4: 192.168.0.2
gatewayv4: 192.168.0.254
ipv6: 2a01:e0a:260:b5b0::2
gatewayv6: 2a01:e0a:260:b5b0::1
gatewayv6: 2a01:e34:ec5c:dbe0::1
interface: eno1
dns_1: 212.27.40.240
dns_2: 212.27.40.241
@ -39,17 +39,15 @@ cluster_nodes:
dns_2: 212.27.40.241
ansible_python_interpreter: python3
extra_nodes:
hosts:
io:
ansible_host: io.machine.deuxfleurs.fr
ansible_port: 22
ansible_host: jupiter.site.deuxfleurs.fr
ansible_port: 110
ansible_become: true
ipv4: 192.168.1.57
ipv4: 192.168.1.2
gatewayv4: 192.168.1.1
ipv6: 2a01:e0a:5e4:1d0::57
gatewayv6: 2a01:e0a:5e4:1d0::2
ipv6: 2a02:8428:81d6:6901::2
gatewayv6: 2a02:8428:81d6:6901::1
interface: enp2s0
dns_1: 9.9.9.10
dns_2: 149.112.112.10
dns_1: 109.0.66.20
dns_2: 109.0.66.10
ansible_python_interpreter: python3

View file

@ -28,14 +28,14 @@
- bmon
- iftop
- iotop
# - docker.io # The bad way of installing Docker
- docker.io
- locales
- unzip
- tar
- tcpdump
- less
- parted
# - btrfs-tools # not in Debian 11
- btrfs-tools
- libnss-resolve
- net-tools
- strace
@ -43,15 +43,6 @@
- ethtool
- pciutils
- pv
- zstd
- miniupnpc
- rsync
- ncdu
- smartmontools
- ioping
- lm-sensors
- netcat
- sysstat
state: present
- name: "Passwordless sudo"

View file

@ -1,6 +1,6 @@
- name: "Set consul version"
set_fact:
consul_version: 1.11.4
consul_version: 1.9.1
- name: "Download and install Consul for x86_64"
unarchive:

View file

@ -10,12 +10,12 @@
-A INPUT -p tcp --dport 22 -j ACCEPT
# Diplonat needs everything open to communicate with IGD with the router
-A INPUT -s 192.168.0.254 -j ACCEPT
-A INPUT -s 192.168.1.254 -j ACCEPT
# Cluster
-A INPUT -s 192.168.0.2 -j ACCEPT
-A INPUT -s 192.168.0.3 -j ACCEPT
-A INPUT -s 192.168.0.4 -j ACCEPT
{% for selected_host in groups['cluster_nodes'] %}
-A INPUT -s {{ hostvars[selected_host]['ipv4'] }} -j ACCEPT
{% endfor %}
# Local
-A INPUT -i docker0 -j ACCEPT

View file

@ -16,9 +16,9 @@
-A INPUT -p tcp --dport 22 -j ACCEPT
# Cluster
-A INPUT -s 2a01:e0a:260:b5b0::2 -j ACCEPT
-A INPUT -s 2a01:e0a:260:b5b0::3 -j ACCEPT
-A INPUT -s 2a01:e0a:260:b5b0::4 -j ACCEPT
{% for selected_host in groups['cluster_nodes'] %}
-A INPUT -s {{ hostvars[selected_host]['ipv6'] }} -j ACCEPT
{% endfor %}
# Local
-A INPUT -i docker0 -j ACCEPT
@ -27,29 +27,19 @@
# Who is part of our trusted net?
# Max@Bruxelles
-A DEUXFLEURS-TRUSTED-NET -s 2a02:1811:3612:b300::0/64 -j DEUXFLEURS-TRUSTED-PORT
-A DEUXFLEURS-TRUSTED-NET -s 2a02:1811:3606:4800::0/64 -j DEUXFLEURS-TRUSTED-PORT
# Max@Suresnes
-A DEUXFLEURS-TRUSTED-NET -s 2a01:e0a:183:7be2::0/64 -j DEUXFLEURS-TRUSTED-PORT
# Max@OVH
-A DEUXFLEURS-TRUSTED-NET -s 2001:41d0:a:307c:ac7c::0/64 -j DEUXFLEURS-TRUSTED-PORT
# Jill@Rennes
-A DEUXFLEURS-TRUSTED-NET -s 2a01:e0a:5e4:1d0::0/64 -j DEUXFLEURS-TRUSTED-PORT
-A DEUXFLEURS-TRUSTED-NET -s 2001:41d0:a:307c:ac7c::/64 -j DEUXFLEURS-TRUSTED-PORT
# LX@Rennes
-A DEUXFLEURS-TRUSTED-NET -s 2a02:8428:81d6:6901::0/64 -j DEUXFLEURS-TRUSTED-PORT
# ADRN@Gandi
-A DEUXFLEURS-TRUSTED-NET -s 2001:4b98:dc0:41:216:3eff:fe9b:1afb/128 -j DEUXFLEURS-TRUSTED-PORT
# ADRN@Lille
-A DEUXFLEURS-TRUSTED-NET -s 2a01:e0a:e4:2dd0::0/64 -j DEUXFLEURS-TRUSTED-PORT
# Quentin@Rennes
-A DEUXFLEURS-TRUSTED-NET -s 2a01:e35:2fdc:dbe0::0/64 -j DEUXFLEURS-TRUSTED-PORT
# Erwan@Rennes
-A DEUXFLEURS-TRUSTED-NET -s 2a01:e0a:260:b5b0::0/64 -j DEUXFLEURS-TRUSTED-PORT
# LX@Orsay
-A DEUXFLEURS-TRUSTED-NET -s 2a06:a004:3025:1::0/64 -j DEUXFLEURS-TRUSTED-PORT
-A DEUXFLEURS-TRUSTED-NET -s 2a06:a003:515d:1::0/64 -j DEUXFLEURS-TRUSTED-PORT
-A DEUXFLEURS-TRUSTED-NET -s 2001:910:1204:1::0/64 -j DEUXFLEURS-TRUSTED-PORT
# Zorun@Nantes
-A DEUXFLEURS-TRUSTED-NET -s 2a00:5881:4008::/56 -j DEUXFLEURS-TRUSTED-PORT
# Quentin@Lyon
-A DEUXFLEURS-TRUSTED-NET -s 2a01:e0a:28f:5e60::/64 -j DEUXFLEURS-TRUSTED-PORT
# Source address is not trusted
-A DEUXFLEURS-TRUSTED-NET -j RETURN

View file

@ -1,6 +1,6 @@
- name: "Set nomad version"
set_fact:
nomad_version: 1.2.6
nomad_version: 1.0.2
- name: "Download and install Nomad for x86_64"
unarchive:

View file

@ -0,0 +1,3 @@
---
- name: umount gluster
shell: umount --force --lazy /mnt/glusterfs ; true

View file

@ -0,0 +1,72 @@
- name: "Add GlusterFS Repo Key"
apt_key:
url: https://download.gluster.org/pub/gluster/glusterfs/5/rsa.pub
state: present
- name: "Add GlusterFS official repository"
apt_repository:
repo: "deb [arch=amd64] https://download.gluster.org/pub/gluster/glusterfs/5/LATEST/Debian/buster/amd64/apt buster main"
state: present
filename: gluster
- name: "Install GlusterFS"
apt:
name:
- glusterfs-server
- glusterfs-client
state: present
- name: "Ensure Gluster Daemon started and enabled"
service:
name: glusterd
enabled: yes
state: started
- name: "Create directory for GlusterFS bricks"
file: path=/mnt/storage/glusterfs/brick1 recurse=yes state=directory
- name: "Create GlusterFS volumes"
gluster_volume:
state: present
name: donnees
bricks: /mnt/storage/glusterfs/brick1/g1
#rebalance: yes
redundancies: 1
disperses: 3
#replicas: 3
force: yes
options:
client.event-threads: "8"
server.event-threads: "8"
performance.stat-prefetch: "on"
nfs.disable: "on"
features.cache-invalidation: "on"
performance.client-io-threads: "on"
config.transport: tcp
performance.quick-read: "on"
performance.io-cache: "on"
nfs.export-volumes: "off"
cluster.lookup-optimize: "on"
cluster: "{% for selected_host in groups['cluster_nodes'] %}{{ hostvars[selected_host]['ipv4'] }}{{ ',' if not loop.last else '' }}{% endfor %}"
run_once: true
- name: "Create mountpoint"
file: path=/mnt/glusterfs recurse=yes state=directory
- name: "Flush handlers (umount glusterfs and restart ganesha)"
meta: flush_handlers
- name: "Add fstab entry"
tags: gluster-fstab
mount:
path: /mnt/glusterfs
src: "{{ ipv4 }}:/donnees"
fstype: glusterfs
opts: "defaults,_netdev,noauto,x-systemd.automount"
state: present
- name: Mount everything
command: mount -a
args:
warn: no

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPTsEgcOtb2bij+Ih8eg8ZqO7d3IMiWykv6deMzlSSS kokakiwi@kira

View file

@ -25,15 +25,10 @@ active_users:
- 'florian-key2.pub'
- username: 'adrien'
is_admin: true
is_admin: false
ssh_keys:
- 'adrien-key1.pub'
- username: 'kokakiwi'
is_admin: true
ssh_keys:
- 'jill-key1.pub'
disabled_users:
- 'john.doe'
- 'erwan'

View file

@ -1,13 +0,0 @@
cluster_nodes:
hosts:
spoutnik:
ansible_host: spoutnik.machine.deuxfleurs.fr
ansible_port: 220
ansible_become: true
ipv4: 192.168.0.40
gatewayv4: 192.168.0.1
interface: enp0s25
dns_1: 192.168.0.50
dns_2: 212.27.40.241
ansible_python_interpreter: python3
contact_name: ADRN