1
0
Fork 0
forked from pub-solar/infra

Compare commits

..

3 commits

105 changed files with 944 additions and 40501 deletions
.forgejo/workflows
.git-blame-ignore-revs.gitignoreREADME.md
docs
flake.lockflake.nix
hosts
lib
logins
modules
overlays
default.nix
pkgs/element-themes
public-keys
secrets

View file

@ -1,71 +1,17 @@
name: Flake checks
on: [pull_request]
env:
USER: ci
jobs:
Check:
runs-on: ubuntu-latest
runs-on: nix-flakes
steps:
- name: Check out repository code
uses: https://code.forgejo.org/actions/checkout@v4
- uses: https://github.com/nixbuild/nix-quick-install-action@v27
with:
load_nixConfig: false
nix_conf: |
substituters = https://cache.nixos.org/ https://nix-community.cachix.org
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=
keep-outputs = true
- name: Calculate flake.lock hash
id: flake-lock-hash
run: |
echo "hash=$(md5sum flake.lock | awk '{print $1}')" >> $GITHUB_OUTPUT
- name: Restore and cache Nix store
uses: https://github.com/nix-community/cache-nix-action@v4.0.3
id: nix-store-cache
with:
key: cache-${{ runner.os }}-nix-store-${{ steps.flake-lock-hash.outputs.hash }}
restore-keys: |
cache-${{ runner.os }}-nix-store-
gc-linux: true
gc-max-store-size-linux: 10000000000
purge-caches: true
purge-key: cache-${{ runner.os }}-nix-store-
purge-created: true
purge-created-max-age: 42
- name: Prepare cachix
uses: https://github.com/cachix/cachix-action@v14
uses: https://github.com/cachix/cachix-action@v12
with:
name: pub-solar
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
useDaemon: false
- name: Run flake checks
run: |
# Prevent cache garbage collection by creating GC roots
for target in $(nix flake show --json --all-systems | jq '
.["nixosConfigurations"] |
to_entries[] |
.key
' | tr -d '"'
); do
nix --print-build-logs --verbose --accept-flake-config --access-tokens '' \
build --out-link ./result-$target ".#nixosConfigurations.${target}.config.system.build.toplevel"
done
nix --print-build-logs --verbose --accept-flake-config --access-tokens '' flake check
# Add GC roots for flake inputs, too
# https://github.com/NixOS/nix/issues/4250#issuecomment-1146878407
mkdir --parents "$NIX_USER_PROFILE_DIR"
gc_root_prefix="$NIX_USER_PROFILE_DIR"/infra-flake-
echo "Adding gcroots flake inputs with prefix $gc_root_prefix ..."
nix flake archive --json 2>/dev/null | jq --raw-output '.inputs | to_entries[] | "ln --force --symbolic --no-target-directory "+.value.path+" \"'"$gc_root_prefix"'"+.key+"\""' | while read -r line; do
eval "$line"
done
nix --print-build-logs --verbose --accept-flake-config flake check

View file

@ -1,2 +0,0 @@
# Apply treewide formatting with nixpkgs-fmt
815033c764660e1468b1564a02570bad0f84f77a

1
.gitignore vendored
View file

@ -3,4 +3,3 @@
.direnv
.terraform
*.plan
result

View file

