fmt
This commit is contained in:
parent
f4615cbae9
commit
a7734d312b
25 changed files with 328 additions and 222 deletions
|
@ -56,9 +56,7 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
boot = {
|
boot = {
|
||||||
kernelParams = [
|
kernelParams = [ "quiet" ];
|
||||||
"quiet"
|
|
||||||
];
|
|
||||||
loader.efi.canTouchEfiVariables = true;
|
loader.efi.canTouchEfiVariables = true;
|
||||||
initrd.availableKernelModules = [
|
initrd.availableKernelModules = [
|
||||||
"xhci_pci"
|
"xhci_pci"
|
||||||
|
|
|
@ -83,9 +83,7 @@ in
|
||||||
|
|
||||||
services.power-profiles-daemon.enable = false;
|
services.power-profiles-daemon.enable = false;
|
||||||
services.upower.enable = true;
|
services.upower.enable = true;
|
||||||
boot.extraModulePackages = [
|
boot.extraModulePackages = [ cpupower ] ++ optional enable_perf_policy x86_energy_perf_policy;
|
||||||
cpupower
|
|
||||||
] ++ optional enable_perf_policy x86_energy_perf_policy;
|
|
||||||
|
|
||||||
services.tlp = {
|
services.tlp = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -17,7 +17,11 @@ in
|
||||||
|
|
||||||
programs.xonsh = {
|
programs.xonsh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
config = lib.concatLines (lib.mapAttrsToList (name: value: ''aliases["${name}"] = "${value}"'') config.environment.shellAliases);
|
config = lib.concatLines (
|
||||||
|
lib.mapAttrsToList (
|
||||||
|
name: value: ''aliases["${name}"] = "${value}"''
|
||||||
|
) config.environment.shellAliases
|
||||||
|
);
|
||||||
package = pkgs.xonsh.override {
|
package = pkgs.xonsh.override {
|
||||||
extraPackages =
|
extraPackages =
|
||||||
ps: with ps; [
|
ps: with ps; [
|
||||||
|
|
|
@ -9,12 +9,17 @@ let
|
||||||
nivSources = import ./nix/sources.nix;
|
nivSources = import ./nix/sources.nix;
|
||||||
asGithubRef = src: "github:${src.owner}/${src.repo}/${src.rev}";
|
asGithubRef = src: "github:${src.owner}/${src.repo}/${src.rev}";
|
||||||
|
|
||||||
build_target = let env_host = builtins.getEnv "NIXOS_TARGET_HOST"; in if env_host != "" then env_host else builtins.replaceStrings ["\n"] [""] (lib.toLower (builtins.readFile /proc/sys/kernel/hostname));
|
build_target =
|
||||||
|
let
|
||||||
|
env_host = builtins.getEnv "NIXOS_TARGET_HOST";
|
||||||
|
in
|
||||||
|
if env_host != "" then
|
||||||
|
env_host
|
||||||
|
else
|
||||||
|
builtins.replaceStrings [ "\n" ] [ "" ] (lib.toLower (builtins.readFile /proc/sys/kernel/hostname));
|
||||||
|
|
||||||
host_modules = {
|
host_modules = {
|
||||||
grimmauld-nixos = [
|
grimmauld-nixos = [ ./specific/grimm-nixos-laptop/configuration.nix ];
|
||||||
./specific/grimm-nixos-laptop/configuration.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
grimmauld-nixos-server = [
|
grimmauld-nixos-server = [
|
||||||
./specific/grimmauld-nixos-server/configuration.nix
|
./specific/grimmauld-nixos-server/configuration.nix
|
||||||
|
|
|
@ -1,22 +1,40 @@
|
||||||
{ config, lib, pkgs, ...}: let
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
bridge_port = 9005; # netstat -nlp | grep 9005
|
bridge_port = 9005; # netstat -nlp | grep 9005
|
||||||
in {
|
in
|
||||||
nixpkgs.overlays = [ (final: prev: { matrix-appservice-discord = prev.matrix-appservice-discord.overrideAttrs (old: {
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
matrix-appservice-discord = prev.matrix-appservice-discord.overrideAttrs (old: {
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
owner = "t2bot";
|
owner = "t2bot";
|
||||||
repo = "matrix-appservice-discord";
|
repo = "matrix-appservice-discord";
|
||||||
rev = "8361ca6121bf1f0902154baa538cb6d5766e477f";
|
rev = "8361ca6121bf1f0902154baa538cb6d5766e477f";
|
||||||
hash = "sha256-oXon6pFJgqQ1uBLtsSVNH7XSOpxxJYqpW2n9cFrs3sU=";
|
hash = "sha256-oXon6pFJgqQ1uBLtsSVNH7XSOpxxJYqpW2n9cFrs3sU=";
|
||||||
};
|
};
|
||||||
patches = (let oldPatches = old.patches or []; in if oldPatches == null then [] else oldPatches) ++ [ ./patch_bridge_perms.patch ];
|
patches =
|
||||||
|
(
|
||||||
|
let
|
||||||
|
oldPatches = old.patches or [ ];
|
||||||
|
in
|
||||||
|
if oldPatches == null then [ ] else oldPatches
|
||||||
|
)
|
||||||
|
++ [ ./patch_bridge_perms.patch ];
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
});})
|
});
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
age.secrets.matrix_discord_bridge_token.file = ../secrets/matrix_discord_bridge_token.age;
|
age.secrets.matrix_discord_bridge_token.file = ../secrets/matrix_discord_bridge_token.age;
|
||||||
|
|
||||||
services.matrix-synapse-next.settings.app_service_config_files = [ "/var/lib/matrix-synapse/discord-registration.yaml" ];
|
services.matrix-synapse-next.settings.app_service_config_files = [
|
||||||
|
"/var/lib/matrix-synapse/discord-registration.yaml"
|
||||||
|
];
|
||||||
|
|
||||||
services.matrix-appservice-discord = {
|
services.matrix-appservice-discord = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -31,13 +49,12 @@ in {
|
||||||
disablePresence = true;
|
disablePresence = true;
|
||||||
disableTypingNotifications = true;
|
disableTypingNotifications = true;
|
||||||
};
|
};
|
||||||
# logging.console = "silly";
|
# logging.console = "silly";
|
||||||
};
|
};
|
||||||
serviceDependencies = ["matrix-synapse.target"];
|
serviceDependencies = [ "matrix-synapse.target" ];
|
||||||
port = bridge_port;
|
port = bridge_port;
|
||||||
localpart = "_discord_";
|
localpart = "_discord_";
|
||||||
package = pkgs.matrix-appservice-discord;
|
package = pkgs.matrix-appservice-discord;
|
||||||
environmentFile = config.age.secrets.matrix_discord_bridge_token.path;
|
environmentFile = config.age.secrets.matrix_discord_bridge_token.path;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
mail_host = "mail.${domain}";
|
mail_host = "mail.${domain}";
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
security.acme.certs."${domain}".extraDomainNames = [ mail_host ];
|
security.acme.certs."${domain}".extraDomainNames = [ mail_host ];
|
||||||
|
|
||||||
# services.dovecot2.sieve.extensions = [ "fileinto" ]; # sives break without this for some reason
|
# services.dovecot2.sieve.extensions = [ "fileinto" ]; # sives break without this for some reason
|
||||||
mailserver = {
|
mailserver = {
|
||||||
enable = true;
|
enable = true;
|
||||||
fqdn = mail_host;
|
fqdn = mail_host;
|
||||||
|
@ -16,7 +17,7 @@ in {
|
||||||
loginAccounts = {
|
loginAccounts = {
|
||||||
"contact@${domain}" = {
|
"contact@${domain}" = {
|
||||||
hashedPasswordFile = ./mailpass/contact;
|
hashedPasswordFile = ./mailpass/contact;
|
||||||
aliases = ["kontakt@${domain}"];
|
aliases = [ "kontakt@${domain}" ];
|
||||||
};
|
};
|
||||||
"admin@${domain}" = {
|
"admin@${domain}" = {
|
||||||
hashedPasswordFile = ./mailpass/admin;
|
hashedPasswordFile = ./mailpass/admin;
|
||||||
|
@ -35,7 +36,8 @@ in {
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
virtualHosts."${mail_host}" = { # you should NOT be here from a browser :P
|
virtualHosts."${mail_host}" = {
|
||||||
|
# you should NOT be here from a browser :P
|
||||||
serverName = mail_host;
|
serverName = mail_host;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
useACMEHost = domain;
|
useACMEHost = domain;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
{ ... }: {
|
{ ... }:
|
||||||
|
{
|
||||||
services.fail2ban = {
|
services.fail2ban = {
|
||||||
enable = true;
|
enable = true;
|
||||||
maxretry = 5;
|
maxretry = 5;
|
||||||
ignoreIP = [
|
ignoreIP = [
|
||||||
# Whitelist some subnets
|
# Whitelist some subnets
|
||||||
"10.0.0.0/8" "172.16.0.0/12" "192.168.0.0/16"
|
"10.0.0.0/8"
|
||||||
|
"172.16.0.0/12"
|
||||||
|
"192.168.0.0/16"
|
||||||
"matrix.org"
|
"matrix.org"
|
||||||
"app.element.io" # don't ratelimit matrix users
|
"app.element.io" # don't ratelimit matrix users
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
{ lib, config, inputs, pkgs, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
inputs,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
gitea_host = "git.${domain}";
|
gitea_host = "git.${domain}";
|
||||||
gitea_port = 8081;
|
gitea_port = 8081;
|
||||||
gitea_ssh_port = 2222;
|
gitea_ssh_port = 2222;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
services.gitea = {
|
services.gitea = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
|
@ -17,22 +24,19 @@ in {
|
||||||
START_SSH_SERVER = true;
|
START_SSH_SERVER = true;
|
||||||
BUILTIN_SSH_SERVER_USER = "git";
|
BUILTIN_SSH_SERVER_USER = "git";
|
||||||
SSH_PORT = gitea_ssh_port;
|
SSH_PORT = gitea_ssh_port;
|
||||||
# SSH_LISTEN_HOST="::"; # fixme?
|
# SSH_LISTEN_HOST="::"; # fixme?
|
||||||
# SSH_AUTHORIZED_PRINCIPALS_ALLOW="username";
|
# SSH_AUTHORIZED_PRINCIPALS_ALLOW="username";
|
||||||
};
|
};
|
||||||
# log.LEVEL = "Debug";
|
# log.LEVEL = "Debug";
|
||||||
"ssh.minimum_key_sizes".RSA = 2048;
|
"ssh.minimum_key_sizes".RSA = 2048;
|
||||||
"git.timeout".MIGRATE = 6000;
|
"git.timeout".MIGRATE = 6000;
|
||||||
};
|
};
|
||||||
lfs.enable = true;
|
lfs.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [ gitea ];
|
||||||
gitea
|
|
||||||
];
|
|
||||||
|
|
||||||
|
security.acme.certs."${domain}".extraDomainNames = [ gitea_host ];
|
||||||
security.acme.certs."${domain}".extraDomainNames = [ gitea_host];
|
|
||||||
networking.firewall.allowedTCPPorts = [ gitea_ssh_port ];
|
networking.firewall.allowedTCPPorts = [ gitea_ssh_port ];
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
|
@ -47,4 +51,3 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
grafana_host = "grafana.${domain}";
|
grafana_host = "grafana.${domain}";
|
||||||
grafana_port = 8082;
|
grafana_port = 8082;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
age.secrets.grafana_admin_pass = {
|
age.secrets.grafana_admin_pass = {
|
||||||
file = ../secrets/grafana_admin_pass.age;
|
file = ../secrets/grafana_admin_pass.age;
|
||||||
owner = "grafana";
|
owner = "grafana";
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
{ lib, config, inputs, pkgs, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
inputs,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
root_email = "contact@${domain}";
|
root_email = "contact@${domain}";
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
security.acme = {
|
security.acme = {
|
||||||
acceptTerms = true;
|
acceptTerms = true;
|
||||||
defaults.email = root_email;
|
defaults.email = root_email;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
{ config, ... } :
|
{ config, ... }:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
mastodon_host = "mastodon.${domain}";
|
mastodon_host = "mastodon.${domain}";
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
security.acme.certs."${domain}".extraDomainNames = [ mastodon_host ];
|
security.acme.certs."${domain}".extraDomainNames = [ mastodon_host ];
|
||||||
services.mastodon = {
|
services.mastodon = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
{ lib, config, inputs, pkgs, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
inputs,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
matrix_host = "matrix.${domain}";
|
matrix_host = "matrix.${domain}";
|
||||||
in {
|
in
|
||||||
services.postgresql = {
|
{
|
||||||
|
services.postgresql = {
|
||||||
enable = true;
|
enable = true;
|
||||||
# CREATE DATABASE synapse ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse;
|
# CREATE DATABASE synapse ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse;
|
||||||
ensureDatabases = [ "synapse" ];
|
ensureDatabases = [ "synapse" ];
|
||||||
|
@ -16,15 +23,15 @@ services.postgresql = {
|
||||||
];
|
];
|
||||||
authentication = pkgs.lib.mkOverride 10 ''
|
authentication = pkgs.lib.mkOverride 10 ''
|
||||||
#type database DBuser auth-method
|
#type database DBuser auth-method
|
||||||
local all postgres peer
|
local all postgres peer
|
||||||
local all all peer
|
local all all peer
|
||||||
host all all 127.0.0.1/32 md5
|
host all all 127.0.0.1/32 md5
|
||||||
host synapse matrix-synapse ::1/128 md5
|
host synapse matrix-synapse ::1/128 md5
|
||||||
host nextcloud nextcloud ::1/128 md5
|
host nextcloud nextcloud ::1/128 md5
|
||||||
host all all ::1/128 md5
|
host all all ::1/128 md5
|
||||||
local replication all peer
|
local replication all peer
|
||||||
host replication all 127.0.0.1/32 md5
|
host replication all 127.0.0.1/32 md5
|
||||||
host replication all ::1/128 md5
|
host replication all ::1/128 md5
|
||||||
'';
|
'';
|
||||||
identMap = ''
|
identMap = ''
|
||||||
# ArbitraryMapName systemUser DBUser
|
# ArbitraryMapName systemUser DBUser
|
||||||
|
@ -37,9 +44,11 @@ host replication all ::1/128 md5
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.postgresql.postStart = let
|
systemd.services.postgresql.postStart =
|
||||||
|
let
|
||||||
password_file_path = config.age.secrets.synapse_db_pass.path;
|
password_file_path = config.age.secrets.synapse_db_pass.path;
|
||||||
in ''
|
in
|
||||||
|
''
|
||||||
$PSQL -tA <<'EOF'
|
$PSQL -tA <<'EOF'
|
||||||
DO $$
|
DO $$
|
||||||
DECLARE password TEXT;
|
DECLARE password TEXT;
|
||||||
|
@ -71,10 +80,10 @@ host replication all ::1/128 md5
|
||||||
enable_registration = true;
|
enable_registration = true;
|
||||||
registration_requires_token = true;
|
registration_requires_token = true;
|
||||||
registration_shared_secret_path = config.age.secrets.synapse_registration_shared_secret.path;
|
registration_shared_secret_path = config.age.secrets.synapse_registration_shared_secret.path;
|
||||||
# enable_registration_without_verification = true;
|
# enable_registration_without_verification = true;
|
||||||
# mainLogConfig = ./matrix_synapse_log_config.yaml;
|
# mainLogConfig = ./matrix_synapse_log_config.yaml;
|
||||||
|
|
||||||
# registrations_require_3pid = [ "email" ];
|
# registrations_require_3pid = [ "email" ];
|
||||||
|
|
||||||
database = {
|
database = {
|
||||||
name = "psycopg2";
|
name = "psycopg2";
|
||||||
|
@ -125,16 +134,16 @@ host replication all ::1/128 md5
|
||||||
locations."/.well-known/matrix/server" = {
|
locations."/.well-known/matrix/server" = {
|
||||||
return = "200 '{\"m.server\":\"${matrix_host}:443\"}'";
|
return = "200 '{\"m.server\":\"${matrix_host}:443\"}'";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
default_type application/json;
|
default_type application/json;
|
||||||
add_header Access-Control-Allow-Origin *;
|
add_header Access-Control-Allow-Origin *;
|
||||||
add_header Accept-Ranges bytes;'';
|
add_header Accept-Ranges bytes;'';
|
||||||
};
|
};
|
||||||
locations."/.well-known/matrix/client" = {
|
locations."/.well-known/matrix/client" = {
|
||||||
return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${matrix_host}\"}}'";
|
return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${matrix_host}\"}}'";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
add_header Access-Control-Allow-Origin *;
|
add_header Access-Control-Allow-Origin *;
|
||||||
default_type application/json;
|
default_type application/json;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
locations."/_matrix" = {
|
locations."/_matrix" = {
|
||||||
proxyPass = "http://$synapse_backend";
|
proxyPass = "http://$synapse_backend";
|
||||||
|
@ -171,5 +180,5 @@ default_type application/json;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
# networking.firewall.allowedTCPPorts = [ 8448 8008 ];
|
# networking.firewall.allowedTCPPorts = [ 8448 8008 ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ config, ... } :
|
{ config, ... }:
|
||||||
let
|
let
|
||||||
|
in
|
||||||
in {
|
{
|
||||||
age.secrets = {
|
age.secrets = {
|
||||||
matrix_mjolnir_pass = {
|
matrix_mjolnir_pass = {
|
||||||
file = ../secrets/matrix_mjolnir_pass.age;
|
file = ../secrets/matrix_mjolnir_pass.age;
|
||||||
|
@ -22,9 +22,7 @@ in {
|
||||||
services.mjolnir = {
|
services.mjolnir = {
|
||||||
enable = true;
|
enable = true;
|
||||||
homeserverUrl = config.services.matrix-synapse-next.settings.public_baseurl;
|
homeserverUrl = config.services.matrix-synapse-next.settings.public_baseurl;
|
||||||
protectedRooms = [
|
protectedRooms = [ "https://matrix.to/#/!zDkrFrfuMIKbqYFbFv:grimmauld.de" ];
|
||||||
"https://matrix.to/#/!zDkrFrfuMIKbqYFbFv:grimmauld.de"
|
|
||||||
];
|
|
||||||
managementRoom = "!kgfXXqEYHGgToIwhMP:grimmauld.de";
|
managementRoom = "!kgfXXqEYHGgToIwhMP:grimmauld.de";
|
||||||
pantalaimon = {
|
pantalaimon = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -37,23 +35,25 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
services.logrotate.checkConfig = false; # needed or this explodes
|
services.logrotate.checkConfig = false; # needed or this explodes
|
||||||
containers.mjolnirtle = let
|
containers.mjolnirtle =
|
||||||
|
let
|
||||||
baseurl = config.services.matrix-synapse-next.settings.public_baseurl;
|
baseurl = config.services.matrix-synapse-next.settings.public_baseurl;
|
||||||
pass_file = config.age.secrets.matrix_mjolnir_tle_pass.path;
|
pass_file = config.age.secrets.matrix_mjolnir_tle_pass.path;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
privateNetwork = false; # don't want nat
|
privateNetwork = false; # don't want nat
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
bindMounts."${pass_file}".isReadOnly = true;
|
bindMounts."${pass_file}".isReadOnly = true;
|
||||||
config = { config, ... }: {
|
config =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
system.stateVersion = "unstable";
|
system.stateVersion = "unstable";
|
||||||
# tle mjolnir
|
# tle mjolnir
|
||||||
services.logrotate.checkConfig = false;
|
services.logrotate.checkConfig = false;
|
||||||
services.mjolnir = {
|
services.mjolnir = {
|
||||||
enable = true;
|
enable = true;
|
||||||
homeserverUrl = baseurl;
|
homeserverUrl = baseurl;
|
||||||
protectedRooms = [
|
protectedRooms = [ "https://matrix.to/#/!BgDBnHgMgilMMnPMyp:grimmauld.de" ];
|
||||||
"https://matrix.to/#/!BgDBnHgMgilMMnPMyp:grimmauld.de"
|
|
||||||
];
|
|
||||||
managementRoom = "!NQedmlMeoQErGgAwxm:grimmauld.de";
|
managementRoom = "!NQedmlMeoQErGgAwxm:grimmauld.de";
|
||||||
pantalaimon = {
|
pantalaimon = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
{ lib, pkgs, config, ...} :
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
nextcloud_host = "cloud.${domain}";
|
nextcloud_host = "cloud.${domain}";
|
||||||
nextcloud_port = 8083;
|
nextcloud_port = 8083;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
services.postgresql = {
|
services.postgresql = {
|
||||||
enable = true;
|
enable = true;
|
||||||
ensureDatabases = [ "nextcloud" ];
|
ensureDatabases = [ "nextcloud" ];
|
||||||
|
@ -46,13 +52,13 @@ in {
|
||||||
package = pkgs.nextcloud28;
|
package = pkgs.nextcloud28;
|
||||||
caching.redis = true;
|
caching.redis = true;
|
||||||
|
|
||||||
# extraApps = with config.services.nextcloud.package.packages.apps; [
|
# extraApps = with config.services.nextcloud.package.packages.apps; [
|
||||||
# news contacts calendar tasks;
|
# news contacts calendar tasks;
|
||||||
# ];
|
# ];
|
||||||
config = {
|
config = {
|
||||||
adminpassFile = config.age.secrets.nextcloud_admin_pass.path;
|
adminpassFile = config.age.secrets.nextcloud_admin_pass.path;
|
||||||
dbuser = "nextcloud";
|
dbuser = "nextcloud";
|
||||||
dbhost= "localhost:${builtins.toString config.services.postgresql.settings.port}";
|
dbhost = "localhost:${builtins.toString config.services.postgresql.settings.port}";
|
||||||
dbtype = "pgsql";
|
dbtype = "pgsql";
|
||||||
};
|
};
|
||||||
settings = {
|
settings = {
|
||||||
|
@ -64,7 +70,6 @@ in {
|
||||||
port = 6379;
|
port = 6379;
|
||||||
timeout = 0.0;
|
timeout = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
phpOptions = {
|
phpOptions = {
|
||||||
"opcache.interned_strings_buffer" = "12";
|
"opcache.interned_strings_buffer" = "12";
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
{ config, ... } :
|
{ config, ... }:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
prometheus_host = "prometheus.${domain}";
|
prometheus_host = "prometheus.${domain}";
|
||||||
prometheus_port = 9090; # netstat -nlp | grep 9090
|
prometheus_port = 9090; # netstat -nlp | grep 9090
|
||||||
in {
|
in
|
||||||
security.acme.certs."${domain}".extraDomainNames = [ prometheus_host];
|
{
|
||||||
|
security.acme.certs."${domain}".extraDomainNames = [ prometheus_host ];
|
||||||
|
|
||||||
services.prometheus = {
|
services.prometheus = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -13,13 +14,15 @@ in {
|
||||||
scrapeConfigs = [
|
scrapeConfigs = [
|
||||||
{
|
{
|
||||||
job_name = "chrysalis";
|
job_name = "chrysalis";
|
||||||
static_configs = [{
|
static_configs = [
|
||||||
|
{
|
||||||
targets = [
|
targets = [
|
||||||
"127.0.0.1:${toString config.services.prometheus.exporters.node.port}"
|
"127.0.0.1:${toString config.services.prometheus.exporters.node.port}"
|
||||||
"127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}"
|
"127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}"
|
||||||
"127.0.0.1:${toString config.services.prometheus.exporters.postgres.port}"
|
"127.0.0.1:${toString config.services.prometheus.exporters.postgres.port}"
|
||||||
];
|
];
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
exporters = {
|
exporters = {
|
||||||
|
@ -44,7 +47,7 @@ in {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
useACMEHost = domain;
|
useACMEHost = domain;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
# proxyPass = "http://127.0.0.1:${builtins.toString config.services.prometheus.port}";
|
# proxyPass = "http://127.0.0.1:${builtins.toString config.services.prometheus.port}";
|
||||||
return = "307 https://${domain}"; # nuh uh, no raw prometheus access for you!
|
return = "307 https://${domain}"; # nuh uh, no raw prometheus access for you!
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{config, pkgs, ...}: let
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
root_email = "contact@${domain}";
|
root_email = "contact@${domain}";
|
||||||
ptero_host = "ptero.${domain}";
|
ptero_host = "ptero.${domain}";
|
||||||
|
@ -7,13 +8,14 @@
|
||||||
local_bridge = "ptero-local-br";
|
local_bridge = "ptero-local-br";
|
||||||
ptero_ver = "1.11.5";
|
ptero_ver = "1.11.5";
|
||||||
ptero_port = "8042";
|
ptero_port = "8042";
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
users.users.${panel_user} = {
|
users.users.${panel_user} = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
extraGroups = ["docker"];
|
extraGroups = [ "docker" ];
|
||||||
group = panel_user;
|
group = panel_user;
|
||||||
};
|
};
|
||||||
users.groups.${panel_user} = {};
|
users.groups.${panel_user} = { };
|
||||||
|
|
||||||
age.secrets.ptero_env = {
|
age.secrets.ptero_env = {
|
||||||
file = ../secrets/ptero_env.age;
|
file = ../secrets/ptero_env.age;
|
||||||
|
@ -24,15 +26,15 @@ in {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
serviceConfig.Type = "oneshot";
|
serviceConfig.Type = "oneshot";
|
||||||
script =''
|
script = ''
|
||||||
mkdir -p ${DATA_DIR}/database
|
mkdir -p ${DATA_DIR}/database
|
||||||
mkdir -p ${DATA_DIR}/cache
|
mkdir -p ${DATA_DIR}/cache
|
||||||
mkdir -p ${DATA_DIR}/panel/var
|
mkdir -p ${DATA_DIR}/panel/var
|
||||||
mkdir -p ${DATA_DIR}/panel/logs
|
mkdir -p ${DATA_DIR}/panel/logs
|
||||||
mkdir -p ${DATA_DIR}/panel/nginx
|
mkdir -p ${DATA_DIR}/panel/nginx
|
||||||
chown ${panel_user}:${panel_user} -R ${DATA_DIR}
|
chown ${panel_user}:${panel_user} -R ${DATA_DIR}
|
||||||
chmod +777 -R ${DATA_DIR}
|
chmod +777 -R ${DATA_DIR}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualisation.oci-containers.backend = "podman";
|
virtualisation.oci-containers.backend = "podman";
|
||||||
|
@ -43,8 +45,11 @@ chmod +777 -R ${DATA_DIR}
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
serviceConfig.Type = "oneshot";
|
serviceConfig.Type = "oneshot";
|
||||||
script = let podmancli = "${config.virtualisation.podman.package}/bin/podman";
|
script =
|
||||||
in ''
|
let
|
||||||
|
podmancli = "${config.virtualisation.podman.package}/bin/podman";
|
||||||
|
in
|
||||||
|
''
|
||||||
check=$(${podmancli} pod ls | grep "ptero" || true)
|
check=$(${podmancli} pod ls | grep "ptero" || true)
|
||||||
if [ -z "$check" ]; then
|
if [ -z "$check" ]; then
|
||||||
${podmancli} pod create -p "${ptero_port}:80" ptero
|
${podmancli} pod create -p "${ptero_port}:80" ptero
|
||||||
|
@ -54,7 +59,6 @@ chmod +777 -R ${DATA_DIR}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
virtualisation.oci-containers.containers."ptero-mysql" = {
|
virtualisation.oci-containers.containers."ptero-mysql" = {
|
||||||
image = "library/mysql:8.0";
|
image = "library/mysql:8.0";
|
||||||
workdir = "${DATA_DIR}/database";
|
workdir = "${DATA_DIR}/database";
|
||||||
|
@ -64,14 +68,17 @@ chmod +777 -R ${DATA_DIR}
|
||||||
"MYSQL_DATABASE" = "panel";
|
"MYSQL_DATABASE" = "panel";
|
||||||
};
|
};
|
||||||
environmentFiles = [ config.age.secrets.ptero_env.path ];
|
environmentFiles = [ config.age.secrets.ptero_env.path ];
|
||||||
volumes = ["${DATA_DIR}/database:/var/lib/mysql" "${DATA_DIR}/database:${DATA_DIR}/database"];
|
volumes = [
|
||||||
cmd=["--default-authentication-plugin=mysql_native_password"];
|
"${DATA_DIR}/database:/var/lib/mysql"
|
||||||
|
"${DATA_DIR}/database:${DATA_DIR}/database"
|
||||||
|
];
|
||||||
|
cmd = [ "--default-authentication-plugin=mysql_native_password" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualisation.oci-containers.containers."ptero-cache" = {
|
virtualisation.oci-containers.containers."ptero-cache" = {
|
||||||
image = "redis:alpine";
|
image = "redis:alpine";
|
||||||
workdir = "${DATA_DIR}/cache";
|
workdir = "${DATA_DIR}/cache";
|
||||||
volumes = ["${DATA_DIR}/cache:${DATA_DIR}/cache"];
|
volumes = [ "${DATA_DIR}/cache:${DATA_DIR}/cache" ];
|
||||||
extraOptions = [ "--pod=ptero" ];
|
extraOptions = [ "--pod=ptero" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,8 +103,8 @@ chmod +777 -R ${DATA_DIR}
|
||||||
"MAIL_PASSWORD" = "";
|
"MAIL_PASSWORD" = "";
|
||||||
"MAIL_ENCRYPTION" = "true";
|
"MAIL_ENCRYPTION" = "true";
|
||||||
|
|
||||||
"APP_ENV"= "production";
|
"APP_ENV" = "production";
|
||||||
"APP_ENVIRONMENT_ONLY"= "false";
|
"APP_ENVIRONMENT_ONLY" = "false";
|
||||||
"CACHE_DRIVER" = "redis";
|
"CACHE_DRIVER" = "redis";
|
||||||
"SESSION_DRIVER" = "redis";
|
"SESSION_DRIVER" = "redis";
|
||||||
"QUEUE_DRIVER" = "redis";
|
"QUEUE_DRIVER" = "redis";
|
||||||
|
@ -106,7 +113,7 @@ chmod +777 -R ${DATA_DIR}
|
||||||
"TRUSTED_PROXIES" = "*";
|
"TRUSTED_PROXIES" = "*";
|
||||||
};
|
};
|
||||||
labels = {
|
labels = {
|
||||||
"traefik.http.routers.pterodactyl_panel.entrypoints"="web";
|
"traefik.http.routers.pterodactyl_panel.entrypoints" = "web";
|
||||||
};
|
};
|
||||||
environmentFiles = [ config.age.secrets.ptero_env.path ];
|
environmentFiles = [ config.age.secrets.ptero_env.path ];
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
{ lib, config, inputs, pkgs, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
inputs,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
puffer_port = 8080;
|
puffer_port = 8080;
|
||||||
|
@ -6,14 +12,15 @@ let
|
||||||
puffer_host = "puffer.${domain}";
|
puffer_host = "puffer.${domain}";
|
||||||
tlemap_host = "tlemap.${domain}";
|
tlemap_host = "tlemap.${domain}";
|
||||||
tlemap_port = 8100;
|
tlemap_port = 8100;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
services.pufferpanel = {
|
services.pufferpanel = {
|
||||||
enable = true;
|
enable = true;
|
||||||
environment = {
|
environment = {
|
||||||
PUFFER_WEB_HOST = ":${builtins.toString puffer_port}";
|
PUFFER_WEB_HOST = ":${builtins.toString puffer_port}";
|
||||||
PUFFER_DAEMON_SFTP_HOST = ":${builtins.toString puffer_sftp_port}";
|
PUFFER_DAEMON_SFTP_HOST = ":${builtins.toString puffer_sftp_port}";
|
||||||
};
|
};
|
||||||
extraPackages = with pkgs; [];
|
extraPackages = with pkgs; [ ];
|
||||||
extraGroups = [ "docker" ];
|
extraGroups = [ "docker" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,12 +42,21 @@ in {
|
||||||
proxyPass = "http://127.0.0.1:${builtins.toString tlemap_port}";
|
proxyPass = "http://127.0.0.1:${builtins.toString tlemap_port}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
security.acme.certs."${domain}".extraDomainNames = [ puffer_host tlemap_host ];
|
security.acme.certs."${domain}".extraDomainNames = [
|
||||||
networking.firewall.allowedTCPPorts = [ puffer_sftp_port 25565 25566 25567 25568 7270 ];
|
puffer_host
|
||||||
|
tlemap_host
|
||||||
|
];
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
puffer_sftp_port
|
||||||
|
25565
|
||||||
|
25566
|
||||||
|
25567
|
||||||
|
25568
|
||||||
|
7270
|
||||||
|
];
|
||||||
|
|
||||||
# virtualisation.podman.enable = true;
|
# virtualisation.podman.enable = true;
|
||||||
virtualisation.docker.enable = true;
|
virtualisation.docker.enable = true;
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
{config, pkgs, ...}: let
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
git_user = "Grimmauld";
|
git_user = "Grimmauld";
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
(writeShellScriptBin "silent-add" "git add --intent-to-add $@ ; git update-index --assume-unchanged $@")
|
(writeShellScriptBin "silent-add" "git add --intent-to-add $@ ; git update-index --assume-unchanged $@")
|
||||||
(writeShellScriptBin "systemd-owner" "systemctl show -pUser,UID $@")
|
(writeShellScriptBin "systemd-owner" "systemctl show -pUser,UID $@")
|
||||||
|
@ -39,7 +41,12 @@ in {
|
||||||
'';
|
'';
|
||||||
packages.myVimPackage = with pkgs.vimPlugins; {
|
packages.myVimPackage = with pkgs.vimPlugins; {
|
||||||
# loaded on launch
|
# loaded on launch
|
||||||
start = [ vim-nix vim-scala fugitive autoclose-nvim ];
|
start = [
|
||||||
|
vim-nix
|
||||||
|
vim-scala
|
||||||
|
fugitive
|
||||||
|
autoclose-nvim
|
||||||
|
];
|
||||||
# manually loadable by calling `:packadd $plugin-name`
|
# manually loadable by calling `:packadd $plugin-name`
|
||||||
opt = [ ];
|
opt = [ ];
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,10 @@ let
|
||||||
contabo_nix_pub = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDCCsCsjhJleQCBm0gwnUj5R7zewC0SoRvth1qhXtUCeWM3KHkX+CjiHvVaHs+ftYE9uCe5jwVMB+b4UPkNU8EfQeL99iOYtkcn+fEQqjUJe/x/Pn0NxfS1DCvFpI6s3485ysDmagi640XN9S+eIiiMZIqWTsIlUtkEwGF0wuv+xqzbBOlUtIkL2AMpMeFCFovOcpu2JwEAIpDUiW+FanAFImw6rvNmpAtaaFGheYOGJwnpVfdaIeRPqEN3fqtIRBIQVgxt25BGYX83vaIH3Y/OaEKMGUa/4Fe/PRpGJyhCtdae6kcVfx57hs0e7/HezjgfS90HTu2cy6BrJOvGUspCjCbdElddfboE9wtBeNYsgjUOdU926m2M1tTn7Ex6ZMOQRKRlVFac6Yo+CedRTe4u6lkrWcsDdmnajel7uxoW8VMEre/CBCtK+ZlGaDwJjIVNCn7J3KZBKeaB/t/1iSr7/buaXYh5VV1Q0gv0mtvx+D7YLngaTv3sLFpLV8Wk1mgXt9R2hHxcRBKGJYx5RWa8aMHK62RP1GRc5yCzREj2Mc5qUJyd8oirnQYms/BsaDybUJde9IL4REeMzIBYyi/MG/+OAIUSAtdYygABWco+Swv4jP52UODHikcmyejHdFhRngsb4IYzGZXbS5pobkCyqCMJ20v5BG3WNFmujAlXRw==";
|
contabo_nix_pub = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDCCsCsjhJleQCBm0gwnUj5R7zewC0SoRvth1qhXtUCeWM3KHkX+CjiHvVaHs+ftYE9uCe5jwVMB+b4UPkNU8EfQeL99iOYtkcn+fEQqjUJe/x/Pn0NxfS1DCvFpI6s3485ysDmagi640XN9S+eIiiMZIqWTsIlUtkEwGF0wuv+xqzbBOlUtIkL2AMpMeFCFovOcpu2JwEAIpDUiW+FanAFImw6rvNmpAtaaFGheYOGJwnpVfdaIeRPqEN3fqtIRBIQVgxt25BGYX83vaIH3Y/OaEKMGUa/4Fe/PRpGJyhCtdae6kcVfx57hs0e7/HezjgfS90HTu2cy6BrJOvGUspCjCbdElddfboE9wtBeNYsgjUOdU926m2M1tTn7Ex6ZMOQRKRlVFac6Yo+CedRTe4u6lkrWcsDdmnajel7uxoW8VMEre/CBCtK+ZlGaDwJjIVNCn7J3KZBKeaB/t/1iSr7/buaXYh5VV1Q0gv0mtvx+D7YLngaTv3sLFpLV8Wk1mgXt9R2hHxcRBKGJYx5RWa8aMHK62RP1GRc5yCzREj2Mc5qUJyd8oirnQYms/BsaDybUJde9IL4REeMzIBYyi/MG/+OAIUSAtdYygABWco+Swv4jP52UODHikcmyejHdFhRngsb4IYzGZXbS5pobkCyqCMJ20v5BG3WNFmujAlXRw==";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
"nextcloud_pass.age".publicKeys = [ laptop_pub laptop_pub_ed ];
|
"nextcloud_pass.age".publicKeys = [
|
||||||
|
laptop_pub
|
||||||
|
laptop_pub_ed
|
||||||
|
];
|
||||||
|
|
||||||
# "duckdns_token.age".publicKeys = [ contabo_nix_pub ];
|
# "duckdns_token.age".publicKeys = [ contabo_nix_pub ];
|
||||||
"synapse_db_pass.age".publicKeys = [ contabo_nix_pub ];
|
"synapse_db_pass.age".publicKeys = [ contabo_nix_pub ];
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
{ lib, config, inputs, pkgs, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
inputs,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
in {
|
in
|
||||||
imports = [
|
{
|
||||||
./hardware-configuration.nix
|
imports = [ ./hardware-configuration.nix ];
|
||||||
];
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
80
|
||||||
|
443
|
||||||
|
];
|
||||||
networking.hostName = "grimmauld-nixos-server";
|
networking.hostName = "grimmauld-nixos-server";
|
||||||
networking.domain = "grimmauld.de";
|
networking.domain = "grimmauld.de";
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
{
|
{
|
||||||
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
|
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
|
||||||
boot.loader.grub.device = "/dev/sda";
|
boot.loader.grub.device = "/dev/sda";
|
||||||
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "xen_blkfront" "vmw_pvscsi" ];
|
boot.initrd.availableKernelModules = [
|
||||||
|
"ata_piix"
|
||||||
|
"uhci_hcd"
|
||||||
|
"xen_blkfront"
|
||||||
|
"vmw_pvscsi"
|
||||||
|
];
|
||||||
boot.initrd.kernelModules = [ "nvme" ];
|
boot.initrd.kernelModules = [ "nvme" ];
|
||||||
fileSystems."/" = { device = "/dev/sda3"; fsType = "ext4"; };
|
fileSystems."/" = {
|
||||||
|
device = "/dev/sda3";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
OMP_NUM_THREADS = "8";
|
OMP_NUM_THREADS = "8";
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,9 @@
|
||||||
{ remote = "Videos"; }
|
{ remote = "Videos"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
packages = with pkgs; lib.optionals config.grimmShared.graphical [
|
packages =
|
||||||
|
with pkgs;
|
||||||
|
lib.optionals config.grimmShared.graphical [
|
||||||
webcord
|
webcord
|
||||||
discord
|
discord
|
||||||
obs-studio
|
obs-studio
|
||||||
|
|
Loading…
Reference in a new issue