@ -1,6 +1,6 @@
# The pub.solar infrastructure
This repository contains almost all of the configuration for the whole pub.solar infrastructure. Our goal is to have everything, from host configurations to Terraform DNS in this repository.
This repository contains all almost all of the configuration for the whole pub.solar infrastructure. Our goal is to have everything, from host configurations to Terraform DNS in this repository.
The architecture we are working towards is a vast simplification of what it was before: one dedicated Hetzner server running [NixOS](https://nixos.org/) with all services. Offsite backups go to several different locations with [restic](https://github.com/restic/restic).

View file

@ -1,37 +0,0 @@
# Adminstrative access
People with admin access to the infrastructure are added to [`logins/admins.nix`](../logins/admins.nix). This is a attrset with the following structure:
```
{
<username> = {
sshPubKeys = {
<name> = <pubkey-string>;
};
wireguardDevices = [
{
publicKey = <pubkey-string>;
allowedIPs = [ "10.7.6.<ip-address>/32" "fd00:fae:fae:fae:fae:<ip-address>::/96" ];
}
}];
secretEncryptionKeys = {
<name> = <encryption-key-string>;
};
};
}
```
# SSH Access
SSH is not reachable from the open internet. Instead, SSH Port 22 is protected by a wireguard VPN network. Thus, to get root access on the servers, at least two pieces of information have to be added to the admins config:
1. **SSH Public key**: self-explanatory. Add your public key to your user attrset under `sshPubKeys`.
2. **Wireguard device**: each wireguard device has two parts: the public key and the IP addresses it should have in the wireguard network. The pub.solar wireguard network is spaced under `10.7.6.0/24` and `fd00:fae:fae:fae:fae::/80`. To add your device, it's best to choose a free number between 200 and 255 and use that in both the ipv4 and ipv6 ranges: `10.7.6.<ip-address>/32` `fd00:fae:fae:fae:fae:<ip-address>::/96`. For more information on how to generate keypairs, see [the NixOS Wireguard docs](https://nixos.wiki/wiki/WireGuard#Generate_keypair).
# Secret encryption
Deployment secrets are added to the repository in encrypted files. To be able to work with these encrypted files, your public key(s) will have to be added to your user attrset under `secretEncryptionKeys`.
See also the docs on [working with secrets](./secrets.md).

View file

@ -1,61 +0,0 @@
# Process for handling a deletion request
### Keycloak
Required:
- auth.pub.solar ops user credentials
- SSH access to host nachtigall
```
ssh barkeeper@nachtigall.pub.solar
sudo --user keycloak kcadm.sh config credentials --config /tmp/kcadm.config --server http://localhost:8080 --realm pub.solar --user ops
# Take note of user id in response from following command
sudo --user keycloak kcadm.sh get --config /tmp/kcadm.config users --realm pub.solar --query email=<email-address>
# To avoid impersonification, we deactivate the account by resetting the password and email address
# Use user id from previous command, for example
sudo --user keycloak kcadm.sh update --config /tmp/kcadm.config users/2ec6f173-3c10-4b82-9808-e2f2d393ff11/reset-password --realm pub.solar --set type=password --set value=<random-password> --no-merge
sudo --user keycloak kcadm.sh update --config /tmp/kcadm.config users/2ec6f173-3c10-4b82-9808-e2f2d393ff11 --realm pub.solar --set email=<username>@deactivated.pub.solar
```
Docs: https://www.keycloak.org/docs/latest/server_admin/index.html#updating-a-user
### Nextcloud
```
ssh barkeeper@nachtigall.pub.solar
nextcloud-occ user:delete <username>
```
Docs: https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html#user-commands-label
### Mastodon
```
ssh barkeeper@nachtigall.pub.solar
sudo -u mastodon mastodon-tootctl accounts delete --email <mail-address>
```
Docs: https://docs.joinmastodon.org/admin/tootctl/#accounts-delete
### Forgejo
```
ssh barkeeper@nachtigall.pub.solar
sudo -u gitea gitea admin user delete --config /var/lib/forgejo/custom/conf/app.ini --purge --email <mail-address>
```
Docs: https://forgejo.org/docs/latest/admin/command-line/#delete
### Matrix
```
ssh bartender@matrix.pub.solar -p 2020
curl --header "Authorization: Bearer <admin-access-token>" --request POST http://172.18.0.3:8008/_synapse/admin/v1/deactivate/@<username>:pub.solar --data '{"erase": true}'
```
Docs: https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#deactivate-account
### OpenBikeSensor
Not implemented, see: https://github.com/openbikesensor/portal/issues/95

View file

@ -1,32 +1,20 @@
# Deploying new versions
We use [deploy-rs](https://github.com/serokell/deploy-rs) to deploy changes.
Currently this process is not automated, so configuration changes will have to
be manually deployed.
We use [deploy-rs](https://github.com/serokell/deploy-rs) to deploy changes. Currently this process is not automated, so configuration changes will have to be manually deployed.
To deploy, make sure you have a [working development shell](./development-shell.md).
Then, run `deploy-rs` with the hostname of the server you want to deploy:
To deploy, make sure you have a [working development shell](./development-shell.md). Then, run `deploy-rs` with the hostname of the server you want to deploy:
For nachtigall.pub.solar:
```
deploy --targets '.#nachtigall' --magic-rollback false --auto-rollback false
deploy '.#nachtigall'
```
For flora-6.pub.solar:
```
deploy --targets '.#flora-6' --magic-rollback false --auto-rollback false
deploy '.#flora-6'
```
Usually we skip all rollback functionality, but if you want to deploy a change
that might lock you out, e.g. to SSH, it might make sense to set these to `true`.
You'll need to have SSH Access to the boxes to be able to do this.
To skip flake checks, e.g. because you already ran them manually before
deployment, add the flag `--skip-checks` at the end of the command.
`--dry-activate` can be used to only put all files in place without switching,
to enable switching to the new config quickly at a later moment.
You'll need to have SSH Access to the boxes to be able to run `deploy`.
### Getting SSH access
See [administrative-access.md](./administrative-access.md).
### SSH access
Ensure your SSH public key is in place [here](./public-keys/admins.nix) and was deployed by someone with access.

View file

@ -3,16 +3,9 @@
Clone this repository:
```
git clone https://git.pub.solar/pub-solar/infra.git
cd infra
git clone https://git.pub.solar/pub-solar/infra-new.git
```
then, install [the package manager nix](https://nixos.org/download).
Finally, run:
```
nix develop
```
This will install a development shell (devshell) with all required tools.
Finally, run `nix develop` in this repo. This will install a development shell that has all required tooling available.

View file

@ -1,44 +1,17 @@
# Changing DNS entries
Our current DNS provider is [namecheap](https://www.namecheap.com/).
We use [Terraform](https://www.terraform.io) to declaratively manage our pub.solar DNS records.
### Initial setup
Skip this step if you already have a `triton` profile setup.
```
triton profile create
```
Please follow https://docs.greenbaum.cloud/en/devops/triton-cli.html for the details.
You will need to setup the following [namecheap API credentials](https://www.namecheap.com/support/api/intro),
look for "namecheap API key" in the pub.solar Keepass database.
```
NAMECHEAP_API_KEY
NAMECHEAP_API_USER
NAMECHEAP_USER_NAME
```
You will probably also need to add your external IP to the [API allow list](https://ap.www.namecheap.com/settings/tools/apiaccess/whitelisted-ips).
```
dig -4 ip @dns.toys
```
Now, change into the terraform directory and initialize the terraform providers.
Change into the terraform directory and initialize the terraform providers.
```
cd terraform
export TRITON_KEY_ID=$(cat ~/.config/triton/profiles.d/lev-1-pub_solar.json | jq --raw-output .keyId)
cat ~/.config/triton/profiles.d/lev-1-pub_solar.json | grep keyId
export TRITON_KEY_ID=
terraform init
```
Make your changes, e.g. in `dns.tf`.
```
$EDITOR dns.tf
```
Plan your changes using:
```
terraform plan -out pub-solar-infra.plan
@ -48,11 +21,3 @@ After verification, apply your changes with:
```
terraform apply "pub-solar-infra.plan"
```
### Useful links
We use the Manta remote backend to save the terraform state for collaboration.
- https://www.terraform.io/language/v1.2.x/settings/backends/manta
Namecheap Terraform provider docs:
- https://registry.terraform.io/providers/namecheap/namecheap/latest/docs

View file

@ -1,19 +0,0 @@
# Drone CI
We currently use two CI systems, [drone CI](https://drone.io), reachable via
https://ci.pub.solar and [Forgejo Actions](https://forgejo.org/docs/latest/user/actions/),
which UI is integrated into https://git.pub.solar, for example
https://git.pub.solar/pub-solar/infra/actions.
### Signing the `.drone.yml` file
Login to https://ci.pub.solar by clicking on the user icon in the bottom left.
After logging in, you can view your personal API token by clicking on the same
icon. If you're using the nix [development-shell](./development-shell.md), the
`drone` command will already be installed.
```
export DRONE_TOKEN=<your-drone-api-token>
drone --token $DRONE_TOKEN sign --save pub-solar/os
```

View file

@ -1,7 +0,0 @@
# Forgejo Actions
Admin docs
https://forgejo.org/docs/latest/admin/actions/
User guide
https://forgejo.org/docs/latest/user/actions/

View file

@ -1,22 +0,0 @@
# Process for getting a list of email addresses of all keycloak users
### Keycloak
Required:
- auth.pub.solar ops user credentials
- SSH access to host nachtigall
```
ssh barkeeper@nachtigall.pub.solar
sudo --user keycloak kcadm.sh get users \
-r pub.solar \
--offset 0 \
--limit 1000 \
--no-config \
--server http://localhost:8080 \
--realm master \
--user admin \
--password <admin password> \
> keycloak-user-list.json
jq -r '.[].email' < keycloak-user-list.json
```

View file

@ -1,33 +0,0 @@
# Process for resetting keycloak user passwords
### Keycloak
Required:
- auth.pub.solar ops user credentials
- SSH access to host nachtigall
```
ssh barkeeper@nachtigall.pub.solar
mkdir /tmp/keycloak-credential-reset
sudo --user keycloak kcadm.sh config credentials --config /tmp/kcadm.config --server http://localhost:8080 --realm pub.solar --user ops
sudo --user keycloak kcadm.sh get --config /tmp/kcadm.config users --realm pub.solar | jq --raw-output '.[] | .id' > /tmp/keycloak-credential-reset/all-uuids
for UUID in $(cat /tmp/keycloak-credential-reset/all-uuids); do
sudo --user keycloak kcadm.sh get --config /tmp/kcadm.config users/$UUID/credentials --realm pub.solar > /tmp/keycloak-credential-reset/$UUID
done
mkdir /tmp/keycloak-credential-reset/accounts-with-creds
find /tmp/keycloak-credential-reset -type f -size +3c -exec mv '{}' /tmp/keycloak-credential-reset/accounts-with-creds/ \;
rm -r /tmp/keycloak-credential-reset/accounts-with-creds/
find /tmp/keycloak-credential-reset/ -type f -exec basename '{}' \; > /tmp/keycloak-credential-reset/accounts-without-credentials
vim /tmp/keycloak-credential-reset/accounts-without-credentials
for UUID in $(cat /tmp/keycloak-credential-reset/accounts-without-credentials); do
sudo --user keycloak kcadm.sh update --config /tmp/kcadm.config users/$UUID/reset-password --target-realm pub.solar --set type=password --set value=$(< /dev/urandom tr -dc A-Z-a-z-0-9 | head -c${1:-32};echo;) --set temporary=true --no-merge
done
```

View file

@ -1,19 +0,0 @@
# Process for updating a keycloak realm via CLI
### Keycloak
Required:
- auth.pub.solar ops user credentials
- SSH access to host nachtigall
```
ssh barkeeper@nachtigall.pub.solar
sudo -u keycloak kcadm.sh config credentials --config /tmp/kcadm.config --server http://localhost:8080 --realm master --user admin
sudo -u keycloak kcadm.sh get --config /tmp/kcadm.config realms/pub.solar
sudo -u keycloak kcadm.sh update --config /tmp/kcadm.config realms/pub.solar -s browserFlow='Webauthn Browser'
sudo -u keycloak kcadm.sh get --config /tmp/kcadm.config realms/pub.solar
```
Source: https://keycloak.ch/keycloak-tutorials/tutorial-webauthn/

View file

@ -1,31 +0,0 @@
# Updating mediawiki docker container
See the [mediawiki-oidc-docker repository](https://git.pub.solar/pub-solar/mediawiki-oidc-docker#updating-the-docker-image)
for instructions on updating our customized mediawiki docker image.
To deploy a new docker image to `nachtigall`, first bump the mediawiki version
of the docker image tag in `hosts/nachtigall/apps/mediawiki.nix` (search for
`image`).
Next, push your changes to https://git.pub.solar and get them reviewed and
approved.
After approval, create a fresh backup of the database and deploy the changes to
`nachtigall`:
```
ssh barkeeper@nachtigall.pub.solar
sudo -u postgres pg_dump --create -Fc mediawiki > mediawiki-db-$(date +%F).dump
exit
```
```
deploy --targets '.#nachtigall'
```
Then, finalize the update by running the database migration script:
```
ssh barkeeper@nachtigall.pub.solar
docker exec -it mediawiki bash
php maintenance/run.php update.php
```

View file

@ -1,43 +0,0 @@
Use these commands to show the diff between versions for planning updates:
```
OLD_CLOSURE=$(nix build --print-out-paths .#nixosConfigurations.nachtigall.config.system.build.toplevel)
/nix/store/c6wqp1vzvyr3bq2igd8p460613ddwrmj-nixos-system-nachtigall-23.11.20231201.5de0b32
```
```
nix flake update
...
```
```
NEW_CLOSURE=$(nix build --print-out-paths .#nixosConfigurations.nachtigall.config.system.build.toplevel)
/nix/store/xynyf943d2nw1wgawhzxh13xkkf1whb0-nixos-system-nachtigall-23.11.20231210.781e2a9
```
```
nix store diff-closures $OLD_CLOSURE $NEW_CLOSURE
cpupower: 6.1.64 → 6.1.66
element-web: 1.11.47 → 1.11.51, +5325.9 KiB
element-web-wrapped: 1.11.47 → 1.11.51
initrd-linux: 6.1.64 → 6.1.66
keycloak: 22.0.5 → 23.0.0, +15201.4 KiB
linux: 6.1.64, 6.1.64-modules → 6.1.66, 6.1.66-modules, +8.3 KiB
mastodon: 4.2.1 → 4.2.3, +16.3 KiB
mastodon-gems: 4.2.1 → 4.2.3, +14.4 KiB
mastodon-modules: 4.2.1 → 4.2.3
nix: +18.8 KiB
nixos-manual: +73.6 KiB
nixos-system-nachtigall: 23.11.20231201.5de0b32 → 23.11.20231210.781e2a9
opensearch: 2.11.0 → 2.11.1, +560.5 KiB
owncast: 0.1.1 → 0.1.2, +798.9 KiB
ruby3.2.2-bcp47_spec: ∅ → 0.2.1, +13.6 KiB
ruby3.2.2-json-canonicalization: 0.3.2 → 1.0.0
ruby3.2.2-json-ld: 3.2.5 → 3.3.1
ruby3.2.2-rdf: 3.2.11 → 3.3.1
samba: +12.5 KiB
source: +3888.1 KiB
wrapped-ruby-mastodon-gems: 4.2.1 → 4.2.3
zfs-kernel: 2.2.1-6.1.64 → 2.2.2-6.1.66
zfs-user: 2.2.1 → 2.2.2
```

View file

@ -1,11 +0,0 @@
# Privacy hardening
Some default options in the services we run are not as privacy friendly as they can be. Oftentimes, services assume they are running for an organization in which everyone knows (or wants to know) everyone else. However, when running a public service accounts should be hidden from other users.
## Nextcloud account leaking
By default, accounts are visible globally across the instance. To prevent this, go into the administration settings -> Sharing. Check the option saying "Restrict users to only share with users in their group".
## Forgejo email leaking
By default, emails are visible on the explore page for other logged in users. We have disabled this in the config by setting `service.DEFAULT_KEEP_EMAIL_PRIVATE` to `true`.

View file

@ -1,5 +1 @@
# Working with secrets
Secrets are handled with [agenix](https://github.com/ryantm/agenix). To be able to view secrets, your public key will have to be added to the admins config. See [Administrative Access](./administrative-access.md) on how to do this.
For a comprehensive tutorial, see [the agenix repository](https://github.com/ryantm/agenix?tab=readme-ov-file#tutorial).

3
docs/ssh.md Normal file
View file

@ -0,0 +1,3 @@
# SSH Access
SSH Access is granted by adding a public key to [`public-keys/admins.nix`](../public-keys/admins.nix). This change will then have to be deployed to all hosts by an existing key. The keys will also grant access to the initrd SSH Server to enable remote unlock.

189
flake.lock generated
View file

@ -10,15 +10,14 @@
],
"nixpkgs": [
"nixpkgs"
],
"systems": "systems"
]
},
"locked": {
"lastModified": 1712079060,
"narHash": "sha256-/JdiT9t+zzjChc5qQiF+jhrVhRt8figYH29rZO7pFe4=",
"lastModified": 1696775529,
"narHash": "sha256-TYlE4B0ktPtlJJF9IFxTWrEeq+XKG8Ny0gc2FGEAdj0=",
"owner": "ryantm",
"repo": "agenix",
"rev": "1381a759b205dff7a6818733118d02253340fd5e",
"rev": "daf42cb35b2dc614d1551e37f96406e4c4a2d3e4",
"type": "github"
},
"original": {
@ -36,11 +35,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1711973905,
"narHash": "sha256-UFKME/N1pbUtn+2Aqnk+agUt8CekbpuqwzljivfIme8=",
"lastModified": 1698921442,
"narHash": "sha256-7KmvhQ7FuXlT/wG4zjTssap6maVqeAMBdtel+VjClSM=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "88b3059b020da69cbe16526b8d639bd5e0b51c8b",
"rev": "660180bbbeae7d60dad5a92b30858306945fd427",
"type": "github"
},
"original": {
@ -51,18 +50,18 @@
},
"devshell": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"keycloak-theme-pub-solar",
"nixpkgs"
]
],
"systems": "systems"
},
"locked": {
"lastModified": 1705332421,
"narHash": "sha256-USpGLPme1IuqG78JNqSaRabilwkCyHmVWY0M9vYyqEA=",
"lastModified": 1688380630,
"narHash": "sha256-8ilApWVb1mAi4439zS3iFeIT0ODlbrifm/fegWwgHjA=",
"owner": "numtide",
"repo": "devshell",
"rev": "83cb93d6d063ad290beee669f4badf9914cc16ec",
"rev": "f9238ec3d75cefbb2b42a44948c4e8fb1ae9a205",
"type": "github"
},
"original": {
@ -71,31 +70,14 @@
"type": "github"
}
},
"element-themes": {
"flake": false,
"locked": {
"lastModified": 1707755689,
"narHash": "sha256-pMwrpZwLp7tw0nBbz/ENVJ2LoN9jIxEfjcq7OXoiKEw=",
"owner": "aaronraimist",
"repo": "element-themes",
"rev": "2368b58c16d2c4aabb82a245f036d228cbb6e5f5",
"type": "github"
},
"original": {
"owner": "aaronraimist",
"ref": "master",
"repo": "element-themes",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"type": "github"
},
"original": {
@ -109,11 +91,11 @@
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"lastModified": 1698882062,
"narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"rev": "8c9fa2545007b49a5db5f650ae91f227672c3877",
"type": "github"
},
"original": {
@ -124,14 +106,14 @@
},
"flake-utils": {
"inputs": {
"systems": "systems_3"
"systems": "systems_2"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"lastModified": 1689068808,
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
"type": "github"
},
"original": {
@ -141,24 +123,6 @@
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_4"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
@ -180,16 +144,16 @@
]
},
"locked": {
"lastModified": 1714043624,
"narHash": "sha256-Xn2r0Jv95TswvPlvamCC46wwNo8ALjRCMBJbGykdhcM=",
"lastModified": 1699748081,
"narHash": "sha256-MOmMapBydd7MTjhX4eeQZzKlCABWw8W6iSHSG4OeFKE=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "86853e31dc1b62c6eeed11c667e8cdd0285d4411",
"rev": "04bac349d585c9df38d78e0285b780a140dc74a4",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-23.11",
"ref": "release-23.05",
"repo": "home-manager",
"type": "github"
}
@ -197,17 +161,17 @@
"keycloak-theme-pub-solar": {
"inputs": {
"devshell": "devshell",
"flake-utils": "flake-utils_2",
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1707424749,
"narHash": "sha256-eTvts5E3zmD4/DoAI9KedQjRwica0cg36wwIVp1NWbM=",
"lastModified": 1689875310,
"narHash": "sha256-gJxh8fVX24nZXBxstZcrzZhMRFG9jyOnQEfkgoRr39I=",
"ref": "main",
"rev": "1202a23c205b3c07a5feb5caf6813f21b3c69307",
"revCount": 30,
"rev": "c2c86bbf9855f16a231a596b75b443232a7b9395",
"revCount": 24,
"type": "git",
"url": "https://git.pub.solar/pub-solar/keycloak-theme"
},
@ -217,6 +181,22 @@
"url": "https://git.pub.solar/pub-solar/keycloak-theme"
}
},
"mastodon-fork": {
"locked": {
"lastModified": 1698490885,
"narHash": "sha256-Ic2YgJ7vlAoiihho4pJgHewIubIZQpv1L8ePRB1wfG4=",
"owner": "teutat3s",
"repo": "nixpkgs",
"rev": "534d90c65614f05e543fd11b3f4acd748704a625",
"type": "github"
},
"original": {
"owner": "teutat3s",
"ref": "mastodon-4.2.1",
"repo": "nixpkgs",
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
@ -224,11 +204,11 @@
]
},
"locked": {
"lastModified": 1713946171,
"narHash": "sha256-lc75rgRQLdp4Dzogv5cfqOg6qYc5Rp83oedF2t0kDp8=",
"lastModified": 1699867978,
"narHash": "sha256-+arl45HUOcBdKiRGrKXZYXDyBQ6MQGkYPZa/28f6Yzo=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "230a197063de9287128e2c68a7a4b0cd7d0b50a7",
"rev": "e67f2bf515343da378c3f82f098df8ca01bccc5f",
"type": "github"
},
"original": {
@ -240,11 +220,11 @@
},
"nixos-flake": {
"locked": {
"lastModified": 1711376798,
"narHash": "sha256-37wawZGSX/dD1rn7TwFJhUdpozC2VPEQXetpfpK/D+w=",
"lastModified": 1699802281,
"narHash": "sha256-kfR7z4so9s9vsYHT3Q9kU/GvYYCVeBsQH1h7EpSvkHg=",
"owner": "srid",
"repo": "nixos-flake",
"rev": "7b19503e7f8c7cc0884fc2fbd669c0cc2e05aef5",
"rev": "40010feda1ac1afdcc2571ef550ef3de44926b0e",
"type": "github"
},
"original": {
@ -255,16 +235,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1713995372,
"narHash": "sha256-fFE3M0vCoiSwCX02z8VF58jXFRj9enYUSTqjyHAjrds=",
"lastModified": 1699994397,
"narHash": "sha256-xxNeIcMNMXH2EA9IAX6Cny+50mvY22LhIBiGZV363gc=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "dd37924974b9202f8226ed5d74a252a9785aedf8",
"rev": "d4b5a67bbe9ef750bd2fdffd4cad400dd5553af8",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-23.11",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
@ -288,11 +268,11 @@
"nixpkgs-lib": {
"locked": {
"dir": "lib",
"lastModified": 1711703276,
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
"lastModified": 1698611440,
"narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
"rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735",
"type": "github"
},
"original": {
@ -307,10 +287,10 @@
"inputs": {
"agenix": "agenix",
"deploy-rs": "deploy-rs",
"element-themes": "element-themes",
"flake-parts": "flake-parts",
"home-manager": "home-manager",
"keycloak-theme-pub-solar": "keycloak-theme-pub-solar",
"mastodon-fork": "mastodon-fork",
"nix-darwin": "nix-darwin",
"nixos-flake": "nixos-flake",
"nixpkgs": "nixpkgs",
@ -349,39 +329,9 @@
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_4": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"triton-vmtools": {
"inputs": {
"flake-utils": "flake-utils_3",
"flake-utils": "flake-utils_2",
"nixpkgs": [
"nixpkgs"
]
@ -405,11 +355,11 @@
},
"unstable": {
"locked": {
"lastModified": 1713895582,
"narHash": "sha256-cfh1hi+6muQMbi9acOlju3V1gl8BEaZBXBR9jQfQi4U=",
"lastModified": 1699781429,
"narHash": "sha256-UYefjidASiLORAjIvVsUHG6WBtRhM67kTjEY4XfZOFs=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "572af610f6151fd41c212f897c71f7056e3fb518",
"rev": "e44462d6021bfe23dfb24b775cc7c390844f773d",
"type": "github"
},
"original": {
@ -420,15 +370,12 @@
}
},
"utils": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {

View file

@ -1,15 +1,16 @@
{
inputs = {
# Track channels with commits tested and built by hydra
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
unstable.url = "github:nixos/nixpkgs/nixos-unstable";
mastodon-fork.url = "github:teutat3s/nixpkgs/mastodon-4.2.1";
nixpkgs-2205.url = "github:nixos/nixpkgs/nixos-22.05";
nix-darwin.url = "github:lnl7/nix-darwin/master";
nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
home-manager.url = "github:nix-community/home-manager/release-23.11";
home-manager.url = "github:nix-community/home-manager/release-23.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
flake-parts.url = "github:hercules-ci/flake-parts";
@ -28,9 +29,6 @@
triton-vmtools.url = "git+https://git.pub.solar/pub-solar/infra-vintage?ref=main&dir=vmtools";
triton-vmtools.inputs.nixpkgs.follows = "nixpkgs";
element-themes.url = "github:aaronraimist/element-themes/master";
element-themes.flake = false;
};
outputs = inputs@{ self, ... }:
@ -39,7 +37,7 @@
imports = [
inputs.nixos-flake.flakeModule
./logins
./public-keys
./lib
./overlays
./modules
@ -63,9 +61,9 @@
deploy-rs
nixpkgs-fmt
agenix
age-plugin-yubikey
cachix
editorconfig-checker
nix
nodePackages.prettier
nvfetcher
shellcheck
@ -73,7 +71,6 @@
treefmt
nixos-generators
inputs.nixpkgs-2205.legacyPackages.${system}.terraform
jq
];
};
};
@ -81,20 +78,21 @@
flake =
let
username = "barkeeper";
in
{
in {
inherit username;
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) inputs.deploy-rs.lib;
deploy.nodes = self.lib.deploy.mkDeployNodes self.nixosConfigurations {
nachtigall = {
hostname = "10.7.6.1";
# hostname is set in hosts/nachtigall/networking.nix
sshUser = username;
};
flora-6 = {
hostname = "10.7.6.2";
hostname = "flora-6.pub.solar";
sshUser = username;
# Example
#sshOpts = [ "-p" "19999" ];
};
};
};

View file

@ -1,28 +1,28 @@
{ self, ... }:
{
flake = {
nixosConfigurations = {
nachtigall = self.nixos-flake.lib.mkLinuxSystem {
imports = [
self.inputs.agenix.nixosModules.default
self.nixosModules.home-manager
./nachtigall
self.nixosModules.overlays
self.nixosModules.unlock-zfs-on-boot
self.nixosModules.core
self.nixosModules.docker
];
};
{ self, ... }:
{
flake = {
nixosConfigurations = {
nachtigall = self.nixos-flake.lib.mkLinuxSystem {
imports = [
self.inputs.agenix.nixosModules.default
self.nixosModules.home-manager
./nachtigall
self.nixosModules.overlays
self.nixosModules.unlock-zfs-on-boot
self.nixosModules.core
self.nixosModules.docker
];
};
flora-6 = self.nixos-flake.lib.mkLinuxSystem {
imports = [
self.inputs.agenix.nixosModules.default
self.nixosModules.home-manager
./flora-6
self.nixosModules.overlays
self.nixosModules.core
];
flora-6 = self.nixos-flake.lib.mkLinuxSystem {
imports = [
self.inputs.agenix.nixosModules.default
self.nixosModules.home-manager
./flora-6
self.nixosModules.overlays
self.nixosModules.core
];
};
};
};
};
}
}

View file

@ -1,260 +0,0 @@
{ lib }:
let
# docker's filesystems disappear quickly, leading to false positives
deviceFilter = ''path!~"^(/var/lib/docker|/nix/store).*"'';
in
lib.mapAttrsToList
(name: opts: {
alert = name;
expr = opts.condition;
for = opts.time or "2m";
labels = { };
annotations.description = opts.description;
})
({
# prometheus_too_many_restarts = {
# condition = ''changes(process_start_time_seconds{job=~"prometheus|alertmanager"}[15m]) > 2'';
# description = "Prometheus has restarted more than twice in the last 15 minutes. It might be crashlooping.";
# };
# alert_manager_config_not_synced = {
# condition = ''count(count_values("config_hash", alertmanager_config_hash)) > 1'';
# description = "Configurations of AlertManager cluster instances are out of sync.";
# };
#alert_manager_e2e_dead_man_switch = {
# condition = "vector(1)";
# description = "Prometheus DeadManSwitch is an always-firing alert. It's used as an end-to-end test of Prometheus through the Alertmanager.";
#};
# prometheus_not_connected_to_alertmanager = {
# condition = "prometheus_notifications_alertmanagers_discovered < 1";
# description = "Prometheus cannot connect the alertmanager\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
# };
# prometheus_rule_evaluation_failures = {
# condition = "increase(prometheus_rule_evaluation_failures_total[3m]) > 0";
# description = "Prometheus encountered {{ $value }} rule evaluation failures, leading to potentially ignored alerts.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
# };
# prometheus_template_expansion_failures = {
# condition = "increase(prometheus_template_text_expansion_failures_total[3m]) > 0";
# time = "0m";
# description = "Prometheus encountered {{ $value }} template text expansion failures\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
# };
# promtail_file_lagging = {
# condition = ''abs(promtail_file_bytes_total - promtail_read_bytes_total) > 1e6'';
# time = "15m";
# description = ''{{ $labels.instance }} {{ $labels.job }} {{ $labels.path }} has been lagging by more than 1MB for more than 15m.'';
# };
filesystem_full_80percent = {
condition = ''
100 - ((node_filesystem_avail_bytes{fstype!="rootfs",mountpoint="/"} * 100) / node_filesystem_size_bytes{fstype!="rootfs",mountpoint="/"}) > 80'';
time = "10m";
description =
"{{$labels.instance}} device {{$labels.device}} on {{$labels.mountpoint}} got less than 20% space left on its filesystem.";
};
# filesystem_inodes_full = {
# condition = ''disk_inodes_free / disk_inodes_total < 0.10'';
# time = "10m";
# description = "{{$labels.instance}} device {{$labels.device}} on {{$labels.mountpoint}} got less than 10% inodes left on its filesystem.";
# };
# daily_task_not_run = {
# # give 6 hours grace period
# condition = ''time() - task_last_run{state="ok",frequency="daily"} > (24 + 6) * 60 * 60'';
# description = "{{$labels.instance}}: {{$labels.name}} was not run in the last 24h";
# };
# daily_task_failed = {
# condition = ''task_last_run{state="fail"}'';
# description = "{{$labels.instance}}: {{$labels.name}} failed to run";
# };
# } // (lib.genAttrs [
# "borgbackup-turingmachine"
# "borgbackup-eve"
# "borgbackup-datastore"
# ]
# (name: {
# condition = ''absent_over_time(task_last_run{name="${name}"}[1d])'';
# description = "status of ${name} is unknown: no data for a day";
# }))
# // {
# borgbackup_matchbox_not_run = {
# # give 6 hours grace period
# condition = ''time() - task_last_run{state="ok",frequency="daily",name="borgbackup-matchbox"} > 7 * 24 * 60 * 60'';
# description = "{{$labels.instance}}: {{$labels.name}} was not run in the last week";
# };
# borgbackup_matchbox = {
# condition = ''absent_over_time(task_last_run{name="borgbackup-matchbox"}[7d])'';
# description = "status of borgbackup-matchbox is unknown: no data for a week";
# };
# homeassistant = {
# condition = ''
# homeassistant_entity_available{domain="persistent_notification", entity!="persistent_notification.http_login"} >= 0'';
# description =
# "homeassistant notification {{$labels.entity}} ({{$labels.friendly_name}}): {{$value}}";
# };
swap_using_20percent = {
condition =
"node_memory_SwapTotal_bytes - (node_memory_SwapCached_bytes + node_memory_SwapFree_bytes) > node_memory_SwapTotal_bytes * 0.2";
time = "30m";
description =
"{{$labels.instance}} is using 20% of its swap space for at least 30 minutes.";
};
systemd_service_failed = {
condition = ''node_systemd_unit_state{state="failed"} == 1'';
description =
"{{$labels.instance}} failed to (re)start service {{$labels.name}}.";
};
restic_backup_too_old = {
condition = ''(time() - restic_snapshots_latest_time)/(60*60) > 24'';
description = "{{$labels.instance}} not backed up for more than 24 hours. ({{$value}})";
};
host_down = {
condition = ''up{job="node-stats", instance!~"ahorn.wireguard:9100|kartoffel.wireguard:9100|mega.wireguard:9100"} == 0'';
description = "{{$labels.instance}} is down!";
};
# service_not_running = {
# condition = ''systemd_units_active_code{name=~"teamspeak3-server.service|tt-rss.service", sub!="running"}'';
# description = "{{$labels.instance}} should have a running {{$labels.name}}.";
# };
ram_using_90percent = {
condition =
"node_memory_Buffers_bytes + node_memory_MemFree_bytes + node_memory_Cached_bytes < node_memory_MemTotal_bytes * 0.1";
time = "1h";
description =
"{{$labels.instance}} is using at least 90% of its RAM for at least 1 hour.";
};
cpu_using_90percent = {
condition = ''
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) >= 90'';
time = "10m";
description =
"{{$labels.instance}} is running with cpu usage > 90% for at least 10 minutes: {{$value}}";
};
reboot = {
condition = "node_boot_time_seconds < 300";
description = "{{$labels.instance}} just rebooted.";
};
uptime = {
condition = "(time() - node_boot_time_seconds ) / (60*60*24) > 30";
description =
"Uptime monster: {{$labels.instance}} has been up for more than 30 days.";
};
flake_nixpkgs_outdated = {
condition = ''
(time() - flake_input_last_modified{input="nixpkgs"}) / (60*60*24) > 30'';
description =
"Nixpkgs outdated: Nixpkgs on {{$labels.instance}} has not been updated in 30 days";
};
/* ping = {
condition = "ping_result_code{type!='mobile'} != 0";
description = "{{$labels.url}}: ping from {{$labels.instance}} has failed!";
};
ping_high_latency = {
condition = "ping_average_response_ms{type!='mobile'} > 5000";
description = "{{$labels.instance}}: ping probe from {{$labels.source}} is encountering high latency!";
};
*/
http_status = {
condition = ''
probe_http_status_code{instance!~"https://megaclan3000.de"} != 200'';
description =
"http request failed from {{$labels.instance}}: {{$labels.result}}!";
};
/* http_match_failed = {
condition = "http_response_response_string_match == 0";
description = "{{$labels.server}} : http body not as expected; status code: {{$labels.status_code}}!";
};
dns_query = {
condition = "dns_query_result_code != 0";
description = "{{$labels.domain}} : could retrieve A record {{$labels.instance}} from server {{$labels.server}}: {{$labels.result}}!";
};
secure_dns_query = {
condition = "secure_dns_state != 0";
description = "{{$labels.domain}} : could retrieve A record {{$labels.instance}} from server {{$labels.server}}: {{$labels.result}} for protocol {{$labels.protocol}}!";
};
connection_failed = {
condition = "net_response_result_code != 0";
description = "{{$labels.server}}: connection to {{$labels.port}}({{$labels.protocol}}) failed from {{$labels.instance}}";
};
healthchecks = {
condition = "hc_check_up == 0";
description = "{{$labels.instance}}: healtcheck {{$labels.job}} fails!";
};
*/
cert_expiry = {
condition = "(probe_ssl_earliest_cert_expiry - time())/(3600*24) < 30";
description =
"{{$labels.instance}}: The TLS certificate will expire in less than 30 days: {{$value}}s";
};
# ignore devices that disabled S.M.A.R.T (example if attached via USB)
# smart_errors = {
# condition = ''smart_device_health_ok{enabled!="Disabled"} != 1'';
# description =
# "{{$labels.instance}}: S.M.A.R.T reports: {{$labels.device}} ({{$labels.model}}) has errors.";
# };
oom_kills = {
condition = "increase(node_vmstat_oom_kill[5m]) > 0";
description = "{{$labels.instance}}: OOM kill detected";
};
/* unusual_disk_read_latency = {
condition =
"rate(diskio_read_time[1m]) / rate(diskio_reads[1m]) > 0.1 and rate(diskio_reads[1m]) > 0";
description = ''
{{$labels.instance}}: Disk latency is growing (read operations > 100ms)
'';
};
unusual_disk_write_latency = {
condition =
"rate(diskio_write_time[1m]) / rate(diskio_write[1m]) > 0.1 and rate(diskio_write[1m]) > 0";
description = ''
{{$labels.instance}}: Disk latency is growing (write operations > 100ms)
'';
};
*/
host_memory_under_memory_pressure = {
condition = "rate(node_vmstat_pgmajfault[1m]) > 1000";
description =
"{{$labels.instance}}: The node is under heavy memory pressure. High rate of major page faults: {{$value}}";
};
# ext4_errors = {
# condition = "ext4_errors_value > 0";
# description =
# "{{$labels.instance}}: ext4 has reported {{$value}} I/O errors: check /sys/fs/ext4/*/errors_count";
# };
# alerts_silences_changed = {
# condition = ''abs(delta(alertmanager_silences{state="active"}[1h])) >= 1'';
# description =
# "alertmanager: number of active silences has changed: {{$value}}";
# };
})

View file

@ -1,8 +1,9 @@
{ config
, lib
, pkgs
, flake
, ...
{
config,
lib,
pkgs,
flake,
...
}:
{
systemd.tmpfiles.rules = [
@ -26,33 +27,6 @@
reverse_proxy :4000
'';
};
"flora-6.pub.solar" = {
logFormat = lib.mkForce ''
output discard
'';
extraConfig = ''
basicauth * {
hakkonaut $2a$14$mmIAy/Ezm6YGohUtXa2mWeW6Bcw1MQXPhrRbz14jAD2iUu3oob/t.
}
reverse_proxy :${toString config.services.loki.configuration.server.http_listen_port}
'';
};
"alerts.pub.solar" = {
logFormat = lib.mkForce ''
output discard
'';
extraConfig = ''
reverse_proxy 10.7.6.2:${toString config.services.prometheus.alertmanager.port}
'';
};
"grafana.pub.solar" = {
logFormat = lib.mkForce ''
output discard
'';
extraConfig = ''
reverse_proxy :${toString config.services.grafana.settings.server.http_port}
'';
};
"obs-portal.pub.solar" = {
logFormat = lib.mkForce ''
output discard
@ -63,5 +37,5 @@
};
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
networking.firewall.allowedTCPPorts = [80 443];
}

View file

@ -1,8 +1,9 @@
{ config
, lib
, pkgs
, flake
, ...
{
config,
lib,
pkgs,
flake,
...
}: {
age.secrets.drone-secrets = {
file = "${flake.self}/secrets/drone-secrets.age";
@ -24,24 +25,22 @@
isSystemUser = true;
};
users.groups.drone = { };
users.groups.drone = {};
systemd.tmpfiles.rules = [
"d '/var/lib/drone-db' 0750 drone drone - -"
];
systemd.services."docker-network-drone" =
let
docker = config.virtualisation.oci-containers.backend;
dockerBin = "${pkgs.${docker}}/bin/${docker}";
in
{
serviceConfig.Type = "oneshot";
before = [ "docker-drone-server.service" ];
script = ''
${dockerBin} network inspect drone-net >/dev/null 2>&1 || ${dockerBin} network create drone-net --subnet 172.20.0.0/24
'';
};
systemd.services."docker-network-drone" = let
docker = config.virtualisation.oci-containers.backend;
dockerBin = "${pkgs.${docker}}/bin/${docker}";
in {
serviceConfig.Type = "oneshot";
before = ["docker-drone-server.service"];
script = ''
${dockerBin} network inspect drone-net >/dev/null 2>&1 || ${dockerBin} network create drone-net --subnet 172.20.0.0/24
'';
};
virtualisation = {
docker = {
@ -72,13 +71,12 @@
autoStart = true;
user = "994";
ports = [
"127.0.0.1:4000:80"
"4000:80"
];
dependsOn = [ "drone-db" ];
dependsOn = ["drone-db"];
extraOptions = [
"--network=drone-net"
"--pull=always"
"--add-host=nachtigall.pub.solar:10.7.6.1"
];
environment = {
DRONE_GITEA_SERVER = "https://git.pub.solar";
@ -98,11 +96,10 @@
volumes = [
"/var/run/docker.sock:/var/run/docker.sock"
];
dependsOn = [ "drone-db" ];
dependsOn = ["drone-db"];
extraOptions = [
"--network=drone-net"
"--pull=always"
"--add-host=nachtigall.pub.solar:10.7.6.1"
];
environment = {
DRONE_RPC_HOST = "ci.pub.solar";

View file

@ -1,60 +1,30 @@
{ config
, lib
, pkgs
, flake
, ...
{
config,
lib,
pkgs,
flake,
...
}: {
age.secrets.forgejo-actions-runner-token = {
file = "${flake.self}/secrets/forgejo-actions-runner-token.age";
mode = "644";
};
# Trust docker bridge interface traffic
# Needed for the docker runner to communicate with the act_runner cache
networking.firewall.trustedInterfaces = [ "br-+" ];
users.users.gitea-runner = {
home = "/var/lib/gitea-runner/flora-6";
useDefaultShell = true;
group = "gitea-runner";
isSystemUser = true;
};
users.groups.gitea-runner = {};
systemd.services."gitea-runner-flora\\x2d6".serviceConfig = {
DynamicUser = lib.mkForce false;
};
systemd.tmpfiles.rules = [
"d '/data/gitea-actions-runner' 0750 gitea-runner gitea-runner - -"
"d '/var/lib/gitea-runner' 0750 gitea-runner gitea-runner - -"
];
# forgejo actions runner
# https://forgejo.org/docs/latest/admin/actions/
# https://docs.gitea.com/usage/actions/quickstart
services.gitea-actions-runner = {
package = pkgs.forgejo-runner;
package = pkgs.forgejo-actions-runner;
instances."flora-6" = {
enable = true;
name = config.networking.hostName;
url = "https://git.pub.solar";
tokenFile = config.age.secrets.forgejo-actions-runner-token.path;
settings = {
cache = {
enabled = true;
dir = "/data/gitea-actions-runner/actcache";
host = "";
port = 0;
external_server = "";
};
};
labels = [
# provide a debian 12 bookworm base with Node.js for actions
"debian-latest:docker://git.pub.solar/pub-solar/actions-base-image:20-bookworm"
"debian-latest:docker://node:20-bookworm"
# fake the ubuntu name, commonly used in actions examples
"ubuntu-latest:docker://git.pub.solar/pub-solar/actions-base-image:20-bookworm"
"ubuntu-latest:docker://node:20-bookworm"
# alpine with Node.js
"alpine-latest:docker://node:20-alpine"
# nix flakes enabled image with Node.js

File diff suppressed because it is too large Load diff

View file

@ -1,112 +0,0 @@
{ config
, lib
, pkgs
, flake
, ...
}: {
age.secrets.grafana-admin-password = {
file = "${flake.self}/secrets/grafana-admin-password.age";
mode = "644";
owner = "grafana";
};
age.secrets.grafana-smtp-password = {
file = "${flake.self}/secrets/grafana-smtp-password.age";
mode = "644";
owner = "grafana";
};
age.secrets.grafana-keycloak-client-secret = {
file = "${flake.self}/secrets/grafana-keycloak-client-secret.age";
mode = "644";
owner = "grafana";
};
environment.etc = {
"grafana-dashboards/node-exporter-full_rev33.json" = {
source = ./grafana-dashboards/node-exporter-full_rev33.json;
group = "grafana";
user = "grafana";
};
"grafana-dashboards/synapse.json" = {
source = ./grafana-dashboards/synapse.json;
group = "grafana";
user = "grafana";
};
};
services.grafana = {
enable = true;
settings = {
server = {
# Listening Address
http_addr = "127.0.0.1";
# and Port
http_port = 3000;
# Grafana needs to know on which domain and URL it's running
domain = "grafana.pub.solar";
root_url = "https://grafana.pub.solar";
enable_gzip = true;
};
smtp = {
enabled = true;
host = "mail.greenbaum.zone:465";
user = "admins@pub.solar";
password = "\$__file{${config.age.secrets.grafana-smtp-password.path}}";
from_address = "no-reply@pub.solar";
from_name = "grafana.pub.solar";
ehlo_identity = "flora-6.pub.solar";
};
security = {
admin_email = "crew@pub.solar";
admin_password = "\$__file{${config.age.secrets.grafana-admin-password.path}}";
};
"auth.generic_oauth" = {
enabled = true;
name = "pub.solar ID";
allow_sign_up = true;
client_id = "grafana";
client_secret = "\$__file{${config.age.secrets.grafana-keycloak-client-secret.path}}";
scopes = "openid email profile offline_access roles";
email_attribute_path = "email";
login_attribute_path = "preferred_username";
name_attribute_path = "full_name";
auth_url = "https://auth.pub.solar/realms/pub.solar/protocol/openid-connect/auth";
token_url = "https://auth.pub.solar/realms/pub.solar/protocol/openid-connect/token";
api_url = "https://auth.pub.solar/realms/pub.solar/protocol/openid-connect/userinfo";
role_attribute_path = "contains(roles[*], 'admin') && 'GrafanaAdmin' || 'Viewer'";
allow_assign_grafana_admin = true;
};
};
provision = {
enable = true;
datasources = {
settings = {
datasources = [
{
name = "Prometheus";
type = "prometheus";
access = "proxy";
url = "http://127.0.0.1:${toString config.services.prometheus.port}";
isDefault = true;
}
{
name = "Loki";
type = "loki";
access = "proxy";
url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}";
}
];
};
};
dashboards = {
settings = {
providers = [
{
name = "pub.solar Dashboards";
options.path = "/etc/grafana-dashboards";
}
];
};
};
};
};
}

View file

@ -1,84 +0,0 @@
{ config
, lib
, pkgs
, flake
, ...
}: {
# source: https://gist.github.com/rickhull/895b0cb38fdd537c1078a858cf15d63e
# https://grafana.com/docs/loki/latest/configure/examples/#1-local-configuration-exampleyaml
services.loki = {
enable = true;
configuration = {
server.http_listen_port = 3100;
auth_enabled = false;
common = {
ring = {
instance_addr = "127.0.0.1";
kvstore = {
store = "inmemory";
};
};
replication_factor = 1;
path_prefix = "/var/lib/loki";
storage = {
filesystem = {
chunks_directory = "chunks/";
rules_directory = "rules/";
};
};
};
# Keep logs for 4 weeks
# https://grafana.com/docs/loki/latest/operations/storage/retention/
limits_config.retention_period = "4w";
compactor = {
shared_store = "filesystem";
compaction_interval = "10m";
retention_enabled = true;
retention_delete_delay = "2h";
retention_delete_worker_count = 150;
};
schema_config = {
configs = [{
from = "2020-05-15";
store = "boltdb-shipper";
object_store = "filesystem";
schema = "v11";
index = {
prefix = "index_";
period = "24h";
};
}];
};
};
};
services.promtail = {
enable = true;
configuration = {
server = {
http_listen_port = 9080;
grpc_listen_port = 0;
};
positions = {
filename = "/tmp/positions.yaml";
};
clients = [{
url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push";
}];
scrape_configs = [{
job_name = "journal";
journal = {
max_age = "24h";
labels = {
job = "systemd-journal";
host = "flora-6";
};
};
relabel_configs = [{
source_labels = [ "__journal__systemd_unit" ];
target_label = "unit";
}];
}];
};
};
}

View file

@ -1,114 +0,0 @@
{ config
, lib
, pkgs
, flake
, ...
}: {
age.secrets.nachtigall-metrics-prometheus-basic-auth-password = {
file = "${flake.self}/secrets/nachtigall-metrics-prometheus-basic-auth-password.age";
mode = "600";
owner = "prometheus";
};
services.prometheus = {
enable = true;
port = 9001;
exporters = {
node = {
enable = true;
enabledCollectors = [ "systemd" ];
port = 9002;
};
};
globalConfig = {
scrape_interval = "10s";
scrape_timeout = "9s";
};
scrapeConfigs = [
{
job_name = "node-exporter-http";
static_configs = [{
targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ];
labels = {
instance = "flora-6";
};
}];
}
{
job_name = "node-exporter-https";
scheme = "https";
metrics_path = "/metrics";
basic_auth = {
username = "hakkonaut";
password_file = "${config.age.secrets.nachtigall-metrics-prometheus-basic-auth-password.path}";
};
static_configs = [{
targets = [ "nachtigall.pub.solar" ];
labels = {
instance = "nachtigall";
};
}];
}
{
job_name = "matrix-synapse";
scheme = "https";
metrics_path = "/_synapse/metrics";
basic_auth = {
username = "hakkonaut";
password_file = "${config.age.secrets.nachtigall-metrics-prometheus-basic-auth-password.path}";
};
static_configs = [{
targets = [ "nachtigall.pub.solar" ];
labels = {
instance = "nachtigall";
};
}];
}
];
ruleFiles = [
(pkgs.writeText "prometheus-rules.yml" (builtins.toJSON {
groups = [{
name = "alerting-rules";
rules = import ./alert-rules.nix { inherit lib; };
}];
}))
];
alertmanagers = [{ static_configs = [{ targets = [ "localhost:9093" ]; }]; }];
alertmanager = {
enable = true;
# port = 9093; # Default
webExternalUrl = "https://alerts.pub.solar"; # TODO use a proper url?
# environmentFile = "${config.age.secrets.nachtigall-alertmanager-envfile.path}";
configuration = {
route = {
receiver = "all";
group_by = [ "instance" ];
group_wait = "30s";
group_interval = "2m";
repeat_interval = "24h";
};
receivers = [{
name = "all";
# Email config documentation: https://prometheus.io/docs/alerting/latest/configuration/#email_config
email_configs = [{
send_resolved = true;
to = "TODO";
from = "alerts@pub.solar";
smarthost = "TODO";
auth_username = "TODO";
auth_password_file = "${config.age.secrets.nachtigall-alertmanager-smtp-password.path}";
require_tls = true;
}];
# TODO:
# For matrix notifications, look into: https://github.com/pinpox/matrix-hook and add a webhook
# webhook_configs = [ { url = "http://127.0.0.1:11000/alert"; } ];
}];
};
};
};
}

View file

@ -1,13 +1,21 @@
{ config
, lib
, pkgs
, flake
, ...
}:
let
psCfg = config.pub-solar;
in
{
config,
lib,
pkgs,
flake,
...
}: let
psCfg = config.pub-solar;
in {
imports = [
"${flake.inputs.unstable}/nixos/modules/services/continuous-integration/gitea-actions-runner.nix"
"${flake.inputs.unstable}/nixos/modules/services/web-servers/caddy/default.nix"
];
disabledModules = [
"services/continuous-integration/gitea-actions-runner.nix"
"services/web-servers/caddy/default.nix"
];
config = {
# Override nix.conf for more agressive garbage collection
nix.extraOptions = lib.mkForce ''
@ -30,14 +38,6 @@ in
# Force getting the hostname from cloud-init
networking.hostName = lib.mkDefault "";
# We use cloud-init to configure networking, this option should fix
# systemd-networkd-wait-online timeouts
#systemd.services."systemd-networkd".environment.SYSTEMD_LOG_LEVEL = "debug";
systemd.network.wait-online.ignoredInterfaces = [
"docker0"
"wg-ssh"
];
# List services that you want to enable:
services.cloud-init.enable = true;
services.cloud-init.ext4.enable = true;

View file

@ -2,19 +2,14 @@
{
imports =
[
# Include the results of the hardware scan.
[ # Include the results of the hardware scan.
./hardware-configuration.nix
./configuration.nix
./triton-vmtools.nix
./wireguard.nix
./apps/caddy.nix
./apps/drone.nix
./apps/forgejo-actions-runner.nix
./apps/grafana.nix
./apps/prometheus.nix
./apps/loki.nix
];
}

View file

@ -1,18 +1,19 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config
, lib
, pkgs
, modulesPath
, ...
{
config,
lib,
pkgs,
modulesPath,
...
}: {
imports = [ ];
imports = [];
boot.initrd.availableKernelModules = [ "ahci" "virtio_pci" "xhci_pci" "sr_mod" "virtio_blk" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
boot.initrd.availableKernelModules = ["ahci" "virtio_pci" "xhci_pci" "sr_mod" "virtio_blk"];
boot.initrd.kernelModules = [];
boot.kernelModules = [];
boot.extraModulePackages = [];
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
@ -34,7 +35,7 @@
];
};
swapDevices = [ ];
swapDevices = [];
networking.useDHCP = lib.mkDefault false;
networking.networkmanager.enable = lib.mkForce false;

View file

@ -1,6 +1,7 @@
{ pkgs
, flake
, ...
{
pkgs,
flake,
...
}: {
environment.systemPackages = with pkgs; [
flake.inputs.triton-vmtools.packages.${pkgs.system}.default

View file

@ -1,40 +0,0 @@
{
config,
pkgs,
flake,
... }:
{
networking.firewall.allowedUDPPorts = [ 51820 ];
age.secrets.wg-private-key.file = "${flake.self}/secrets/flora6-wg-private-key.age";
networking.wireguard.interfaces = {
wg-ssh = {
listenPort = 51820;
mtu = 1300;
ips = [
"10.7.6.2/32"
"fd00:fae:fae:fae:fae:2::/96"
];
privateKeyFile = config.age.secrets.wg-private-key.path;
peers = flake.self.logins.admins.wireguardDevices ++ [
{ # nachtigall.pub.solar
endpoint = "138.201.80.102:51820";
publicKey = "qzNywKY9RvqTnDO8eLik75/SHveaSk9OObilDzv+xkk=";
allowedIPs = [ "10.7.6.1/32" "fd00:fae:fae:fae:fae:1::/96" ];
}
];
};
};
services.openssh.listenAddresses = [
{
addr = "10.7.6.2";
port = 22;
}
{
addr = "[fd00:fae:fae:fae:fae:2::]";
port = 22;
}
];
}

View file

@ -1,8 +1,9 @@
{ config
, lib
, pkgs
, self
, ...
{
config,
lib,
pkgs,
self,
...
}: {
services.nginx.virtualHosts."collabora.pub.solar" = {
enableACME = true;
@ -14,7 +15,7 @@
proxy_pass http://127.0.0.1:9980;
proxy_set_header Host $host;
'';
};
};
};
virtualisation = {

View file

@ -1,96 +0,0 @@
{ flake, config, lib, ... }:
{
age.secrets."coturn-static-auth-secret" = {
file = "${flake.self}/secrets/coturn-static-auth-secret.age";
mode = "400";
owner = "turnserver";
};
services.coturn = rec {
enable = true;
no-cli = true;
no-tcp-relay = true;
min-port = 49000;
max-port = 50000;
use-auth-secret = true;
static-auth-secret-file = "/run/agenix/coturn-static-auth-secret";
realm = "turn.pub.solar";
cert = "${config.security.acme.certs.${realm}.directory}/full.pem";
pkey = "${config.security.acme.certs.${realm}.directory}/key.pem";
extraConfig =
let
externalIPv4s = lib.strings.concatMapStringsSep "\n" ({ address, ... }: "external-ip=${address}") config.networking.interfaces.enp35s0.ipv4.addresses;
externalIPv6s = lib.strings.concatMapStringsSep "\n" ({ address, ... }: "external-ip=${address}") config.networking.interfaces.enp35s0.ipv6.addresses;
in
''
${externalIPv4s}
${externalIPv6s}
no-tlsv1
no-tlsv1_1
no-rfc5780
response-origin-only-with-rfc5780
prod
no-stun-backward-compatibility
# ban private IP ranges
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
'';
};
networking.firewall = {
interfaces.enp35s0 =
let
range = with config.services.coturn; [{
from = min-port;
to = max-port;
}];
in
{
allowedUDPPortRanges = range;
allowedUDPPorts = [ 3478 5349 ];
allowedTCPPortRanges = [ ];
allowedTCPPorts = [ 3478 5349 ];
};
};
# get a certificate
security.acme.certs.${config.services.coturn.realm} = {
/* insert here the right configuration to obtain a certificate */
postRun = "systemctl restart coturn.service";
group = "turnserver";
};
services.nginx.virtualHosts.${config.services.coturn.realm} = {
enableACME = true;
addSSL = true;
globalRedirect = "pub.solar";
};
users.users.nginx.extraGroups = [ "turnserver" ];
}

View file

@ -1,8 +1,9 @@
{ config
, lib
, pkgs
, flake
, ...
{
config,
lib,
pkgs,
flake,
...
}: {
age.secrets.forgejo-database-password = {
file = "${flake.self}/secrets/forgejo-database-password.age";
@ -16,25 +17,12 @@
owner = "gitea";
};
age.secrets.forgejo-ssh-private-key = {
file = "${flake.self}/secrets/forgejo-ssh-private-key.age";
mode = "600";
owner = "gitea";
path = "/etc/forgejo/ssh/id_forgejo";
};
environment.etc."forgejo/ssh/id_forgejo.pub" = {
text = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCkPjvF2tZ2lZtkXed6lBvaPUpsNrI5kHlCNEf4LyFtgFXHoUL8UD3Bz9Fn1S+SDkdBMw/SumjvUf7TEGqQqzmFbG7+nWdWg2L00VdN8Kp8W+kKPBByJrzjDUIGhIMt7obaZnlSAVO5Cdqc1Q6bA9POLjSHIBxSD3QUs2pjUCkciNcEtL93easuXnlMwoYa217n5sA8n+BZmOJAcmA/UxYvKsqYlpJxa44m8JgMTy+5L08i/zkx9/FwniOcKcLedxmjZfV8raitDy34LslT2nBNG4I+em7qhKhSScn/cfyPvARiK71pk/rTx9mxBEjcGAkp3+hiA3Nyms0h/qTUh8yGyhbOn8hiro34HEKswXDN1HRfseyyZ4TqOoIC07F53x4OliYA0B+QbvwOemTX2XAWHfU4xEYrIhR46o3Eu5ooOM9HZLLYzIzKjsj/rpuKalFZ+9IeT/PJ/DrbgOEBlJGTu4XucEYXSiIvWB7G9WXij7TXKYbsRAFho9jw+9UZWklFAh9dcUKlX9YxafxOrw9DhJK620hblHLY9wPPFCbZVXDGfqdtn+ncRReMAw6N3VYqxMgnxd+OC52SMsSUi9VaL26i2UvEBwNYuim8GDnVabu/ciQLHMgifBONuF9sKD58ee5nnKgtYLDy9zU86aHBU78Ijew+WhYitO7qejMHMQ==";
mode = "600";
user = "gitea";
};
services.nginx.virtualHosts."git.pub.solar" = {
enableACME = true;
forceSSL = true;
locations."/user/login".extraConfig = ''
return 302 /user/oauth2/keycloak;
return 302 /user/oauth2/keycloak;
'';
locations."/" = {
@ -45,69 +33,41 @@
};
};
users.users.gitea = {
home = "/var/lib/forgejo";
useDefaultShell = true;
group = "gitea";
isSystemUser = true;
};
users.groups.gitea = {};
# Expose SSH port only for forgejo SSH
networking.firewall.interfaces.enp35s0.allowedTCPPorts = [ 2223 ];
networking.firewall.extraCommands = ''
iptables -t nat -i enp35s0 -I PREROUTING -p tcp --dport 22 -j REDIRECT --to-ports 2223
ip6tables -t nat -i enp35s0 -I PREROUTING -p tcp --dport 22 -j REDIRECT --to-ports 2223
'';
services.forgejo = {
services.gitea = {
enable = true;
user = "gitea";
group = "gitea";
package = pkgs.forgejo;
appName = "pub.solar git server";
database = {
type = "postgres";
passwordFile = config.age.secrets.forgejo-database-password.path;
name = "gitea";
user = "gitea";
};
stateDir = "/var/lib/forgejo";
lfs.enable = true;
mailerPasswordFile = config.age.secrets.forgejo-mailer-password.path;
settings = {
DEFAULT.APP_NAME = "pub.solar git server";
server = {
ROOT_URL = "https://git.pub.solar";
DOMAIN = "git.pub.solar";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 3000;
START_SSH_SERVER = true;
SSH_LISTEN_PORT = 2223;
SSH_SERVER_HOST_KEYS = "${config.age.secrets."forgejo-ssh-private-key".path}";
};
log.LEVEL = "Warn";
mailer = {
ENABLED = true;
PROTOCOL = "smtps";
SMTP_ADDR = "mail.greenbaum.zone";
SMTP_ADDR = "mx2.greenbaum.cloud";
SMTP_PORT = 465;
FROM = ''"pub.solar git server" <forgejo@pub.solar>'';
USER = "admins@pub.solar";
};
"repository.signing" = {
SIGNING_KEY = "default";
MERGES = "always";
};
openid = {
ENABLE_OPENID_SIGNIN = true;
ENABLE_OPENID_SIGNUP = true;
};
service = {
# uncomment after initial deployment, first user is admin user
# required to setup SSO (oauth openid-connect, keycloak auth provider)
@ -115,37 +75,15 @@
ENABLE_NOTIFY_MAIL = true;
DEFAULT_KEEP_EMAIL_PRIVATE = true;
};
session = {
PROVIDER = "db";
COOKIE_SECURE = lib.mkForce true;
};
# https://forgejo.org/docs/latest/admin/config-cheat-sheet/#webhook-webhook
webhook = {
ALLOWED_HOST_LIST = "loopback,external,*.pub.solar";
};
# See https://forgejo.org/docs/latest/admin/actions/
actions = {
ENABLED = true;
# In an actions workflow, when uses: does not specify an absolute URL,
# the value of DEFAULT_ACTIONS_URL is prepended to it.
DEFAULT_ACTIONS_URL = "https://code.forgejo.org";
};
# https://forgejo.org/docs/next/admin/recommendations/#securitylogin_remember_days
security = {
LOGIN_REMEMBER_DAYS = 365;
};
# https://forgejo.org/docs/next/admin/config-cheat-sheet/#indexer-indexer
indexer = {
REPO_INDEXER_ENABLED = true;
REPO_INDEXER_PATH = "indexers/repos.bleve";
MAX_FILE_SIZE = 1048576;
REPO_INDEXER_EXCLUDE = "resources/bin/**";
};
actions.ENABLED = true;
# In an actions workflow, when uses: does not specify an absolute URL,
# the value of DEFAULT_ACTIONS_URL is prepended to it.
actions.DEFAULT_ACTIONS_URL = "https://code.forgejo.org";
};
};
@ -171,7 +109,7 @@
GPG_TTY = "$(tty)";
};
services.restic.backups.forgejo-droppie = {
services.restic.backups.forgejo = {
paths = [
"/var/lib/forgejo"
"/tmp/forgejo-backup.sql"
@ -190,34 +128,5 @@
backupCleanupCommand = ''
rm /tmp/forgejo-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
services.restic.backups.forgejo-storagebox = {
paths = [
"/var/lib/forgejo"
"/tmp/forgejo-backup.sql"
];
timerConfig = {
OnCalendar = "*-*-* 04:20:00 Etc/UTC";
};
initialize = true;
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
backupPrepareCommand = ''
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump -d gitea > /tmp/forgejo-backup.sql
'';
backupCleanupCommand = ''
rm /tmp/forgejo-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
}

View file

@ -1,8 +1,9 @@
{ flake
, config
, lib
, pkgs
, ...
{
flake,
config,
lib,
pkgs,
...
}: {
age.secrets.keycloak-database-password = {
file = "${flake.self}/secrets/keycloak-database-password.age";
@ -46,7 +47,7 @@
};
};
services.restic.backups.keycloak-droppie = {
services.restic.backups.keycloak = {
paths = [
"/tmp/keycloak-backup.sql"
];
@ -64,33 +65,5 @@
backupCleanupCommand = ''
rm /tmp/keycloak-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
services.restic.backups.keycloak-storagebox = {
paths = [
"/tmp/keycloak-backup.sql"
];
timerConfig = {
OnCalendar = "*-*-* 04:10:00 Etc/UTC";
};
initialize = true;
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
backupPrepareCommand = ''
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump -d keycloak > /tmp/keycloak-backup.sql
'';
backupCleanupCommand = ''
rm /tmp/keycloak-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
}

View file

@ -1,11 +1,12 @@
{ flake
, config
, lib
, pkgs
, ...
{
flake,
config,
lib,
pkgs,
...
}:
{
networking.firewall.allowedTCPPorts = [ 25 ];
networking.firewall.allowedTCPPorts = [25];
users.users.nginx.extraGroups = [ "mailman" ];
@ -22,13 +23,13 @@
services.postfix = {
enable = true;
relayDomains = [ "hash:/var/lib/mailman/data/postfix_domains" ];
relayDomains = ["hash:/var/lib/mailman/data/postfix_domains"];
# get TLS certs for list.pub.solar from acme
sslCert = "/var/lib/acme/list.pub.solar/fullchain.pem";
sslKey = "/var/lib/acme/list.pub.solar/key.pem";
config = {
transport_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
local_recipient_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
transport_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
local_recipient_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
};
rootAlias = "admins@pub.solar";
postmasterAlias = "admins@pub.solar";
@ -37,34 +38,34 @@
systemd.paths.watcher-acme-ssl-file = {
description = "Watches for changes in acme's TLS cert file (after renewals) to reload postfix";
documentation = [ "systemd.path(5)" ];
partOf = [ "postfix-reload.service" ];
documentation = ["systemd.path(5)"];
partOf = ["postfix-reload.service"];
pathConfig = {
PathChanged = "/var/lib/acme/list.pub.solar/fullchain.pem";
Unit = "postfix-reload.service";
};
wantedBy = [ "multi-user.target" ];
wantedBy = ["multi-user.target"];
};
systemd.services."postfix-reload" = {
description = "Reloads postfix config, e.g. after TLS certs change, notified by watcher-acme-ssl-file.path";
documentation = [ "systemd.path(5)" ];
requires = [ "postfix.service" ];
after = [ "postfix.service" ];
documentation = ["systemd.path(5)"];
requires = ["postfix.service"];
after = ["postfix.service"];
startLimitIntervalSec = 10;
startLimitBurst = 5;
serviceConfig.Type = "oneshot";
script = ''
${pkgs.systemd}/bin/systemctl reload postfix
'';
wantedBy = [ "multi-user.target" ];
wantedBy = ["multi-user.target"];
};
services.mailman = {
enable = true;
serve.enable = true;
hyperkitty.enable = true;
webHosts = [ "list.pub.solar" ];
webHosts = ["list.pub.solar"];
siteOwner = "admins@pub.solar";
};
@ -79,7 +80,7 @@
# ])
#'';
services.restic.backups.mailman-droppie = {
services.restic.backups.mailman = {
paths = [
"/var/lib/mailman"
"/var/lib/mailman-web/mailman-web.db"
@ -94,30 +95,5 @@
initialize = true;
passwordFile = config.age.secrets."restic-repo-droppie".path;
repository = "sftp:yule@droppie.b12f.io:/media/internal/pub.solar";
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
services.restic.backups.mailman-storagebox = {
paths = [
"/var/lib/mailman"
"/var/lib/mailman-web/mailman-web.db"
"/var/lib/mailman-web/settings_local.json"
"/var/lib/postfix/conf/aliases.db"
];
timerConfig = {
OnCalendar = "*-*-* 04:15:00 Etc/UTC";
};
initialize = true;
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
}

View file

@ -40,9 +40,10 @@
# Different from WEB_DOMAIN in our case
localDomain = "pub.solar";
enableUnixSocket = true;
# Number of processes used by the mastodon-streaming service
# Recommended is the amount of your CPU cores minus one
# On our current 8-Core system, let's start with 5 for now
# Processes used by the mastodon-streaming service. Defaults to the number
# of CPU cores minus one
# This is without affect until this comment is addressed
# https://github.com/NixOS/nixpkgs/pull/251950#issuecomment-1732568492
streamingProcesses = 5;
# Processes used by the mastodon-web service
webProcesses = 2;
@ -54,16 +55,13 @@
vapidPublicKeyFile = "/run/agenix/mastodon-vapid-public-key";
smtp = {
createLocally = false;
host = "mail.greenbaum.zone";
host = "mx2.greenbaum.cloud";
port = 587;
authenticate = true;
user = "admins@pub.solar";
passwordFile = "/run/agenix/mastodon-smtp-password";
fromAddress = "mastodon-notifications@pub.solar";
};
mediaAutoRemove = {
olderThanDays = 7;
};
extraEnvFiles = [
"/run/agenix/mastodon-extra-env-secrets"
];
@ -96,7 +94,7 @@
};
};
services.restic.backups.mastodon-droppie = {
services.restic.backups.mastodon = {
paths = [
"/tmp/mastodon-backup.sql"
];
@ -114,33 +112,5 @@
backupCleanupCommand = ''
rm /tmp/mastodon-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
services.restic.backups.mastodon-storagebox = {
paths = [
"/tmp/mastodon-backup.sql"
];
timerConfig = {
OnCalendar = "*-*-* 04:05:00 Etc/UTC";
};
initialize = true;
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
backupPrepareCommand = ''
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump -d mastodon > /tmp/mastodon-backup.sql
'';
backupCleanupCommand = ''
rm /tmp/mastodon-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
}

View file

@ -1,45 +1,46 @@
{ pkgs, lib, ... }: {
default_server_config = {
"m.homeserver" = {
base_url = "https://matrix.pub.solar";
server_name = "pub.solar";
};
"m.identity_server" = {
base_url = "";
};
};
setting_defaults = {
custom_themes = (lib.modules.importJSON "${pkgs.element-themes}").config;
};
default_theme = "light";
default_country_code = "DE";
permalink_prefix = "https://matrix.to";
disable_custom_urls = true;
disable_guests = true;
brand = "Element Solar";
{
default_server_config = {
"m.homeserver" = {
base_url = "https://matrix.test.pub.solar";
server_name = "test.pub.solar";
};
"m.identity_server" = {
base_url = "";
};
};
# TODO: Add themes
# setting_defaults = {
# custom_themes = {{ matrix_client_element_setting_defaults_custom_themes | to_json }}
# };
# default_theme = {{ matrix_client_element_default_theme | string | to_json }};
# default_country_code = {{ matrix_client_element_default_country_code | string | to_json }};
permalink_prefix = "https://matrix.to";
disable_custom_urls = true;
disable_guests = true;
brand = "Element Solar";
# TODO: Configure these
integrations_ui_url = "";
integrations_rest_url = "";
integrations_widgets_urls = "";
integrations_jitsi_widget_url = "";
integrations_ui_url = "";
integrations_rest_url = "";
integrations_widgets_urls = "";
integrations_jitsi_widget_url = "";
bug_report_endpoint_url = "https://element.io/bugreports/submit";
show_labs_settings = true;
room_directory = {
servers = [ "matrix.org" ];
};
bug_report_endpoint_url = "https://element.io/bugreports/submit";
show_labs_settings = true;
room_directory = {
servers = ["matrix.org"];
};
# TODO: This looks wrong
enable_presence_by_hs_url = "\n";
embedded_pages = {
homeUrl = "";
};
branding = {
auth_footer_links = [{
enable_presence_by_hs_url = "\n";
embedded_pages = {
homeUrl = "";
};
branding = {
auth_footer_links = [{
text = "Privacy";
url = "https://pub.solar/privacy";
}];
# FUTUREWORK: Replace with pub.solar logo
auth_header_logo_url = "themes/element/img/logos/element-logo.svg";
};
auth_header_logo_url = "themes/element/img/logos/element-logo.svg";
};
}

View file

@ -1,120 +0,0 @@
{ config, lib, pkgs, ... }:
let
# Find element in list config.services.matrix-synapse.settings.listeners.*.resources
# that sets names = "client"
nameHasClient = name: name == "client";
resourceHasClient = resource: builtins.any nameHasClient resource.names;
listenerWithClient = lib.findFirst
(listener:
builtins.any resourceHasClient listener.resources)
(throw "Found no matrix-synapse.settings.listeners.*.resources.*.names containing string client")
config.services.matrix-synapse.settings.listeners
;
synapseClientPort = "${toString listenerWithClient.port}";
in
{
services.matrix-appservice-irc = {
enable = true;
localpart = "irc_bot";
port = 8010;
registrationUrl = "http://localhost:8010";
settings = {
homeserver = {
domain = "pub.solar";
url = "http://127.0.0.1:${synapseClientPort}";
media_url = "https://matrix.pub.solar";
enablePresence = false;
};
ircService = {
ident = {
address = "::";
enabled = false;
port = 1113;
};
logging = {
level = "debug";
maxFiles = 5;
toCosole = true;
};
matrixHandler = {
eventCacheSize = 4096;
};
metrics = {
enabled = true;
remoteUserAgeBuckets = [ "1h" "1d" "1w" ];
};
provisioning = {
enabled = false;
requestTimeoutSeconds = 300;
};
servers =
let
commonConfig = {
allowExpiredCerts = false;
botConfig = {
enabled = false;
joinChannelsIfNoUsers = false;
nick = "MatrixBot";
};
dynamicChannels = {
createAlias = true;
enabled = true;
federate = true;
joinRule = "public";
published = true;
};
ircClients = {
allowNickChanges = true;
concurrentReconnectLimit = 50;
idleTimeout = 10800;
lineLimit = 3;
maxClients = 30;
nickTemplate = "$DISPLAY[m]";
reconnectIntervalMs = 5000;
};
matrixClients = {
joinAttempts = -1;
};
membershipLists = {
enabled = true;
floodDelayMs = 10000;
global = {
ircToMatrix = {
incremental = true;
initial = true;
};
matrixToIrc = {
incremental = true;
initial = true;
};
};
};
port = 6697;
privateMessages = {
enabled = true;
federate = true;
};
sasl = false;
sendConnectionMessages = true;
ssl = true;
};
in
{
"irc.libera.chat" = lib.attrsets.recursiveUpdate commonConfig {
name = "libera";
dynamicChannels.groupId = "+libera.chat:localhost";
dynamicChannels.aliasTemplate = "#_libera_$CHANNEL";
matrixClients.displayName = "$NICK (LIBERA-IRC)";
};
"irc.scratch-network.net" = lib.attrsets.recursiveUpdate commonConfig {
name = "scratch";
matrixClients.displayName = "$NICK (SCRATCH-IRC)";
dynamicChannels.aliasTemplate = "#_scratch_$CHANNEL";
dynamicChannels.groupId = "+scratch-network.net:localhost";
};
};
};
};
};
}

View file

@ -0,0 +1,112 @@
{ flake, pkgs, ...}:{
age.secrets."matrix-hookshot-registration.yaml" = {
file = "${flake.self}/secrets/matrix-hookshot-registration.yaml.age";
mode = "400";
owner = "matrix-synapse";
};
configFile = ''
bot:
avatar: mxc://half-shot.uk/2876e89ccade4cb615e210c458e2a7a6883fe17d
displayname: Hookshot Bot
bridge:
bindAddress: 0.0.0.0
domain: test.pub.solar
mediaUrl: http://matrix-nginx-proxy:12080
port: 9993
url: http://matrix-nginx-proxy:12080
feeds:
enabled: true
pollIntervalSeconds: 600
pollTimeoutSeconds: 30
generic:
allowJsTransformationFunctions: true
enableHttpGet: false
enabled: true
urlPrefix: https://matrix.test.pub.solar/hookshot/webhooks
userIdPrefix: _webhooks_
waitForComplete: false
gitlab:
instances:
gitlab.com:
url: https://gitlab.com
webhook:
secret: ""
listeners:
- bindAddress: 0.0.0.0
port: 9000
resources:
- webhooks
- bindAddress: 0.0.0.0
port: 9002
resources:
- provisioning
- bindAddress: 0.0.0.0
port: 9003
resources:
- widgets
logging:
level: warn
metrics:
enabled: false
passFile: /data/passkey.pem
permissions:
- actor: pub.solar
services:
- level: commands
service: '*'
- actor: '@axeman:pub.solar'
services:
- level: admin
service: '*'
- actor: '@b12f:pub.solar'
services:
- level: admin
service: '*'
- actor: '@hensoko:pub.solar'
services:
- level: admin
service: '*'
- actor: '@teutat3s:pub.solar'
services:
- level: admin
service: '*'
provisioning:
secret: 1acb44197a5a6d52c6cff38ea07433bfbfe9a83313a6bade
widgets:
addToAdminRooms: false
branding:
widgetTitle: Hookshot Configuration
publicUrl: https://matrix.pub.solar/hookshot/widgetapi/v1/static
roomSetupWidget:
addOnInvite: false
'';
systemd.services.matrix-hookshot = {
description = "Matrix-Hookshot, a bridge between Matrix and multiple project management services, such as GitHub, GitLab and JIRA. ";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
serviceConfig = {
Type = "simple";
Restart = "always";
ProtectSystem = "strict";
ProtectHome = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
DynamicUser = true;
PrivateTmp = true;
UMask = "0027";
ExecStart = ''
${pkgs.matrix-hookshot}/bin/matrix-hookshot
'';
};
};
}

View file

@ -13,7 +13,7 @@
homeserver = {
# TODO: Use the port from synapse config
address = "http://127.0.0.1:8008";
domain = "pub.solar";
domain = "test.pub.solar";
verify_ssl = true;
};
appservice = {
@ -27,14 +27,14 @@
id = "telegram";
max_body_size = 1;
port = 8009;
provisioning = {
provisioning = {
enabled = false;
prefix = "/_matrix/provision/v1";
shared_secret = "generate";
};
public = {
enabled = true;
external = "https://matrix.pub.solar/c3c3f34b-29fb-5feb-86e5-98c75ec8214b";
external = "https://matrix.test.pub.solar/c3c3f34b-29fb-5feb-86e5-98c75ec8214b";
prefix = "/c3c3f34b-29fb-5feb-86e5-98c75ec8214b";
};
};
@ -59,7 +59,7 @@
bot_messages_as_notices = true;
bridge_notices = {
default = false;
exceptions = [ ];
exceptions = [];
};
command_prefix = "!tg";
delivery_error_reports = true;
@ -84,13 +84,13 @@
};
federate_rooms = true;
filter = {
list = [ ];
list = [];
mode = "blacklist";
};
image_as_file_size = 10;
initial_power_level_overrides = {
group = { };
user = { };
group = {};
user = {};
};
inline_images = false;
max_document_size = 100;
@ -112,15 +112,15 @@
public_portals = true;
relaybot = {
authless_portals = true;
group_chat_invite = [ ];
group_chat_invite = [];
ignore_own_incoming_events = true;
ignore_unbridged_group_chat = true;
private_chat = {
invite = [ ];
invite = [];
message = "This is a Matrix bridge relaybot and does not support direct chats";
state_changes = true;
};
whitelist = [ ];
whitelist = [];
whitelist_group_admins = true;
};
resend_bridge_info = false;
@ -140,12 +140,12 @@
username_template = "telegram_{userid}";
permissions = {
"pub.solar" = "full";
"test.pub.solar" = "full";
};
};
logging = {
formatters = {
formatters= {
precise = {
format = "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s";
};
@ -156,14 +156,14 @@
formatter = "precise";
};
};
loggers = {
loggers={
aiohttp.level = "WARNING";
mau.level = "WARNING";
telethon.level = "WARNING";
};
root = {
handlers = [ "console" ];
level = "WARNING";
level = "WARNING";
};
version = 1;
};
@ -202,8 +202,8 @@
};
systemd.services.mautrix-telegram.path = with pkgs; [
lottieconverter # for animated stickers conversion, unfree package
ffmpeg # if converting animated stickers to webm (very slow!)
lottieconverter # for animated stickers conversion, unfree package
ffmpeg # if converting animated stickers to webm (very slow!)
];
systemd.services.mautrix-telegram.serviceConfig = {
User = "matrix-synapse";

View file

@ -1,9 +1,8 @@
{ flake, config, pkgs, ... }:
let
publicDomain = "matrix.pub.solar";
serverDomain = "pub.solar";
in
{
publicDomain = "matrix.test.pub.solar";
serverDomain = "test.pub.solar";
in {
age.secrets."matrix-synapse-signing-key" = {
file = "${flake.self}/secrets/matrix-synapse-signing-key.age";
mode = "400";
@ -16,17 +15,11 @@ in
owner = "matrix-synapse";
};
age.secrets."matrix-synapse-sliding-sync-secret" = {
file = "${flake.self}/secrets/matrix-synapse-sliding-sync-secret.age";
mode = "400";
owner = "matrix-synapse";
};
services.matrix-synapse = {
enable = true;
settings = {
server_name = serverDomain;
public_baseurl = "https://${publicDomain}/";
public_baseurl = "https://matrix.test.pub.solar/";
database = {
name = "psycopg2";
args = {
@ -38,56 +31,16 @@ in
allow_unsafe_locale = false;
txn_limit = 0;
};
listeners = [
{
bind_addresses = [
"127.0.0.1"
];
port = 8008;
resources = [
{
compress = true;
names = [
"client"
];
}
{
compress = false;
names = [
"federation"
];
}
];
tls = false;
type = "http";
x_forwarded = true;
}
{
bind_addresses = [
"127.0.0.1"
];
port = 8012;
resources = [
{
names = [
"metrics"
];
}
];
tls = false;
type = "metrics";
}
];
account_threepid_delegates.msisdn = "";
alias_creation_rules = [{
action = "allow";
alias = "*";
room_id = "*";
alias= "*";
room_id = "*" ;
user_id = "*";
}];
allow_guest_access = false;
allow_public_rooms_over_federation = true;
allow_public_rooms_over_federation = false;
allow_public_rooms_without_auth = false;
auto_join_rooms = [
"#community:${serverDomain}"
@ -99,9 +52,22 @@ in
default_room_version = "10";
disable_msisdn_registration = true;
email = {
app_name = "Matrix";
client_base_url = "https://chat.pub.solar";
enable_notifs = true;
enable_tls = true;
# FUTUREWORK: Maybe we should change this
invite_client_location = "https://app.element.io";
notif_for_new_users = true;
notif_from = "Matrix <no-reply@pub.solar>";
require_transport_security = false;
smtp_host = "matrix-mailer";
smtp_port = 8025;
};
enable_media_repo = true;
enable_metrics = true;
mau_stats_only = true;
enable_registration = false;
enable_registration_captcha = false;
enable_registration_without_verification = false;
@ -109,17 +75,16 @@ in
encryption_enabled_by_default_for_room_type = "off";
event_cache_size = "100K";
federation_rr_transactions_per_room_per_second = 50;
federation_client_minimum_tls_version = "1.2";
forget_rooms_on_leave = true;
include_profile_data_on_invite = true;
instance_map = { };
instance_map = {};
limit_profile_requests_to_users_who_share_rooms = false;
log_config = ./matrix-log-config.yaml;
max_spider_size = "10M";
max_upload_size = "50M";
media_storage_providers = [ ];
media_storage_providers = [];
password_config = {
enabled = false;
@ -127,71 +92,70 @@ in
pepper = "";
};
presence.enabled = true;
presencee.enabled = true;
push.include_content = false;
rc_admin_redaction = {
rc_admin_redaction= {
burst_count = 50;
per_second = 1;
};
rc_federation = {
rc_federation= {
concurrent = 3;
reject_limit = 50;
sleep_delay = 500;
sleep_limit = 10;
window_size = 1000;
};
rc_invites = {
per_issuer = {
rc_invites= {
per_issuer= {
burst_count = 10;
per_second = 0.3;
};
per_room = {
per_room= {
burst_count = 10;
per_second = 0.3;
};
per_user = {
per_user= {
burst_count = 5;
per_second = 0.003;
};
};
rc_joins = {
local = {
rc_joins= {
local= {
burst_count = 10;
per_second = 0.1;
};
remote = {
remote= {
burst_count = 10;
per_second = 0.01;
};
};
rc_login = {
account = {
rc_login= {
account= {
burst_count = 3;
per_second = 0.17;
};
address = {
address= {
burst_count = 3;
per_second = 0.17;
};
failed_attempts = {
failed_attempts= {
burst_count = 3;
per_second = 0.17;
};
};
rc_message = {
rc_message= {
burst_count = 10;
per_second = 0.2;
};
rc_registration = {
rc_registration= {
burst_count = 3;
per_second = 0.17;
};
redaction_retention_period = "7d";
forgotten_room_retention_period = "7d";
redis.enabled = false;
registration_requires_token = false;
registrations_require_3pid = [ "email" ];
registrations_require_3pid = ["email"];
report_stats = false;
require_auth_for_profile_requests = false;
room_list_publication_rules = [{
@ -203,17 +167,13 @@ in
signing_key_path = "/run/agenix/matrix-synapse-signing-key";
stream_writers = { };
trusted_key_servers = [{ server_name = "matrix.org"; }];
suppress_key_server_warning = true;
stream_writers = {};
trusted_key_servers = [{ server_name = "matrix.org";}];
turn_allow_guests = false;
turn_uris = [
"turn:${config.services.coturn.realm}:3478?transport=udp"
"turn:${config.services.coturn.realm}:3478?transport=tcp"
"turn:matrix.pub.solar?transport=udp"
"turn:matrix.pub.solar?transport=tcp"
];
turn_user_lifetime = "1h";
url_preview_accept_language = [
"en-US"
"en"
@ -249,7 +209,7 @@ in
app_service_config_files = [
"/var/lib/matrix-synapse/telegram-registration.yaml"
"/var/lib/matrix-appservice-irc/registration.yml"
# "/matrix-appservice-irc-registration.yaml"
# "/matrix-appservice-slack-registration.yaml"
# "/hookshot-registration.yml"
# "/matrix-mautrix-signal-registration.yaml"
@ -257,8 +217,6 @@ in
];
};
withJemalloc = true;
extraConfigFiles = [
"/run/agenix/matrix-synapse-secret-config.yaml"
@ -271,51 +229,8 @@ in
"/var/lib/matrix-synapse/telegram-registration.yaml"
];
extras = [
"oidc"
"redis"
];
plugins = [
config.services.matrix-synapse.package.plugins.matrix-synapse-shared-secret-auth
];
sliding-sync = {
enable = true;
settings = {
SYNCV3_SERVER = "https://${publicDomain}";
SYNCV3_BINDADDR = "127.0.0.1:8011";
# The bind addr for Prometheus metrics, which will be accessible at
# /metrics at this address
SYNCV3_PROM = "127.0.0.1:9100";
};
environmentFile = config.age.secrets."matrix-synapse-sliding-sync-secret".path;
};
};
services.restic.backups.matrix-synapse-storagebox = {
paths = [
"/var/lib/matrix-synapse"
"/var/lib/matrix-appservice-irc"
"/var/lib/mautrix-telegram"
"/tmp/matrix-synapse-backup.sql"
];
timerConfig = {
OnCalendar = "*-*-* 05:00:00 Etc/UTC";
};
initialize = true;
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
backupPrepareCommand = ''
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump -d matrix > /tmp/matrix-synapse-backup.sql
'';
backupCleanupCommand = ''
rm /tmp/matrix-synapse-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
}

View file

@ -1,161 +1,159 @@
{ flake
, config
, lib
, pkgs
, ...
}:
let
{
flake,
config,
lib,
pkgs,
...
}: let
localSettingsPHP = pkgs.writeScript "LocalSettings.php" ''
<?php
# Protect against web entry
if ( !defined( 'MEDIAWIKI' ) ) {
exit;
}
<?php
# Protect against web entry
if ( !defined( 'MEDIAWIKI' ) ) {
exit;
}
# error_reporting( -1 );
# ini_set( 'display_errors', 1 );
# $wgShowExceptionDetails = true;
# $wgDBerrorLog = '/dev/stderr';
# $wgDebugLogFile = "/dev/stderr";
# error_reporting( -1 );
# ini_set( 'display_errors', 1 );
# $wgShowExceptionDetails = true;
$wgDBerrorLog = '/dev/stderr';
$wgDebugLogFile = "/dev/stderr";
$wgSitename = "pub.solar wiki";
$wgMetaNamespace = false;
$wgSitename = "pub.solar wiki";
$wgMetaNamespace = false;
## The URL base path to the directory containing the wiki;
## defaults for all runtime URL paths are based off of this.
## For more information on customizing the URLs
## (like /w/index.php/Page_title to /wiki/Page_title) please see:
## https://www.mediawiki.org/wiki/Manual:Short_URL
$wgScriptPath = "https://wiki.pub.solar";
## The URL base path to the directory containing the wiki;
## defaults for all runtime URL paths are based off of this.
## For more information on customizing the URLs
## (like /w/index.php/Page_title to /wiki/Page_title) please see:
## https://www.mediawiki.org/wiki/Manual:Short_URL
$wgScriptPath = "https://wiki.pub.solar";
## https://www.mediawiki.org/wiki/Manual:Short_URL
## https://www.mediawiki.org/wiki/Extension:OpenID_Connect#Known_issues
$wgArticlePath = "/index.php/$1";
## https://www.mediawiki.org/wiki/Manual:Short_URL
## https://www.mediawiki.org/wiki/Extension:OpenID_Connect#Known_issues
$wgArticlePath = "/index.php/$1";
## The protocol and server name to use in fully-qualified URLs
$wgServer = "https://wiki.pub.solar";
## The protocol and server name to use in fully-qualified URLs
$wgServer = "https://wiki.pub.solar";
## The URL path to static resources (images, scripts, etc.)
$wgResourceBasePath = $wgScriptPath;
## The URL path to static resources (images, scripts, etc.)
$wgResourceBasePath = $wgScriptPath;
## The URL path to the logo. Make sure you change this from the default,
## or else you'll overwrite your logo when you upgrade!
$wgLogo = "https://pub.solar/assets/pubsolar.svg";
## The URL path to the logo. Make sure you change this from the default,
## or else you'll overwrite your logo when you upgrade!
$wgLogo = "$wgResourceBasePath/resources/assets/wiki.png";
## UPO means: this is also a user preference option
## UPO means: this is also a user preference option
$wgEnableEmail = true;
$wgEnableUserEmail = true; # UPO
$wgEnableEmail = true;
$wgEnableUserEmail = true; # UPO
$wgPasswordSender = "admins@pub.solar";
$wgPasswordSender = "admins@pub.solar";
$wgEnotifUserTalk = false; # UPO
$wgEnotifWatchlist = false; # UPO
$wgEmailAuthentication = true;
$wgEnotifUserTalk = false; # UPO
$wgEnotifWatchlist = false; # UPO
$wgEmailAuthentication = true;
## Database settings
$wgDBtype = "postgres";
$wgDBserver = "host.docker.internal";
$wgDBport = "5432";
$wgDBname = "mediawiki";
$wgDBuser = "mediawiki";
$wgDBpassword = trim(file_get_contents("/run/mediawiki/database-password"));
## Database settings
$wgDBtype = "postgres";
$wgDBserver = "host.docker.internal";
$wgDBport = "5432";
$wgDBname = "mediawiki";
$wgDBuser = "mediawiki";
$wgDBpassword = trim(file_get_contents("/run/mediawiki/database-password"));
## Shared memory settings
$wgMainCacheType = CACHE_NONE;
$wgMemCachedServers = [];
## Shared memory settings
$wgMainCacheType = CACHE_NONE;
$wgMemCachedServers = [];
$wgEnableUploads = true;
$wgUploadDirectory = "/var/www/html/uploads";
$wgUploadPath = $wgScriptPath . "/uploads";
$wgEnableUploads = true;
$wgUploadDirectory = "/var/www/html/uploads";
$wgUseImageMagick = true;
$wgImageMagickConvertCommand = "/usr/bin/convert";
$wgUseImageMagick = true;
$wgImageMagickConvertCommand = "/usr/bin/convert";
# InstantCommons allows wiki to use images from https://commons.wikimedia.org
$wgUseInstantCommons = true;
# InstantCommons allows wiki to use images from https://commons.wikimedia.org
$wgUseInstantCommons = false;
# Periodically send a pingback to https://www.mediawiki.org/ with basic data
# about this MediaWiki instance. The Wikimedia Foundation shares this data
# with MediaWiki developers to help guide future development efforts.
$wgPingback = true;
# Periodically send a pingback to https://www.mediawiki.org/ with basic data
# about this MediaWiki instance. The Wikimedia Foundation shares this data
# with MediaWiki developers to help guide future development efforts.
$wgPingback = true;
## If you use ImageMagick (or any other shell command) on a
## Linux server, this will need to be set to the name of an
## available UTF-8 locale
$wgShellLocale = "C.UTF-8";
## If you use ImageMagick (or any other shell command) on a
## Linux server, this will need to be set to the name of an
## available UTF-8 locale
$wgShellLocale = "C.UTF-8";
# Site language code, should be one of the list in ./languages/data/Names.php
$wgLanguageCode = "en";
# Site language code, should be one of the list in ./languages/data/Names.php
$wgLanguageCode = "en";
$wgSecretKey = trim(file_get_contents("/run/mediawiki/secret-key"));
$wgSecretKey = trim(file_get_contents("/run/mediawiki/secret-key"));
# Changing this will log out all existing sessions.
$wgAuthenticationTokenVersion = "";
# Changing this will log out all existing sessions.
$wgAuthenticationTokenVersion = "";
## For attaching licensing metadata to pages, and displaying an
## appropriate copyright notice / icon. GNU Free Documentation
## License and Creative Commons licenses are supported so far.
$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
$wgRightsUrl = "";
$wgRightsText = "";
$wgRightsIcon = "";
## For attaching licensing metadata to pages, and displaying an
## appropriate copyright notice / icon. GNU Free Documentation
## License and Creative Commons licenses are supported so far.
$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
$wgRightsUrl = "";
$wgRightsText = "";
$wgRightsIcon = "";
# Path to the GNU diff3 utility. Used for conflict resolution.
$wgDiff = "/usr/bin/diff";
$wgDiff3 = "/usr/bin/diff3";
# Path to the GNU diff3 utility. Used for conflict resolution.
$wgDiff = "/usr/bin/diff";
$wgDiff3 = "/usr/bin/diff3";
# Enabled skins.
wfLoadSkin('MonoBook');
wfLoadSkin('Timeless');
wfLoadSkin('Vector');
# Enabled skins.
wfLoadSkin('MonoBook');
wfLoadSkin('Timeless');
wfLoadSkin('Vector');
# Enabled extensions.
wfLoadExtension('OpenIDConnect');
wfLoadExtension('PluggableAuth');
wfLoadExtension('VisualEditor');
wfLoadExtension('TemplateStyles');
# Enabled extensions.
wfLoadExtension('OpenIDConnect');
wfLoadExtension('PluggableAuth');
wfLoadExtension('VisualEditor');
# End of automatically generated settings.
# Add more configuration options below.
# End of automatically generated settings.
# Add more configuration options below.
$wgLogos = [
'svg' => "https://pub.solar/assets/pubsolar.svg",
'icon' => "https://pub.solar/assets/pubsolar.svg",
'wordmark' => [
'src'=> "https://pub.solar/assets/pubsolar.svg",
'width'=> 0,
'height'=> 0,
],
];
$wgFavicon = 'https://pub.solar/assets/pubsolar.svg';
$wgLogo = "https://pub.solar/assets/pubsolar.svg";
$wgLogos = [
'svg' => "https://pub.solar/assets/pubsolar.svg",
'icon' => "https://pub.solar/assets/pubsolar.svg",
'wordmark' => [
'src'=> "https://pub.solar/assets/pubsolar.svg",
'width'=> 0,
'height'=> 0,
],
];
$wgFavicon = 'https://pub.solar/assets/pubsolar.svg';
$wgDefaultSkin = 'vector-2022';
$wgDefaultSkin = 'vector-2022';
// https://www.mediawiki.org/wiki/Extension:PluggableAuth#Installation
$wgGroupPermissions['*']['autocreateaccount'] = true;
// https://www.mediawiki.org/wiki/Extension:PluggableAuth#Installation
$wgGroupPermissions['*']['autocreateaccount'] = true;
// https://www.mediawiki.org/wiki/Extension:PluggableAuth#Configuration
$wgPluggableAuth_EnableAutoLogin = false;
$wgPluggableAuth_ButtonLabel = 'Login with pub.solar ID';
// https://www.mediawiki.org/wiki/Extension:PluggableAuth#Configuration
$wgPluggableAuth_EnableAutoLogin = false;
$wgPluggableAuth_ButtonLabel = 'Login with pub.solar ID';
// https://www.mediawiki.org/wiki/Extension:OpenID_Connect#Keycloak
$wgPluggableAuth_Config[] = [
'plugin' => 'OpenIDConnect',
'data' => [
'providerURL' => 'https://auth.pub.solar/realms/pub.solar',
'clientID' => 'mediawiki',
'clientsecret' => trim(file_get_contents('/run/mediawiki/oidc-client-secret'))
]
];
$wgOpenIDConnect_SingleLogout = true;
$wgOpenIDConnect_MigrateUsersByEmail = true;
// https://www.mediawiki.org/wiki/Extension:OpenID_Connect#Keycloak
$wgPluggableAuth_Config[] = [
'plugin' => 'OpenIDConnect',
'data' => [
'providerURL' => 'https://auth.pub.solar/realms/pub.solar',
'clientID' => 'mediawiki',
'clientsecret' => trim(file_get_contents('/run/mediawiki/oidc-client-secret'))
]
];
$wgOpenIDConnect_SingleLogout = true;
$wgOpenIDConnect_MigrateUsersByEmail = true;
'';
uid = 986;
gid = 984;
in
{
in {
age.secrets.mediawiki-database-password = {
file = "${flake.self}/secrets/mediawiki-database-password.age";
path = "/run/mediawiki/database-password";
@ -208,7 +206,7 @@ in
backend = "docker";
containers."mediawiki" = {
image = "git.pub.solar/pub-solar/mediawiki-oidc-docker:1.41.1";
image = "git.pub.solar/pub-solar/mediawiki-oidc-docker:latest";
user = "1000:${builtins.toString gid}";
autoStart = true;

Binary file not shown.

Before

(image error) Size: 29 KiB

View file

@ -1,119 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="Layer_3"
data-name="Layer 3"
viewBox="0 0 275.3 276.37"
version="1.1"
sodipodi:docname="pubsolar.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview226"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="4.3962803"
inkscape:cx="95.762774"
inkscape:cy="149.33079"
inkscape:window-width="2560"
inkscape:window-height="1380"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_3" />
<defs
id="defs197">
<style
id="style195">.cls-1,.cls-2{fill:#ed1c24;}.cls-1{stroke:#ed1c24;stroke-width:6.89px;}.cls-1,.cls-2,.cls-4{stroke-miterlimit:10;}.cls-2{stroke:#fff;stroke-width:4.72px;}.cls-3{fill:#fff;}.cls-4{stroke:#000;stroke-width:4.58px;}</style>
</defs>
<title
id="title199">PubSolar logo</title>
<path
class="cls-1"
d="M362.85,272.68v11.78l-4.39,1.84a18.38,18.38,0,0,0-11.24,15.8l-.59,9.43-7.92.61a18.38,18.38,0,0,0-15.53,11.22l-2.47,5.9H309.07a18.38,18.38,0,0,0-14.13,6.63l-6.8,8.17-10.58-3.17a18.38,18.38,0,0,0-14.89,1.95l-9.84,6-8.65-5.75a18.38,18.38,0,0,0-15.75-2.2l-10,3.17-5.88-7a18.38,18.38,0,0,0-15.43-6.51l-10.24.76-4.62-8.75a18.38,18.38,0,0,0-14.22-9.69l-9.7-1.08-1.89-10.65a18.38,18.38,0,0,0-11.06-13.77L134.7,283l.93-11.32a18.38,18.38,0,0,0-7-16l-6.52-5.06,3.55-8.77a18.38,18.38,0,0,0-1.77-17.13l-5.74-8.57,6.06-8a18.38,18.38,0,0,0,2.54-17.63l-3.93-10.34,5.12-2.87a18.38,18.38,0,0,0,9.31-17.78l-1.12-11.75,8.18-2.64a18.38,18.38,0,0,0,12.67-16l.75-9.5h6.44a18.38,18.38,0,0,0,17.59-13L184,99.13l12.19,1.25a18.38,18.38,0,0,0,17.27-8.25l4.11-6.3,8.21,3.79a18.38,18.38,0,0,0,20.12-3.14l5.85-5.36L261,88.21a18.38,18.38,0,0,0,18.23,2.32L287.76,87l6,7.67a18.38,18.38,0,0,0,15.32,7l11.25-.51,3.21,7.56a18.38,18.38,0,0,0,15.29,11.12l9.33.83.48,7.39A18.38,18.38,0,0,0,358.1,143l9.37,5.18-.71,11.41a18.38,18.38,0,0,0,7.43,15.93l7.14,5.26-3.79,10.66a18.38,18.38,0,0,0,2,16.27l5.57,8.45-6.46,10.31a18.38,18.38,0,0,0-2.11,14.77l2.66,9.38-9.63,7.93A18.38,18.38,0,0,0,362.85,272.68Z"
transform="translate(-113.88 -76.62)"
id="path201" />
<circle
class="cls-2"
cx="137.72"
cy="138.48"
r="117.79"
id="circle203" />
<path
class="cls-3"
d="M326.34,141.78A105.72,105.72,0,0,0,181.56,295.61,105.7,105.7,0,1,1,326.34,141.78Z"
transform="translate(-113.88 -76.62)"
id="path205" />
<path
class="cls-3"
d="m 180.73,231.12 c 0.57,1.71 6.47,20.7 10,30 3.53,9.3 7.59,16.9 12.87,17.74 5.28,0.84 10.64,-7.56 16.9,-7.78 8.76,-0.31 13.68,-1 18.13,-8.12 3.56,-5.67 9.9,1.76 25.87,-7.49 8.71,-5 26.56,-4.08 43.4,-11.91 20.26,-9.42 6.82,-12 6.83,-24 0,-3.84 3.66,-4.88 9.42,-7.17 3.82,-1.52 9.75,-4.8 8.63,-8.92 -1.24,-4.55 -0.79,-6.28 -5.2,-7.93 -8.95912,-3.35701 -15.41112,0.51436 -20.81894,2.56685 -7.90305,3.13369 -9.25397,-5.78637 -14.68734,-7.38637 -3.84252,-1.13153 -10.81538,-2.53029 -12.21968,-9.01195 C 278.1258,173.18465 270.1,170.58 261.8,170.42 c -4.33,-0.08 -8,1.37 -11,-5.82 -3.38,-8.07 -10.07,-19.35 -16.92,-12 -6.85,7.35 2,17.55 3.13,27 0.19,1.55 -0.08,3 -1.63,3.23 -3.79619,0.48553 -7.30604,2.27403 -9.93,5.06 -4.27,4.41 -8.18,-2.59 -15.09,3.8 -6.32,5.85 -13.27,-0.73 -25.52,-0.41 -20.65,0.56 -4.11,39.84 -4.11,39.84 z"
transform="translate(-113.88,-76.62)"
id="path207"
sodipodi:nodetypes="csscccccccccscccscccccc" />
<path
class="cls-4"
d="M200.74,254.41a27,27,0,0,0,1.31,3c2.16,4.33,1.11,2.86,3.11,6.36,1.22,2.13,4.06,6.21,2.11,6.86-1.68.56-4.06-1-4.75-3.08-.34-1-.59-2.08-.93-3.1-2.72-8.19-6.6-15.8-9.33-24-3-9-5.76-18.25-7.12-27.94-.46-3.57-3.28-10.18-.86-11,1.49-.49,2.14.53,2.48,1.55.74,2.23.09,2.45.5,3.66a1.31,1.31,0,0,0,1.7.78c1.68-.56,1.9-3.63,3.95-4.31,7.36-2.45,15.23,5.38,17.4,11.9,1.48,6-1.4,10.39-6.34,15.14a7.39,7.39,0,0,1-2.86,1.67c-2,.68-4.81.46-6.12.89s-1.61,1.36-1.15,2.76,1.21,2.7,1.67,4.1c.68,2,1.15,4.07,1.83,6.11a13.67,13.67,0,0,0,.71,1.83C198.94,249.94,200,252.18,200.74,254.41Zm-6.45-48.32c-6.52,2.17-4.88,13.31-3,19.08,1.3,3.91,4.19,5.44,8.09,4.14,5.59-1.86,9.23-8.65,7.37-14.24C205.11,211,199.22,204.45,194.29,206.09Z"
transform="translate(-113.88 -76.62)"
id="path209" />
<path
class="cls-4"
d="M216.34,197.41a.88.88,0,0,1,1.35.45c2.1,3.85,3.09,9.07,5.33,13.18,2.1,3.85,7.1,7,9.45,5.68,2.67-1.46,4.77-8.79,2.56-12.83-.64-1.17-1.64-2.24-2.5-3.8-1.32-2.41-2.15-6.11.13-7.35,1.37-.75,1.92-.2,2.31.52.07.13.08.29.15.43.25.46.59.78.84,1.23,1.1,2,1.14,4.88,1.54,6.86a21.85,21.85,0,0,0,2,6.08,14.16,14.16,0,0,0,4.19,4.74c.38.38,1,.73,1.24,1.18a1.24,1.24,0,0,1-.71,1.66c-.85.46-3.88-1.52-4.84-3.28-.21-.39-.3-.85-.55-1.31a.78.78,0,0,0-1.14-.23c-.65.36-.62,2.12-.83,2.82-.76,2-1.51,4.21-3.33,5.21-4,2.21-9.11-1.63-10.89-4.89-.43-.78-.79-1.6-1.25-2.45C219.43,207.58,215.43,197.91,216.34,197.41Z"
transform="translate(-113.88 -76.62)"
id="path211" />
<path
class="cls-4"
d="M251.1,184.25c.22.55.06,1.41,1.17,1,.62-.24.83-1.12,1.06-1.77a7.57,7.57,0,0,1,4.54-4.5c6.36-2.5,13.65,1.82,15.88,7.49,2.12,5.39,1,13.9-5.72,16.54a10.23,10.23,0,0,1-5.58.43,4,4,0,0,0-2-.18c-.9.35,0,2.33-1.08,2.74-1.94.76-3.25-.83-4.09-2.74-1.37-3.29-3.11-8.25-4.44-11.64s-2.43-7.19-3.84-10.79c-1.33-3.39-3-6.71-4.39-10.17-.6-1.52-1.13-3.07-1.7-4.52a17.75,17.75,0,0,0-2.25-4.31,1,1,0,0,1-.23-.39,1.46,1.46,0,0,1,1.06-1.77,1.54,1.54,0,0,1,2.14,1l.14.35a75.7,75.7,0,0,0,3.53,10.19c.35.9.8,1.84,1.15,2.74l-.07,0C247.73,177.34,249.77,180.86,251.1,184.25Zm8-3.06c-5.33,2.09-6.44,8.2-4.32,13.59a9.89,9.89,0,0,0,13,5.9c4.36-1.71,5.62-9.07,3.88-13.5C268.24,181.58,263.7,179.37,259.07,181.19Z"
transform="translate(-113.88 -76.62)"
id="path213" />
<path
class="cls-4"
d="M216.42,242.8c-.49-2.48,2.88-6.17,6.16-6.81,1.83-.36,4.94.47,5.28,2.22a1.91,1.91,0,0,1-1.12,2c-1.38.27-2.88-1.93-4.33-1.65s-3.39,2.41-3.13,3.72c.59,3,7.19,5.79,10.06,8.48a7,7,0,0,1,2.07,3.61,7.5,7.5,0,0,1-5.63,8.37c-5.76,1.13-9.07-3-11.63-6.81a2,2,0,0,1-.39-.83,1.4,1.4,0,0,1,1-1.71c.87-.17,1.43.7,1.86,1.38,1.5,3,4,6.41,8.28,5.57,2.7-.53,4.44-3.22,3.79-6.57C227.21,249.93,217.23,247,216.42,242.8Z"
transform="translate(-113.88 -76.62)"
id="path215" />
<path
class="cls-4"
d="M244.38,250.12c-6.18-5.9-6.33-14.67-2.63-18.54,2.46-2.58,9.1-4.36,13.13-.51,3.39,3.23,6.36,13.57,1.38,18.78a6.15,6.15,0,0,1-5.21,1.91,7.1,7.1,0,0,0-3.3.34c-.83.33-1,.34-1.85-.43-.27-.26-.59-.67-1.08-1.13Zm8.85-17.44a6.87,6.87,0,0,0-9.3.16c-2.62,2.74-1.09,12.22,1.38,14.58s7.16,2.94,9.68.3C258,244.55,257.58,236.83,253.23,232.67Z"
transform="translate(-113.88 -76.62)"
id="path217" />
<path
class="cls-4"
d="M269.24,237.75a63.21,63.21,0,0,0-2.83-6.39s-1-2.71-1.6-4.88c-.76-1.94-1.59-3.84-2.35-5.78-2.09-5.33-10.17-21.45-6.49-20.18,1.83.63,2.79.82,3.06,1.52a28.65,28.65,0,0,1,1,4.84c1.23,4.66,4.57,13.94,6.83,19.68.9,2.28,1.89,4.61,2.93,6.83,2,4.46,4.33,9.33,4.18,10.25C273.94,243.64,272.62,248.25,269.24,237.75Z"
transform="translate(-113.88 -76.62)"
id="path219" />
<path
class="cls-4"
d="M288.05,226.57c1-.37,1.51-1,1.29-2.58-.3-2.13-2.48-6.48-4.62-6.18-1.84.26-3.45,3.78-4.85,4-.59.08-1.23-.73-1.29-1.17-.26-1.84,4.38-4.66,5.92-4.88,5.22-.73,7.52,9.3,9.65,15.91.44,1.52,1,2.41,2.74,2.39.68.06,1.72,0,1.83.72A2.08,2.08,0,0,1,297,237c-1.25.17-2.61-1.51-3.64-1.37-2.06.29-3.5,3.94-6.3,4.33a4.31,4.31,0,0,1-4.94-3.66c0-.22,0-.45,0-.67C281.56,230.56,283.06,228.39,288.05,226.57ZM284.42,235c.21,1.47.62,2.84,2.54,2.57s5.26-4.26,5-6.32c-.33-2.36-2.1-2.71-3.91-2.76C285.44,228.81,284,231.64,284.42,235Z"
transform="translate(-113.88 -76.62)"
id="path221" />
<path
class="cls-4"
d="M306.07,208c2.38-.87,14.61-5.28,16.95-6.05.86-.23,1.94-.52,2.28.78.92,3.45-22.71,6-20.38,14.81,1.28,4.81,2.85,9.55,4,14.3.25.93.1,1.82-1,2.11-2.08.56-4.25-10.17-4.27-10.24C301.92,216.9,299.43,210.42,306.07,208Z"
transform="translate(-113.88 -76.62)"
id="path223" />
<ellipse
style="fill:#000000;fill-rule:evenodd;stroke-width:0.83809"
id="path429"
cx="172.17104"
cy="122.1034"
rx="4.5852861"
ry="4.9624691" />
<metadata
id="metadata3053">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title>PubSolar logo</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

Before

(image error) Size: 8.7 KiB

View file

@ -1,7 +0,0 @@
# Welcome to your pub.solar cloud!
By default, the cloud is limited to 10MB of storage. If you want more, just send a short request to [crew@pub.solar](mailto:crew@pub.solar).
To download a desktop client, go to https://nextcloud.com/download.
You can edit this file by clicking here, and put any contents you want as notes for this directory :)

View file

@ -1,7 +1,8 @@
{ config
, pkgs
, flake
, ...
{
config,
pkgs,
flake,
...
}:
{
age.secrets."nextcloud-secrets" = {
@ -26,17 +27,15 @@
home = "/var/lib/nextcloud";
enable = true;
package = pkgs.nextcloud28;
package = pkgs.nextcloud27;
https = true;
secretFile = config.age.secrets."nextcloud-secrets".path; # secret
maxUploadSize = "1G";
skeletonDirectory = "./nextcloud-skeleton";
configureRedis = true;
notify_push = {
enable = true;
bendDomainToLocalhost = true;
};
config = {
@ -47,6 +46,11 @@
dbname = "nextcloud";
dbtableprefix = "oc_";
overwriteProtocol = "https";
trustedProxies = [
"127.0.0.1"
"::1"
];
};
extraOptions = {
@ -62,7 +66,7 @@
mail_smtpname = "admins@pub.solar";
mail_smtpsecure = "tls";
mail_smtpauth = 1;
mail_smtphost = "mail.greenbaum.zone";
mail_smtphost = "mx2.greenbaum.cloud";
mail_smtpport = "587";
# This is to allow connections to collabora and keycloak, among other services
@ -97,7 +101,6 @@
integrity.check.disabled = false;
updater.release.channel = "stable";
loglevel = 0;
maintenance_window_start = "1";
# maintenance = false;
app_install_overwrite = [
"pdfdraw"
@ -109,10 +112,7 @@
};
phpOptions = {
"opcache.interned_strings_buffer" = "32";
# https://docs.nextcloud.com/server/latest/admin_manual/installation/server_tuning.html#:~:text=opcache.jit%20%3D%201255%20opcache.jit_buffer_size%20%3D%20128m
"opcache.jit" = "1255";
"opcache.jit_buffer_size" = "128M";
"opcache.interned_strings_buffer" = "16";
};
# Calculated with 4GiB RAM, 80MiB process size available on
@ -131,7 +131,7 @@
database.createLocally = true;
};
services.restic.backups.nextcloud-droppie = {
services.restic.backups.nextcloud = {
paths = [
"/var/lib/nextcloud/data"
"/tmp/nextcloud-backup.sql"
@ -150,34 +150,5 @@
backupCleanupCommand = ''
rm /tmp/nextcloud-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
services.restic.backups.nextcloud-storagebox = {
paths = [
"/var/lib/nextcloud/data"
"/tmp/nextcloud-backup.sql"
];
timerConfig = {
OnCalendar = "*-*-* 04:00:00 Etc/UTC";
};
initialize = true;
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
backupPrepareCommand = ''
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump -d nextcloud > /tmp/nextcloud-backup.sql
'';
backupCleanupCommand = ''
rm /tmp/nextcloud-backup.sql
'';
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 3"
];
};
}

View file

@ -3,55 +3,40 @@ let
cfg = config.services.mastodon;
in
{
services.nginx = {
virtualHosts = {
"mastodon.pub.solar" = {
root = "${cfg.package}/public/";
# mastodon only supports https, but you can override this if you offload tls elsewhere.
forceSSL = lib.mkDefault true;
enableACME = lib.mkDefault true;
services.nginx.virtualHosts = {
"mastodon.pub.solar" = {
root = "${cfg.package}/public/";
# mastodon only supports https, but you can override this if you offload tls elsewhere.
forceSSL = lib.mkDefault true;
enableACME = lib.mkDefault true;
locations."/auth/sign_up".extraConfig = ''
return 302 /auth/sign_in;
'';
locations."/system/".alias = "/var/lib/mastodon/public-system/";
locations."/auth/confirmation/new".extraConfig = ''
return 302 https://auth.pub.solar/realms/pub.solar/login-actions/reset-credentials?client_id=mastodon;
'';
locations."/auth/password/new".extraConfig = ''
return 302 https://auth.pub.solar/realms/pub.solar/login-actions/reset-credentials?client_id=mastodon;
'';
locations."/system/".alias = "/var/lib/mastodon/public-system/";
locations."/" = {
tryFiles = "$uri @proxy";
};
locations."@proxy" = {
proxyPass = (if cfg.enableUnixSocket then "http://unix:/run/mastodon-web/web.socket" else "http://127.0.0.1:${toString(cfg.webPort)}");
proxyWebsockets = true;
};
locations."/api/v1/streaming/" = {
proxyPass = "http://mastodon-streaming";
proxyWebsockets = true;
};
locations."/" = {
tryFiles = "$uri @proxy";
};
};
upstreams.mastodon-streaming = {
extraConfig = ''
least_conn;
locations."/auth/sign_up".extraConfig = ''
return 302 /auth/sign_in;
'';
servers = builtins.listToAttrs
(map
(i: {
name = "unix:/run/mastodon-streaming/streaming-${toString i}.socket";
value = { };
})
(lib.range 1 cfg.streamingProcesses));
locations."/auth/confirmation/new".extraConfig = ''
return 302 https://auth.pub.solar/realms/pub.solar/login-actions/reset-credentials?client_id=mastodon;
'';
locations."/auth/password/new".extraConfig = ''
return 302 https://auth.pub.solar/realms/pub.solar/login-actions/reset-credentials?client_id=mastodon;
'';
locations."@proxy" = {
proxyPass = (if cfg.enableUnixSocket then "http://unix:/run/mastodon-web/web.socket" else "http://127.0.0.1:${toString(cfg.webPort)}");
proxyWebsockets = true;
};
locations."/api/v1/streaming/" = {
proxyPass = (if cfg.enableUnixSocket then "http://unix:/run/mastodon-streaming/streaming.socket" else "http://127.0.0.1:${toString(cfg.streamingPort)}/");
proxyWebsockets = true;
};
};
};
}

View file

@ -5,16 +5,16 @@ let
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-XSS-Protection "1; mode=block";
'';
clientConfig = import ./matrix/element-client-config.nix { inherit lib pkgs; };
clientConfig = import ./matrix/element-client-config.nix;
wellKnownClient = domain: {
"m.homeserver".base_url = "https://matrix.${domain}";
"m.identity_server".base_url = "https://matrix.${domain}";
"org.matrix.msc3575.proxy".url = "https://matrix.${domain}";
"org.matrix.msc3575.proxy".url = "https://matrix.${domain}/sliding-sync";
"im.vector.riot.e2ee".default = true;
"io.element.e2ee" = {
default = true;
secure_backup_required = false;
secure_backup_setup_methods = [ ];
secure_backup_setup_methods = [];
};
"m.integrations" = {
managers = [
@ -25,27 +25,7 @@ let
];
};
};
wellKnownServer = domain: { "m.server" = "matrix.${domain}:8448"; };
wellKnownSupport = {
contacts = [
{
email_address = "crew@pub.solar";
matrix_id = "@b12f:pub.solar";
role = "m.role.admin";
}
{
email_address = "crew@pub.solar";
matrix_id = "@hensoko:pub.solar";
role = "m.role.admin";
}
{
email_address = "crew@pub.solar";
matrix_id = "@teutat3s:pub.solar";
role = "m.role.admin";
}
];
support_page = "https://pub.solar/about";
};
wellKnownServer = domain: { "m.server" = "${domain}:8448"; };
mkWellKnown = data: ''
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
@ -54,7 +34,6 @@ let
wellKnownLocations = domain: {
"= /.well-known/matrix/server".extraConfig = mkWellKnown (wellKnownServer domain);
"= /.well-known/matrix/client".extraConfig = mkWellKnown (wellKnownClient domain);
"= /.well-known/matrix/support".extraConfig = mkWellKnown wellKnownSupport;
};
in
{
@ -68,7 +47,11 @@ in
locations = wellKnownLocations "pub.solar";
};
"chat.pub.solar" = {
#######################################
# Stuff below is still in betatesting #
#######################################
"chat.test.pub.solar" = {
forceSSL = true;
enableACME = true;
root = pkgs.element-web.override {
@ -76,7 +59,7 @@ in
};
};
"matrix.pub.solar" = {
"matrix.test.pub.solar" = {
root = "/dev/null";
forceSSL = lib.mkDefault true;
@ -87,19 +70,16 @@ in
gzip on;
gzip_types text/plain application/json;
'';
locations = {
# For telegram
locations = (wellKnownLocations "test.pub.solar") // {
# TODO: Configure metrics
# "/metrics" = {
# };
"/c3c3f34b-29fb-5feb-86e5-98c75ec8214b" = {
proxyPass = "http://127.0.0.1:8009";
extraConfig = commonHeaders;
};
# sliding-sync
"~ ^/(client/|_matrix/client/unstable/org.matrix.msc3575/sync)" = {
proxyPass = "http://127.0.0.1:8011";
extraConfig = commonHeaders;
};
"~* ^(/_matrix|/_synapse/client|/_synapse/oidc)" = {
proxyPass = "http://127.0.0.1:8008";
@ -117,19 +97,18 @@ in
};
};
"matrix.pub.solar-federation" = {
serverName = "matrix.pub.solar";
serverName = "matrix.test.pub.solar";
forceSSL = lib.mkDefault true;
enableACME = lib.mkDefault true;
listen = [{
port = 8448;
addr = "0.0.0.0";
ssl = true;
}
{
port = 8448;
addr = "[::]";
ssl = true;
}];
} {
port = 8448;
addr = "[::]";
ssl = true;
}];
root = "/dev/null";
extraConfig = ''
server_tokens off;
@ -151,6 +130,6 @@ in
};
};
};
networking.firewall.allowedTCPPorts = [ 8448 ];
networking.firewall.allowedTCPPorts = [8448];
}

View file

@ -1,32 +0,0 @@
{ config, flake, lib, ... }:
let
# Find element in list config.services.matrix-synapse.settings.listeners
# that sets type = "metrics"
listenerWithMetrics = lib.findFirst
(listener:
listener.type == "metrics")
(throw "Found no matrix-synapse.settings.listeners.*.type containing string metrics")
config.services.matrix-synapse.settings.listeners
;
synapseMetricsPort = "${toString listenerWithMetrics.port}";
in
{
age.secrets.nachtigall-metrics-nginx-basic-auth = {
file = "${flake.self}/secrets/nachtigall-metrics-nginx-basic-auth.age";
mode = "600";
owner = "nginx";
};
services.nginx.virtualHosts = {
"nachtigall.pub.solar" = {
enableACME = true;
addSSL = true;
basicAuthFile = "${config.age.secrets.nachtigall-metrics-nginx-basic-auth.path}";
locations."/metrics" = {
proxyPass = "http://127.0.0.1:${toString(config.services.prometheus.exporters.node.port)}";
};
locations."/_synapse/metrics" = {
proxyPass = "http://127.0.0.1:${synapseMetricsPort}";
};
};
};
}

View file

@ -1,43 +0,0 @@
{ ... }:
{
systemd.tmpfiles.rules = [
"d '/srv/www/miom.space' 0750 hakkonaut hakkonaut - -"
];
services.nginx.virtualHosts = {
"www.miom.space" = {
enableACME = true;
addSSL = true;
extraConfig = ''
error_log /dev/null;
access_log /dev/null;
'';
locations."/" = {
extraConfig = ''
return 301 https://miom.space$request_uri;
'';
};
};
"miom.space" = {
enableACME = true;
forceSSL = true;
extraConfig = ''
error_log /dev/null;
access_log /dev/null;
'';
locations = {
"/" = {
root = "/srv/www/miom.space";
index = "index.html";
tryFiles = "$uri $uri/ =404";
};
};
};
};
}

View file

@ -1,4 +1,6 @@
{ lib, ... }: {
{ ... }:
{
systemd.tmpfiles.rules = [
"d '/srv/www/pub.solar' 0750 hakkonaut hakkonaut - -"
];
@ -7,12 +9,6 @@
"www.pub.solar" = {
enableACME = true;
addSSL = true;
extraConfig = ''
error_log /dev/null;
access_log /dev/null;
'';
locations."/" = {
extraConfig = ''
return 301 https://pub.solar$request_uri;
@ -25,23 +21,18 @@
enableACME = true;
forceSSL = true;
extraConfig = ''
error_log /dev/null;
access_log /dev/null;
'';
locations = {
# serve base domain pub.solar for mastodon.pub.solar
# https://masto.host/mastodon-usernames-different-from-the-domain-used-for-installation/
# serve base domain pub.solar for mastodon.pub.solar
# https://masto.host/mastodon-usernames-different-from-the-domain-used-for-installation/
"/.well-known/host-meta" = {
extraConfig = ''
return 301 https://mastodon.pub.solar$request_uri;
'';
};
# Tailscale OIDC webfinger requirement plus Mastodon webfinger redirect
# Tailscale OIDC webfinger requirement plus Mastodon webfinger redirect
"/.well-known/webfinger" = {
# Redirect requests that match /.well-known/webfinger?resource=* to Mastodon
# Redirect requests that match /.well-known/webfinger?resource=* to Mastodon
extraConfig = ''
if ($arg_resource) {
return 301 https://mastodon.pub.solar$request_uri;
@ -52,22 +43,6 @@
'';
};
# Responsible disclosure information https://securitytxt.org/
"/.well-known/security.txt" = let
securityTXT = lib.lists.foldr (a: b: a + "\n" + b) "" [
"Contact: mailto:admins@pub.solar"
"Expires: 2025-01-04T23:00:00.000Z"
"Encryption: https://keys.openpgp.org/vks/v1/by-fingerprint/8A8987ADE3736C8CA2EB315A9B809EBBDD62BAE3"
"Preferred-Languages: en,de"
"Canonical: https://pub.solar/.well-known/security.txt"
];
in {
extraConfig = ''
add_header Content-Type text/plain;
return 200 '${securityTXT}';
'';
};
"/satzung" = {
extraConfig = ''
return 302 https://cloud.pub.solar/s/iaKqiW25QJpHPYs;

View file

@ -1,14 +1,13 @@
{ config
, lib
, pkgs
, self
, ...
}:
let
{
config,
lib,
pkgs,
self,
...
}: let
acmeEmailAddress = "admins@pub.solar";
webserverGroup = "hakkonaut";
in
{
in {
services.nginx = {
enable = true;
group = webserverGroup;
@ -21,22 +20,15 @@ in
recommendedProxySettings = true;
recommendedTlsSettings = true;
appendHttpConfig = ''
# https://my.f5.com/manage/s/article/K51798430
proxy_headers_hash_bucket_size 128;
'';
appendConfig = ''
# Number of CPU cores
worker_processes 8;
'';
eventsConfig = ''
worker_connections 1024;
# https://nginx.org/en/docs/hash.html
proxy_headers_hash_max_size 1024;
'';
};
security.acme = {
acceptTerms = true;
defaults.email = acmeEmailAddress;
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
networking.firewall.allowedTCPPorts = [80 443];
}

View file

@ -1,8 +1,9 @@
{ flake
, config
, lib
, pkgs
, ...
{
flake,
config,
lib,
pkgs,
...
}: {
services.nginx.virtualHosts."stream.pub.solar" = {
enableACME = true;

View file

@ -1,13 +0,0 @@
{ config
, ...
}: {
services.prometheus = {
exporters = {
node = {
enable = true;
enabledCollectors = [ "systemd" ];
port = 9002;
};
};
};
}

View file

@ -1,46 +0,0 @@
{ config
, lib
, pkgs
, flake
, ...
}: {
age.secrets.nachtigall-metrics-prometheus-basic-auth-password = {
file = "${flake.self}/secrets/nachtigall-metrics-prometheus-basic-auth-password.age";
mode = "600";
owner = "promtail";
};
services.promtail = {
enable = true;
configuration = {
server = {
http_listen_port = 9080;
grpc_listen_port = 0;
};
positions = {
filename = "/tmp/positions.yaml";
};
clients = [{
url = "https://flora-6.pub.solar/loki/api/v1/push";
basic_auth = {
username = "hakkonaut";
password_file = "${config.age.secrets.nachtigall-metrics-prometheus-basic-auth-password.path}";
};
}];
scrape_configs = [{
job_name = "journal";
journal = {
max_age = "24h";
labels = {
job = "systemd-journal";
host = "nachtigall";
};
};
relabel_configs = [{
source_labels = [ "__journal__systemd_unit" ];
target_label = "unit";
}];
}];
};
};
}

View file

@ -1,8 +1,9 @@
{ flake
, config
, lib
, pkgs
, ...
{
flake,
config,
lib,
pkgs,
...
}:
{
age.secrets.searx-environment = {
@ -32,7 +33,7 @@
chmod-socket = "660";
};
environmentFile = config.age.secrets.searx-environment.path;
environmentFile = config.age.secrets.searx-environment.path;
settings = {
use_default_settings = true;

View file

@ -1,9 +0,0 @@
{ ... }:
{
services.tmate-ssh-server = {
enable = true;
port = 2222;
openFirewall = true;
host = "tmate.pub.solar";
};
}

View file

@ -4,9 +4,4 @@
mode = "400";
owner = "root";
};
age.secrets."restic-repo-storagebox" = {
file = "${flake.self}/secrets/restic-repo-storagebox.age";
mode = "400";
owner = "root";
};
}

View file

@ -1,7 +1,8 @@
{ flake
, config
, pkgs
, ...
{
flake,
config,
pkgs,
...
}: {
# Use GRUB2 as the boot loader.
# We don't use systemd-boot because Hetzner uses BIOS legacy boot.

View file

@ -1,39 +1,31 @@
{ flake, ... }:
{ ... }:
{
imports =
[
# Include the results of the hardware scan.
[ # Include the results of the hardware scan.
./hardware-configuration.nix
./configuration.nix
./networking.nix
./wireguard.nix
./backups.nix
./apps/nginx.nix
./apps/collabora.nix
./apps/coturn.nix
./apps/forgejo.nix
./apps/keycloak.nix
./apps/mailman.nix
./apps/mastodon.nix
./apps/mediawiki.nix
./apps/nextcloud.nix
./apps/owncast.nix
./apps/nginx-mastodon.nix
./apps/nginx-mastodon-files.nix
./apps/nginx-prometheus-exporters.nix
./apps/nginx-website.nix
./apps/nginx-website-miom.nix
./apps/opensearch.nix
./apps/owncast.nix
./apps/postgresql.nix
./apps/prometheus-exporters.nix
./apps/promtail.nix
./apps/searx.nix
./apps/tmate.nix
./apps/matrix/irc.nix
./apps/matrix/matrix-hookshot.nix
./apps/matrix/mautrix-telegram.nix
./apps/matrix/synapse.nix
./apps/nginx-matrix.nix

View file

@ -5,8 +5,7 @@
{
imports =
[
(modulesPath + "/installer/scan/not-detected.nix")
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "ahci" "nvme" ];
@ -15,38 +14,32 @@
boot.extraModulePackages = [ ];
fileSystems."/" =
{
device = "root_pool/root";
{ device = "root_pool/root";
fsType = "zfs";
};
fileSystems."/var/lib" =
{
device = "root_pool/data";
{ device = "root_pool/data";
fsType = "zfs";
};
fileSystems."/var/lib/postgresql" =
{
device = "root_pool/data/postgresql";
{ device = "root_pool/data/postgresql";
fsType = "zfs";
};
fileSystems."/var/lib/docker" =
{
device = "root_pool/data/docker";
{ device = "root_pool/data/docker";
fsType = "zfs";
};
fileSystems."/boot1" =
{
device = "/dev/disk/by-uuid/5493-EFF5";
{ device = "/dev/disk/by-uuid/5493-EFF5";
fsType = "vfat";
};
fileSystems."/boot2" =
{
device = "/dev/disk/by-uuid/5494-BA1E";
{ device = "/dev/disk/by-uuid/5494-BA1E";
fsType = "vfat";
};

View file

@ -1,8 +1,4 @@
{
config,
pkgs,
flake,
... }:
{ config, pkgs, ... }:
{
networking.hostName = "nachtigall";

View file

@ -1,40 +0,0 @@
{
config,
pkgs,
flake,
... }:
{
networking.firewall.allowedUDPPorts = [ 51820 ];
age.secrets.wg-private-key.file = "${flake.self}/secrets/nachtigall-wg-private-key.age";
networking.wireguard.interfaces = {
wg-ssh = {
listenPort = 51820;
mtu = 1300;
ips = [
"10.7.6.1/32"
"fd00:fae:fae:fae:fae:1::/96"
];
privateKeyFile = config.age.secrets.wg-private-key.path;
peers = flake.self.logins.admins.wireguardDevices ++ [
{ # flora-6.pub.solar
endpoint = "80.71.153.210:51820";
publicKey = "jtSR5G2P/nm9s8WrVc26Xc/SQLupRxyXE+5eIeqlsTU=";
allowedIPs = [ "10.7.6.2/32" "fd00:fae:fae:fae:fae:2::/96" ];
}
];
};
};
services.openssh.listenAddresses = [
{
addr = "10.7.6.1";
port = 22;
}
{
addr = "[fd00:fae:fae:fae:fae:1::]";
port = 22;
}
];
}

View file

@ -5,17 +5,17 @@ let
});
flake =
import
(
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
)
{
src = builtins.path {
path = ../../.;
name = "projectRoot";
};
(
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
)
{
src = builtins.path {
path = ../../.;
name = "projectRoot";
};
};
in
flake
flake

View file

@ -1,5 +1,4 @@
{ ... }:
let
{...}: let
inherit (default.inputs.nixos) lib;
host = configs.${hostname} or configs.PubSolarOS;
@ -7,4 +6,4 @@ let
default = (import ../.).defaultNix;
hostname = lib.fileContents /etc/hostname;
in
host
host

View file

@ -1,18 +1,16 @@
{ self, lib, inputs, ... }: {
# Configuration common to all Linux systems
flake = {
lib =
let
callLibs = file: import file { inherit lib; };
in
rec {
## Define your own library functions here!
#id = x: x;
## Or in files, containing functions that take {lib}
#foo = callLibs ./foo.nix;
## In configs, they can be used under "lib.our"
lib = let
callLibs = file: import file {inherit lib;};
in rec {
## Define your own library functions here!
#id = x: x;
## Or in files, containing functions that take {lib}
#foo = callLibs ./foo.nix;
## In configs, they can be used under "lib.our"
deploy = import ./deploy.nix { inherit inputs lib; };
};
deploy = import ./deploy.nix { inherit inputs lib; };
};
};
}

View file

@ -5,8 +5,7 @@
* Licensed under the MIT license
*/
{ lib, inputs }:
let
{ lib, inputs }: let
# https://github.com/serokell/deploy-rs#overall-usage
system = "x86_64-linux";
pkgs = import inputs.nixpkgs { inherit system; };
@ -17,59 +16,57 @@ let
(self: super: { deploy-rs = { inherit (pkgs) deploy-rs; lib = super.deploy-rs.lib; }; })
];
};
getFqdn = c:
let
net = c.config.networking;
fqdn =
if (net ? domain) && (net.domain != null)
then "${net.hostName}.${net.domain}"
else net.hostName;
in
getFqdn = c: let
net = c.config.networking;
fqdn =
if (net ? domain) && (net.domain != null)
then "${net.hostName}.${net.domain}"
else net.hostName;
in
fqdn;
in
{
in {
mkDeployNodes = systemConfigurations: extraConfig:
/*
*
Synopsis: mkNodes _systemConfigurations_ _extraConfig_
/*
*
Synopsis: mkNodes _systemConfigurations_ _extraConfig_
Generate the `nodes` attribute expected by deploy-rs
where _systemConfigurations_ are `nodes`.
Generate the `nodes` attribute expected by deploy-rs
where _systemConfigurations_ are `nodes`.
_systemConfigurations_ should take the form of a flake's
_nixosConfigurations_. Note that deploy-rs does not currently support
deploying to darwin hosts.
_systemConfigurations_ should take the form of a flake's
_nixosConfigurations_. Note that deploy-rs does not currently support
deploying to darwin hosts.
_extraConfig_, if specified, will be merged into each of the
nodes' configurations.
_extraConfig_, if specified, will be merged into each of the
nodes' configurations.
Example _systemConfigurations_ input:
Example _systemConfigurations_ input:
```
{
hostname-1 = {
fastConnection = true;
sshOpts = [ "-p" "25" ];
};
hostname-2 = {
sshOpts = [ "-p" "19999" ];
sshUser = "root";
};
}
```
*
*/
```
{
hostname-1 = {
fastConnection = true;
sshOpts = [ "-p" "25" ];
};
hostname-2 = {
sshOpts = [ "-p" "19999" ];
sshUser = "root";
};
}
```
*
*/
lib.recursiveUpdate
(lib.mapAttrs
(
_: c: {
hostname = getFqdn c;
profiles.system = {
user = "root";
path = deployPkgs.deploy-rs.lib.activate.nixos c;
};
}
)
systemConfigurations)
extraConfig;
(lib.mapAttrs
(
_: c: {
hostname = getFqdn c;
profiles.system = {
user = "root";
path = deployPkgs.deploy-rs.lib.activate.nixos c;
};
}
)
systemConfigurations)
extraConfig;
}

View file

@ -1,72 +0,0 @@
{
axeman = rec {
sshPubKeys = {
axeman-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNeQYLFauAbzDyIbKC86NUh9yZfiyBm/BtIdkcpZnSU axeman@tuxnix";
};
secretEncryptionKeys = sshPubKeys;
wireguardDevices = [
{
# tuxnix
publicKey = "fTvULvdsc92binFaBV+uWwFi33bi8InShcaPnoxUZEA=";
allowedIPs = [ "10.7.6.203/32" "fd00:fae:fae:fae:fae:203::/96" ];
}
];
};
b12f = rec {
sshPubKeys = {
b12f-gpg = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDVbUEOgciblRPOCaCkkwfYoKLjmJ6JKxnfg6MY7sN3W1/N4AsC27bvYPkYI66d4M3Ygi6nztaUrIIKBOPZrQtS0vx1jqosmcDwBMttNI7u4LdSDjGMEGB4zJdfR60HFuzpSNaBI/nKMWcAxr8v1KODy/mKTQ7fnMDN15OhvE7sAZe26B6IptUbG1DLuouezd4AW0OwQ3c6hVIuv5eF96OKrwFZ9XpNyYAashy8WTYqJWJRb71DV8oiqT9b3sN0Dy+7nUAPcLvJdwUDGjHQvnklgFUupKtrPhpRWqgJ41l4ebb1DCxmoL2zpdVohUK4eVC9ELdplvXtK+EJIJ1lKcDAYduYcxk//3+EdUDH0IkfXvz0Tomryu2BeyxURdMPzQh+ctHUWNI49tByx/mWrEqSu+XdgvtcumVg+jNUZKL9eA++xxuOan7H/OyshptLugZHd2e9JNM34NEOUEptq7LtHD5pEdXRV1ZT1IOsuSoDtdX14GeP2GSl21eKLnvSu9g8nGULIsx9hI3CrrlvvL9JU+Aymb4iEvqLhDeUNE643uYQad6P2SuK0kLQ/9Ny0z3y6bgglGn2uDUiAOPd8c+gFRRkMWvAWjWQi3iIR9TYBS4Z+CeYmUv8X2UCRcQPBn1wt69rvE9RcfHqRLZTUE5SpstQ0rXLinXmRA/WQV5Bdw== yubi-gpg";
};
secretEncryptionKeys = {
bbcom = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCmXpOU6vzQiVSSYCoxHYv7wDxC63Qg3dxlAMR6AOzwIABCU5PFFNcO0NWYms/YR7MOViorl+19LCLRABar9JgHU1n+uqxKV6eGph3OPeMp5sN8LAh7C9N+TZj8iJzBxQ3ch+Z/LdmLRwYNJ7KSUI+gwGK6xRS3+z1022Y4P0G0sx7IeCBl4lealQEIIF10ZOfjUdBcLQar7XTc5AxyGKnHCerXHRtccCoadLQujk0AvPXbv3Ma4JwX9X++AnCWRWakqS5UInu2tGuZ/6Hrjd2a9AKWjTaBVDcbYqCvY4XVuMj2/A2bCceFBaoi41apybSk26FSFTU4qiEUNQ6lxeOwG4+1NCXyHe2bGI4VyoxinDYa8vLLzXIRfTRA0qoGfCweXNeWPf0jMqASkUKaSOH5Ot7O5ps34r0j9pWzavDid8QeKJPyhxKuF1a5G4iBEZ0O9vuti60dPSjJPci9oTxbune2/jb7Sa0yO06DtLFJ2ncr5f70s/BDxKk4XIwQLy+KsvzlQEGdY8yA6xv28bOGxL3sQ0HE2pDTsvIbAisVOKzdJeolStL9MM5W8Hg0r/KkGj2bg0TfoRp1xHV9hjKkvJrsQ6okaPvNFeZq0HXzPhWMOVQ+/46z80uaQ1ByRLr3FTwuWJ7F/73ndfxiq6bDE4z2Ji0vOjeWJm6HCxTdGw== hello@benjaminbaedorf.com";
yubi485 = "age1yubikey1qgxuu2x3uzw7k5pg5sp2dv43edhwdz3xuhj7kjqrnw0p8t0l67c5yz9nm6q";
yubi464 = "age1yubikey1qd7szmr9ux2znl4x4hzykkwaru60nr4ufu6kdd88sm7657gjz4x5w0jy4y7";
} // sshPubKeys;
wireguardDevices = [
{ # stroopwafel
publicKey = "NNb7T8Jmn+V2dTZ8T6Fcq7hGomHGDckKoV3kK2oAhSE=";
allowedIPs = [ "10.7.6.200/32" "fd00:fae:fae:fae:fae:200::/96" ];
}
];
};
hensoko = rec {
sshPubKeys = {
hensoko-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEbaQdxp7Flz6ttELe63rn+Nt9g43qJOLih6VCMP4gPb";
hensoko-2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAqkqMYgncrnczcW/0PY+Z+FmNXXpgw6D9JWTTwiainy";
};
secretEncryptionKeys = sshPubKeys;
wireguardDevices = [
{ # judy
publicKey = "I+gN7v1VXkAGoSir6L8aebtLbguvy5nAx1QVDTzdckk=";
allowedIPs = [ "10.7.6.202/32" "fd00:fae:fae:fae:fae:202::/96" ];
}
];
};
teutat3s = {
sshPubKeys = {
teutat3s-1 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFro/k4Mgqyh8yV/7Zwjc0dv60ZM7bROBU9JNd99P/4co6fxPt1pJiU/pEz2Dax/HODxgcO+jFZfvPEuLMCeAl0= YubiKey #10593996 PIV Slot 9a";
};
secretEncryptionKeys = {
teutat3s-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHcU6KPy4b1MQXd6EJhcYwbJu7E+0IrBZF/IP6T7gbMf teutat3s@dumpyourvms";
};
wireguardDevices = [
{ # dumpyourvms
publicKey = "3UrVLQrwXnPAVXPiTAd7eM3fZYxnFSYgKAGpNMUwnUk=";
allowedIPs = [ "10.7.6.201/32" "fd00:fae:fae:fae:fae:201::/96" ];
}
{ # ryzensun
publicKey = "oVF2/s7eIxyVjtG0MhKPx5SZ1JllZg+ZFVF2eVYtPGo=";
allowedIPs = [ "10.7.6.204/32" "fd00:fae:fae:fae:fae:204::/96" ];
}
];
};
}

View file

@ -1,14 +0,0 @@
{ lib, ... }: let
admins = import ./admins.nix;
robots = import ./robots.nix;
in {
flake = {
logins = {
admins = lib.lists.foldl (logins: adminConfig: {
sshPubKeys = logins.sshPubKeys ++ (lib.attrsets.attrValues adminConfig.sshPubKeys);
wireguardDevices = logins.wireguardDevices ++ (if adminConfig ? "wireguardDevices" then adminConfig.wireguardDevices else []);
}) { sshPubKeys = []; wireguardDevices = []; } (lib.attrsets.attrValues admins);
robots.sshPubKeys = lib.attrsets.attrValues robots;
};
};
}

View file

@ -1,15 +1,6 @@
{ pkgs, lib, ... }: {
# Don't expose SSH via public interfaces
networking.firewall.interfaces.wg-ssh.allowedTCPPorts = [ 22 ];
networking.hosts = {
"10.7.6.1" = ["nachtigall.pub.solar"];
"10.7.6.2" = ["flora-6.pub.solar"];
};
{ pkgs, ... }: {
services.openssh = {
enable = true;
openFirewall = lib.mkDefault false;
settings = {
PermitRootLogin = "prohibit-password";
PasswordAuthentication = false;
@ -36,11 +27,14 @@
services.resolved = {
enable = true;
# DNSSEC=false because of random SERVFAIL responses with Greenbaum DNS
# when using allow-downgrade, see https://github.com/systemd/systemd/issues/10579
extraConfig = ''
DNS=193.110.81.0#dns0.eu 185.253.5.0#dns0.eu 2a0f:fc80::#dns0.eu 2a0f:fc81::#dns0.eu 9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
FallbackDNS=5.1.66.255#dot.ffmuc.net 185.150.99.255#dot.ffmuc.net 2001:678:e68:f000::#dot.ffmuc.net 2001:678:ed0:f000::#dot.ffmuc.net
Domains=~.
DNSOverTLS=yes
DNSSEC=false
'';
};
}

View file

@ -1,8 +1,9 @@
{ config
, pkgs
, lib
, flake
, ...
{
config,
pkgs,
lib,
flake,
...
}: {
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
];
@ -13,21 +14,15 @@
gc.automatic = true;
optimise.automatic = true;
registry = {
nixpkgs.flake = flake.inputs.nixpkgs;
unstable.flake = flake.inputs.unstable;
system.flake = flake.self;
};
settings = {
# Improve nix store disk usage
auto-optimise-store = true;
# Prevents impurities in builds
sandbox = true;
# Give root and @wheel special privileges with nix
trusted-users = [ "root" "@wheel" ];
trusted-users = ["root" "@wheel"];
# Allow only group wheel to connect to the nix daemon
allowed-users = [ "@wheel" ];
allowed-users = ["@wheel"];
};
# Generally useful nix option defaults

View file

@ -10,7 +10,7 @@
# Please create this manually the first time.
hostKeys = [ "/etc/secrets/initrd/ssh_host_ed25519_key" ];
authorizedKeys = flake.self.logins.admins.sshPubKeys;
authorizedKeys = flake.self.publicKeys.admins;
};
# this will automatically load the zfs password prompt on login
# and kill the other prompt so boot can continue

View file

@ -2,14 +2,14 @@
users.users.${flake.self.username} = {
name = flake.self.username;
group = flake.self.username;
extraGroups = [ "wheel" "docker" ];
extraGroups = ["wheel" "docker"];
isNormalUser = true;
openssh.authorizedKeys.keys = flake.self.logins.admins.sshPubKeys;
openssh.authorizedKeys.keys = flake.self.publicKeys.admins;
};
users.groups.${flake.self.username} = { };
users.groups.${flake.self.username} = {};
# TODO: Remove when we stop locking ourselves out.
users.users.root.openssh.authorizedKeys.keys = flake.self.logins.admins.sshPubKeys;
users.users.root.openssh.authorizedKeys.keys = flake.self.publicKeys.admins;
users.users.hakkonaut = {
description = "CI and automation user";
@ -19,10 +19,10 @@
uid = 998;
group = "hakkonaut";
isSystemUser = true;
openssh.authorizedKeys.keys = flake.self.logins.robots.sshPubKeys;
openssh.authorizedKeys.keys = flake.self.publicKeys.robots;
};
users.groups.hakkonaut = { };
users.groups.hakkonaut = {};
users.users.root.initialHashedPassword = "$y$j9T$bIN6GjQkmPMllOcQsq52K0$q0Z5B5.KW/uxXK9fItB8H6HO79RYAcI/ZZdB0Djke32";

View file

@ -1,21 +1,18 @@
{ self
, inputs
, ...
{
self,
inputs,
...
}: {
flake = {
nixosModules = rec {
overlays = ({ ... }: {
nixpkgs.overlays = [
(final: prev:
let
unstable = import inputs.unstable {
system = prev.system;
};
in
{
forgejo-runner = unstable.forgejo-runner;
element-themes = prev.callPackage ./pkgs/element-themes { inherit (inputs) element-themes; };
})
(final: prev: {
mastodon = inputs.mastodon-fork.legacyPackages.${prev.system}.mastodon;
forgejo-actions-runner = inputs.unstable.legacyPackages.${prev.system}.forgejo-actions-runner;
mediawiki = inputs.unstable.legacyPackages.${prev.system}.mediawiki;
})
];
});
};

View file

@ -1,9 +0,0 @@
{ stdenvNoCC, jq, element-themes }:
stdenvNoCC.mkDerivation {
src = element-themes;
name = "element-themes";
nativeBuildInputs = [ jq ];
buildPhase = ''
find "$src" -name '*.json' -print0 | xargs -0 jq -s '.' > $out
'';
}

9
public-keys/admins.nix Normal file
View file

@ -0,0 +1,9 @@
{
axeman-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNeQYLFauAbzDyIbKC86NUh9yZfiyBm/BtIdkcpZnSU axeman@tuxnix";
b12f-1 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHx4A8rLYmFgTOp1fDGbbONN8SOT0l5wWrUSYFUcVzMPTyfdT23ZVIdVD5yZCySgi/7PSh5mVmyLIZVIXlNrZJg= @b12f Yubi Main";
b12f-2 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEST9eyAY3nzGYNnqDYfWHu+89LZsOjyKHMqCFvtP7vrgB7F7JbbECjdjAXEOfPDSCVwtMMpq8JJXeRMjpsD0rw= @b12f Yubi Backup";
hensoko-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEbaQdxp7Flz6ttELe63rn+Nt9g43qJOLih6VCMP4gPb";
hensoko-2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAqkqMYgncrnczcW/0PY+Z+FmNXXpgw6D9JWTTwiainy";
teutat3s-1 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFro/k4Mgqyh8yV/7Zwjc0dv60ZM7bROBU9JNd99P/4co6fxPt1pJiU/pEz2Dax/HODxgcO+jFZfvPEuLMCeAl0= YubiKey #10593996 PIV Slot 9a";
}

View file

@ -1,8 +1,8 @@
{ lib, ... }:
{lib, ...}:
{
flake = {
publicKeys = {
admins = lib.attrsets.attrValues (import ./admins.nix);
admins = lib.attrsets.attrValues (import ./admins.nix);
robots = lib.attrsets.attrValues (import ./robots.nix);
};
};

View file

@ -1 +0,0 @@
AGE-PLUGIN-YUBIKEY-1HZCCGQVZH5WV7DCL6V837

View file

@ -1 +0,0 @@
AGE-PLUGIN-YUBIKEY-1EKCCGQVZE64TLZCKYUCW7

View file

@ -1,28 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 iDKjwg FkQYu4K7yxWuKQChw28kOJrZqXDelVmzExig/cEmxjI
apgJOiOv/gLcSRTcAkhzDZyLdiKbnsipnNt6okrZ6os
-> ssh-ed25519 uYcDNw wfyuSGgrFXRAcNSZoBTCz8kJOMeocD1BFwQ1hhO6dD0
J5hhkK/S+RXjDp/kFGOXP1dDxTyKQx5MqhohgKTP8PQ
-> ssh-rsa kFDS0A
arAz7wP/PQBggo5IOFTZrMp/a1eCxCzx5t0QTs07Mfp1mk1h5Xy39VwRB4PIN1Kw
ASRLnBsUmPznZTWJJ+coAjZiISYx0kW0J5BpKmC6g5orxQJHwEieI/c9JZ1KTjUJ
G+Rl0BWfJiOk23SiQaCEs5D9OPQiKpQvE2W6ZUTaRVzRelGlmzSHkx5hAz3yX936
MXdijUFS15sNKDTaoGrql67YRckYHn8ErrvUaSUEdelNOc9ILhCTT+NSM5SG+oh5
B1GVdHf2hrgmTqhKqxwB/DgXmwsOzX5ffa7kV+KqgYypdjVHlLlkWy6RLVQLEYBM
ldLIHY4SjpuShqcsuoakZ8jAx/J5aU/SnnRBxIgWcdwwMPbn2dB89wkiK9kVgpVH
Izj4oO5EJiZr6Fx+iCFnnsuzBrzswRR2zZOJsYo1XY2uP7JEq8F5iClAgN3C7C9V
3gU4Cf61sr4GftKCBnRUGrtohfL5KeXBX7sTpvF9+cmjQWTBB+fF5Q2I6UmOH08Z
8OVAkPQsK+zfNaOD5+J8/JoCIXNqZKBq+ShgQoMEPlUFwe3mgy5ji38s8CY09ehY
DrsWhQw1M9ka8z0hlfP95jQjNlztUn4K/TB7OXUXAKj9/n74b7lmLJ8OMCn4miZ2
EOV9jVyXrCPQF6RujaYOh52OFz3zIRKEINwWwPNfNJY
-> ssh-ed25519 YFSOsg 5H/taWUdjZcoYSFndLcYZPX8JUtK6BJs2ou1oJnT6k0
dTOUWXMuaERYbfHo6AaiM4NfPWKxTk95YFpRkxq06jQ
-> ssh-ed25519 iHV63A KFTTfUVH8bb+ebLc3WefjyFt2YGdfD8cQiK+VURRplI
d75sa9BchGJl1NdVHCZ5s4f/RqV5TE7jBtC02OnOt2E
-> ssh-ed25519 BVsyTA 8BbKlmlVJvPSoZuVazuOyR2YXncwTHAP80hDYpshjz4
I+u3zwtSecaLeOOR1WJ5+fwWTgn31PvW38kkPgGQ4sM
-> X}64s-grease V7
U9Gkb6Sn+PV3lgb6Kzl0ATgibtLzSm//Z60gct7j8F2wVosjicXaWpv+LVfdBo86
JlXZuA
--- zjT2F/dHJX8rxVXgbjZMsToMSPUXPLwbeAhGiNawKlc
­†ÝˆÉ©õÖ‘èËŽ{´ýÍHª™©kÂ0Z•Yê*¯ÿð“òb;—ÕX#æˆ-•Ÿæé£Í®¸´£Ýé&n<>/mxl 9ò<39>|œc K$åÐú&‹þâ*Š$z ÿ1÷zÐ

Binary file not shown.

View file

@ -1,42 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 Y0ZZaw FvsdIE/inJoLVSosWXATnFbAAVjVuf7jlEC3nSUF6Ug
gX84OKgWdfkGBN+NFy11BxIb4WX1z9UkPA4u2Q1uV+g
-> ssh-ed25519 uYcDNw z5Veza0uVwqCqGCGYzGmXPcyaV9HztEN39cWFbSG7yg
UWZQcDP1vMsYoWwMQlr4YmzWYw2EKm/s5zJVHNf2M0U
-> ssh-rsa f5THog
v1kqiU+cx65mvTNeuAhK65eBEk1vmkABRYgcmFIrdr4eY3pru+FaQTfMhTI9HjcO
OTU0YPxxSadbUCaN6Z3QnTv5qowwOQlEsWK+RMsOZgnyRQHa2SIrhfHz7v+n8BTF
8BYB4UBJpD3aLqM7VED6dYls178HUbiq34ohrG2vY5PHE72xTU60amv9NcJhSJPR
twZPiSp3I14MlJU4bboS1YBaEmgxvbXru0DwuoQLw3OUrH7xOggVoSJxm8lVyjR2
oFYS5wdnrhAIEsJ0lTsO5fvq9Dmie7qoL60rbBbue9lPk1nD1NlUe3akd4IIo36R
kDbthUYluVSJON3o/wenSvJDOw3N3t8bu2+/XfWAd2NL9SPBijMQJtqjK8EAtmz9
OjBMjJGQzVdBxRP9U3CWYIwaqYQfWhXXY4AXTwIMsfmeV8ZHZsId3Y156p0NaKg6
NGb7eX/AWmcdNTp8ZCqlb4QexICrVd7XDkNbPHkYPUOdUhaMyS+T7YU8Qs3YWroP
Bw63QMWbvo1l4HO/3HeIKlzIXTjLEi6PjTiWb7vM4GuoCwjdDg5djMEj4nsvDyea
B9EBTEcoP2oj47wgsX0nfV5bKAQ4y8AN4ZNWb00vjN9ybBbLK3q//1DrEWmddieF
t6FyZXvZH0Gf6y5OO56yRp/vmxvKFcvxqUA3P8bPAnw
-> ssh-rsa kFDS0A
c+0wRUbjzdJiBhdKAVlE8yxt1O3t4oQ438F5HjMPohEXSFLiNFi4Y0JQsw6qn3GP
hySsyIoj9G+cI9FDPjTFPmE7O1SHrd2LqBZGukyswDXX8CpwmZ7vfqfK2lCgKfos
SSPiGaYk+HlQF2QfX/xdgQ2PbFXHnDy8LZ9AfZP04PrnK9wqdiEXwmkWZ/Lu1P+V
Wb/28BYxcfkseAprFr/KSJLoNuD9UphRhQwRklmjADnf0lep3vHccxz1Oo5flu5M
AD47r+0bLGM+w3epCF1GyR4L2lEBaD8pkVOt3/zIdjn8nFZVNJwjshToazvnVEd3
Vd9Uas58AyxcT7Dk/QaVO7c5KJDdfSuxnT1zElkM2ZQM4lEueTJYDBJGyfubb30y
Z7re/MsLOh0jNJbb0r1KOkzwpcdm9iyvi26eaGsX7Q1Gb2pzOYFxD1vSUUC6A6Hp
W5X6fKsiBPreYLf5MV6p9r2YJPdX4SJiq4XztQi1PL+ndq1h8wskxk3Pyvk9fhle
iC5owZ8/FikfC/1oEa2KayeLyYB001BUuktevzfH2GmbqLkR9wBGw5vUJzOO4vOW
o8SVCSUxSrG8S+HQksOSXFWywkdBDhqc8eyRUtb+6iqqMA2Q4GDqktSCB1KeBYD6
OalH6bo4H1ddV8LPMOKcFtjmTPuum43C7bNge2rxhgg
-> piv-p256 vRzPNw A/utfOjPG1zs1Lf2FOWDHhJIJW1PIHmKFqFvBZZycHPn
EfGFh9R0PDgskQg00z6thQ1YozT5ZiBhzNN9iTXWDe4
-> piv-p256 zqq/iw A0RjdOkfYmTlYCwM3aFLdXfBimXMGzVh21A5QxZ217xW
7J9cRYpr1uhQPE0VjvLAwyS7jNSK0+qjA9xUMeRwYos
-> ssh-ed25519 YFSOsg w8ljrS1oRdB9RT8Odi5UOPjEtFL3WBlQUAH9Y7gp3WM
xcrbEm66K6mNrJ9+877YEgWUdxW85YyS1z8CGMyYxeE
-> ssh-ed25519 iHV63A O0bMGpauAYAuiAtbITj+lQOS0LuFl/BDVxIUTly8tQM
0Kiu4sNN0joX5D4eB42oQ/iRSntsJI5JNKOmkQeyLGE
-> ssh-ed25519 BVsyTA k/0Rtr9qbFH7V6DyCRtyqdAHU1b7D7DNGV8pPPJmrnk
dJ29gcfSxaVQ46XbW021PxPotZ8ZG2zjostJme9GUZQ
--- 1V0sJP5JIa9GZ0F0hf1GAFX3LNkPSNsxNhqM9cH7Rgc
|¿‘#ø©mÌæR„Ö5wä­ÎQòÅÐf 1Ü ÑÁZ·MUüèOÃfãÜ:GÓ^<5E>ì•!<21>
G29ƒÙ_B­ìdêÿ

Binary file not shown.

Binary file not shown.

View file

@ -1,28 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 Y0ZZaw M6ha3gQ4Oq4PdymYZ5ZG0qGwFlpCYfJdhOBwH9n1gxg
zCtB0PJanufNdV0ShynDT0Z/2jxMFDRby8xsfv6YPaA
-> ssh-ed25519 uYcDNw V89Ll4HJ3ZkQegiCI6gswz736domVgDGSDCA8bZBwHs
W7IrEL+1xUXuVdy6A61z6P+pS/ajTGPL+qv+9Jh8UxI
-> ssh-rsa kFDS0A
SV6QVIW8MCQVB8ABiOGxLTXEMO6rfeG82CktBFtf76WeIYzlkho/IaGgWXoqoIQ0
KC/ev7vNGnB01AOWe/xkuMZDRvK+qGaOLB7wpZG1cJhqSon9oZtztoDjd/Crp5K0
nfeHjY9E/jgFr0KYeaLedw5OJuaOw4YiuKyTThVbpRZwbof30nvHXqrYKPZJi1gq
s5spoWYH2ijZi9mrJojP2ZqK5DJjCteXqP1YHdz3LjxomoDyl5cv/tLNsvrptfxD
FvZMcPrvrC/IWqJ8qGW+f8ENUGyjXxx6jFQ2WN9IMIdJYk5bz458ip3GKqnAlwi3
SZbaxRuEYEoy6ikKGRuXMAwpJd3YXcRcaRdetw0a4grdD6hF21bTl2+LnTb1ydnb
frzeoXaqbBdhEyLpZFAmGLydteIyA/Kl/D/PEJ0MHc0G0EGofMm6YsNJJrP3mQgi
mXC2Kto6WV/JLVEnURayf12rPR1T/VPIyYZ/Xi9HfPh0p3Y21nadPAcEq/PltWgR
AqELfBbVpNtcxTP2pjEJqGskJCYKAmMeM+yQ0moKVmuMWicahMqjQRJO1jnvTwwd
GhJlUO32EuI6Fn6sApthv2FfLrle+x0H4/v9xvHDJIVSmLYtzK+9ueUPn/A1x8X1
lGeJh+ecEV2r630insGAp8WQzyXhraHrn3lgyacwRmA
-> ssh-ed25519 YFSOsg KKhXh/XW7iF7wMA7JD9fbgmty5yVPaSS1vGdHz0Xh0M
eLJc+F/yIR1ckZX/npLI+l3I2iB+OrKBkJAQTkbWVF4
-> ssh-ed25519 iHV63A xoJ7Tr8mKgYVPPeJYBnOHLBY5E0i34vEQR3pMVKxbAc
TKqc9Y/RpnfTP3CNvCearB4FuvNmW0mcGVLh7Ebjzeo
-> ssh-ed25519 BVsyTA LaMK6X/MJyQTQ24p9uHXh75leMcp/akCA2YZACEG03M
psw6sVlNGT8WsG3L9kbXdrhqxp8hIdSF7s4o60jTYgY
-> vcxmk`-grease 8^p$~+LB -G)+N&$^ P)7#7[wX
8TyK2RrSHFuMyFy9YY7ZI6RSduF5hw6xZKhiysVkif4Husb1flN8QVmWtoW8laWz
n8772TmNTcfq5ebUp+UA+S6MVgf75D1GnDumEDH/LbM4LNjRZzyw3nBGu/Q
--- Ouu56e69gTpAY1ouLPlzI/n6geKz1CMmTl8wAVyIDPM
Ÿ·¢5¿ä7W>J@°óðjÁ–€l_ƒ¥«­Ï/œö÷ú=ßÕ»‰4(²<18>²K» µÅÑ¥„zSÌsæ

Binary file not shown.

Binary file not shown.

View file

@ -1,27 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 iDKjwg O7ax7BWOp2BEKA9i4WAmI0hsGoRjSzfAbMb4eRLdoRM
LlddBgKAoFe7qKvq7ixIphiWiO1JzKSyLJ6PSmUd2xA
-> ssh-ed25519 uYcDNw 5gN/+TZa94jPsMsrwXlrb1U8alMnCJq5/EIegIus0SI
NUTWQw6WCZTpKK4EFBL1lxSSnI9WEAb1MB7iFiezDFg
-> ssh-rsa kFDS0A
mXTGOqDXWJSVo58aok+GC2v7Xm/lL/QUrA9H4Ywfz1ksK2O1vZFmmrj9YOGMwtz3
KodmEn8339Oyz0Tw2lSDMJb22OZPxs2q1tYQ33tvj1OXVQygzW1q/RfTPXFtTCVo
alKl2Dbr8esFN+Cfpdh4zHJFab73m6FUDGF2k4O5Gos8eOUiUx1O8WPMDtKgwTqM
Wtbnk0iBiTdgjwdFjkdMnx1bxGxa4pEtqtBdw9UiLwPKoPWJzHg7F9uIWH8L0FkQ
ml7K+pjZMzwWdJwuaLpIB3yCTDiSF4j9Wr74sXjUGQ/atGesIImIGnXEyZ0v6RI2
uRP4gx4zA9eoYcIWpuitgx9VKDwwJjcAyhffbZvTYF2ogtnWtCBIlY5jAtIV5l9I
x0k/FMfq0hGvXOJb976zsW83ZaXVPFpUEV75mweVAUbsnRmML1kyYKAFWF58hSoa
aEmij9hDvPIoQn2f6OTCtWXSJBtJjhxr4uvbKfrvhQojol91cU0w+fDe5rsZzhMk
CksD3JM+OmCpguvl+4jANxPVY58avIjZArOn/UVyM0LLuKFLfRzqpBup6ifv3Wpk
gplElrdz4iGHoEnceCGVJXcxXVbMfB4cr8I5BMK65TgN0pkl+VG6vY/TvgUl5a1C
VjLQxIVg3hEy8mRvIGjjo0R2E8qTkcMn5Bz5mjFJeXI
-> ssh-ed25519 YFSOsg nvVCR2LV8DHU+hIQa19uX9pEhA+NQxMkmBUMDktKOGU
Q9qhrcOeEA3myMqZbptbsWCS9hbm67pF5qO3jARN/bs
-> ssh-ed25519 iHV63A +Pca506lCnqn/+2e3lKVzlLcsa63EgngYry54yiAxA0
hyZZUoRuYjJvhznZBAkRRjq2x6jZvJX0sfj+jigX39c
-> ssh-ed25519 BVsyTA hza+5wLH7L3VyXIwBK/sq5UNR6SC3EnKxQ3ucrVPwXc
BAXKAf2gdMT29ZXEAeq0B54ojrGa9LwfhBK91v68yis
-> !By"-grease
7r6wODXXipdv7nXJ+K653PLYdKOLF1pEvCWeKk8/q49s5ScMqZpGVA
--- zNjNg84OVHL/CbJyutcBz6eWD+71peLb7weZ/EjQaic
r!ï?RUàÕoäE¤~Wü>_íðtÜî=‰*7ëÎt<C38E>=QÔ¹ü[`@ï‹“£BÛ<42>§jedÜ°Í ¢q¤Ño^Ÿ³™P÷±áN­ÜÏ{H^€ª¾j¬°ÚBûh¼:PPµÞ&â™—mܯt

View file

@ -1,31 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 Y0ZZaw FWuk2kYGB+GfoY3rWfeCosoBOLvUHrH7SR8Fv18o+XI
YyOTULtyOJ3vfAOnYSMzeCCyipJ4Fqrr3PJgRtbElJg
-> ssh-ed25519 iDKjwg Bq6lNuS5MOhsU/7ypHw/E70BktIA+SmN6e3pvrIqRBQ
Xo0OOUXfOkPQfArhqSJyiAkH5lxcJIAO7M5krkCZNfc
-> ssh-ed25519 uYcDNw EfB1B4CSNk8Oe5B7T+KSl9O5OsCrulaLOjR3PBtxpSk
xJxkmBSENc5JosdRiEAC3a41WI6TmTlTxm+lclup+g4
-> ssh-rsa kFDS0A
dYH3A43wClFnDQp8m3ZnhTK5d8LeG6ZkqDQ5dS1yB//4G5TaUnMqOp5Q2G1gbgXY
Zu9qYOHdUydn5HIRSwBXj/KbBm5xJ1zFImOszn7S5mk4iReHFyTnSzAi4utatQcY
DEjGnvKKRoc7ih08+F44kq6DYnhUBFqF8eigQZIsyeWpiW6C1FzasL0KnXoedPG2
AYJForNB8zKp7a2Evxi0MY7a+ldHAekktz1Fta2u9MvrWUtqP/yLqJhCwCNvos7J
kG+XO4j0kiOQCIO9TOeLAu59+VCVM64mY+dp+xc8tX0fWuu7ItSAh6jRHzfgSKjC
qDJc/1YpUG1EnYSH39mfVox3ndeMuVrG6Q1h509jZuxsw/zoDsbY3bbhTaUQ3X8Y
5ShCponnEGBLqeSm1gALCAnlgu8IS4gL6ePKuAhN0qMYj6iiXP/Ugp3lTcv1TvFD
KINnV/tas1CO3PApQm6JgijHEPT9zyUbqR/xN06+OCWbg4hHuEix+0OhM1T5w2xC
KvKF30iUK0tU2hZvKdku2MpbP4N0cQLqBEWiyrUKHRMCdXi3kyO5D84UdWXvETAt
BfEvZ8ZG5fiSXzbPLxVqObXFZUirLuWomWtstqkDuadL9xJkTcsbr8ZCCNpPhxdL
oOfao+tox3RBilAS3AfQVhrPvD2rVUptm+0nPtnO3rY
-> ssh-ed25519 YFSOsg T2OdtA0kY4DqDIxE1QxMV5aCygvKlI5LgXQ+QYYuOko
l0Kzo02jGISCT1zrGf5soXYj7FMVrN/9REF3Zscbmik
-> ssh-ed25519 iHV63A 75daRGD2TQ/mXRsckaH9sGGkHMkLxgHFhn0eDdkDsU8
TXeoLqfU0ywQucPayYoG43Gr56uZoYIWaK9F2YJJ0FM
-> ssh-ed25519 BVsyTA J/xNtG1CAzfoiKPsnWwDp4pId7d3MywXpfhKAmpze3I
8uMO07Se/6krP79flt+XZfjIsw12kWsoD6LqZyLG70M
-> B-grease y3$t@ ; Bs *w
dUrvWB09znCDyvO7RnduMguc9pWTn19q1fc0MHFUXk7WQWns+4kpJIX1qljB5hz/
NPAbNzwMDQKj6awHAth1iFLaEw
--- rI4jrrXCiUpV/EzGsla+lxONmL5/Eel/LODoIM80jcM
˜_°0àÆ7Jˆq•[÷ç<>è'/ù‘õŽi„Ü<E2809E>Òl°mÙ
ÌÂ!JPþ¼>œ… wk¡ž·³¤+ é™)ÚÈPhUÜóç²O=>k=?ÂTÐ

View file

@ -1,30 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 Y0ZZaw CxhF1nK1+6OmJb/68UQ4mBIqxGgr8ngkNsL9dfaPN2s
jZ/JBaTCjFcL0SAGVx5ECDanVn4TGt0g2yn2OQOP9iY
-> ssh-ed25519 iDKjwg D/xqqA53Lw2UQJesg27wmK/UNCV+s914mvMlbKN1rhg
AOg0SkPvSotuSHk33zVfRxB0wn67a29YWc/itDUZ/LQ
-> ssh-ed25519 uYcDNw /QdfQUJmBMQZ+KRCst1gA0LqFGvM1K91ZL/RIRP+qBc
Ttksa44OdwLuRmgYPC2rIn+wy/SooRPUq8gQTR+pF0k
-> ssh-rsa kFDS0A
L9MGJFRceqbge3EF/rqXdT13jt9faxP1NmfRB3i2mrTasvCaovc/62bA0UmlsB/9
Y3hIzo28d6pZRcMm91l6PhWV0M33YNwPQf87vd7klv++1aMIdZ6/jHsQiohIBkRd
4pBe6rrx/lUqEqfQVYUFPfRE50ufkw+hRw/NJCvcBgHgNhhDoeb8keWRPZhhuv0Z
f0eP9ORKjeKxjv3tsIPjiE7aqxE1zTdrnSr7FuqklJhMYRdwVv+2ofNEh05hU6pR
VL4AS7d6Di/0dWTWc/Je2ytsrdio2v0rPAUXN1fyTh4AtrAmGQzUXNWnr4sB5xH9
QlL0Ea3IwndJSDNkqc4qI3JL0vx6QMUbsuNcMmVWSMkODP+gNQYXQNbnwNfeMAnE
V++WBfyrA8+V+ES+usqeWoOXjApzShn+gnrV0DHHXDAzNR+M647rQcsLePSyNjf/
NKd7Z8VfEq7m65AxmSHPezSGdICMf63WLG/Bffj9rWiQxaoiayGF8jbALpXlu93X
txOw8pK7zA8xFEBujmkrDPH3sJFPLOgOMYa0uuCMbrCGxeJ34nuQMhSUTamESSXb
AD3AgUrRvte1iXwy2PoZGolRLZfdq9zcAfFyq9KvIhvz/8b2F+KbqHQlAiKVPw8p
XQo4sXcDAmF251WSCJGN1C6Doxj/6XLuWILbkobQqoI
-> ssh-ed25519 YFSOsg FtIvWeEXI9blJIFAWMacXgPym5ePGXsuiOR+Gh3b3R8
0rp/NIu4kCCt05Is2+eRdUmgNX8QPMsDPhZWIejnBDA
-> ssh-ed25519 iHV63A 85G1w54UHS/gFcLvsXyYLPXvLHkJl3YQCi8ehb+ZrU8
lXDaMXlPw5ohaaYpiEkCNAmE2tJ2824ydmp9EakPtD8
-> ssh-ed25519 BVsyTA XimcaonVCGGyyCfn3BSX/a7zjJkWeaVY/xAcdNDrl1U
RaqpXzUd54qrkYYRbRTUclTpZdZx2us42lkP6wBxjBM
-> CWM8^B-grease
HvBgzYx54YVP0M6pk1bp9qegLscQ4tHIV9DZhr7jnrW41adgY0D39wnE2IgIRc6g
keRHAr7QVqdPy/kr+u0GwQ1MGFKI8Jss8vRxKwv/UgQfmg
--- dJWXhQRYjxWchTW1u3TrF7KvQIOdrOvkEC7oUtFcGeE
l>qFÞ®/®â@tË\Å&Zò êÄ:„Þ@ ò ÚKÏx©ªr¾áHK ûĦb0ÊÖ—5Ëm¸/

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