added stuff
This commit is contained in:
parent
937f28770d
commit
236b8c2a6b
907 changed files with 70990 additions and 0 deletions
5
nyx/modules/core/roles/server/system/default.nix
Normal file
5
nyx/modules/core/roles/server/system/default.nix
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
imports = [
|
||||
./services
|
||||
];
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
{
|
||||
inputs,
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services.bincache.atticd;
|
||||
|
||||
domain = "cache" + config.networking.domain;
|
||||
inherit (cfg.settings) host port;
|
||||
in {
|
||||
imports = [inputs.atticd.nixosModules.atticd];
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [pkgs.attic-client];
|
||||
|
||||
networking.firewall.allowedTCPPorts = [port];
|
||||
|
||||
users = {
|
||||
groups.atticd = {};
|
||||
users."atticd" = {
|
||||
isSystemUser = true;
|
||||
group = "atticd";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.atticd = {
|
||||
serviceConfig.DynamicUser = lib.mkForce false;
|
||||
};
|
||||
|
||||
services = {
|
||||
atticd = {
|
||||
enable = true;
|
||||
credentialsFile = config.age.secrets.attic-env.path;
|
||||
user = "atticd";
|
||||
group = "atticd";
|
||||
|
||||
settings = {
|
||||
listen = "${host}:${toString port}"; # this listens ONLY locally
|
||||
database.url = "postgresql:///atticd?host=/run/postgresql";
|
||||
|
||||
allowed-hosts = ["${domain}"];
|
||||
api-endpoint = "https://${domain}/";
|
||||
require-proof-of-possession = false;
|
||||
|
||||
/*
|
||||
storage = {
|
||||
type = "s3";
|
||||
region = "helios";
|
||||
bucket = "attic-cache";
|
||||
endpoint = "https://s3.notashelf.dev";
|
||||
};
|
||||
*/
|
||||
|
||||
chunking = let
|
||||
KB = x: x * 1024;
|
||||
in {
|
||||
nar-size-threshold = KB 64;
|
||||
min-size = KB 16;
|
||||
avg-size = KB 64;
|
||||
max-size = KB 256;
|
||||
};
|
||||
|
||||
garbage-collection = {
|
||||
interval = "24 hours";
|
||||
default-retention-period = "6 weeks";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."${domain}" = {
|
||||
extraConfig = ''
|
||||
client_max_body_size 0;
|
||||
|
||||
proxy_read_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
'';
|
||||
|
||||
locations."/" = {
|
||||
recommendedProxySettings = true;
|
||||
proxyPass = "http://${host}:${toString port}";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
imports = [
|
||||
./atticd.nix
|
||||
./harmonia.nix
|
||||
];
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services.bincache.harmonia;
|
||||
|
||||
inherit (cfg.settings) port host;
|
||||
in {
|
||||
config = mkIf cfg.enable {
|
||||
users = {
|
||||
groups.harmonia = {};
|
||||
users.harmonia = {
|
||||
isSystemUser = true;
|
||||
createHome = true;
|
||||
group = "harmonia";
|
||||
home = "/srv/storage/harmonia";
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
harmonia = {
|
||||
enable = true;
|
||||
# NOTE: generated via
|
||||
# $ nix-store --generate-binary-cache-key cache.domain.tld-1 /var/lib/secrets/harmonia.secret /var/lib/secrets/harmonia.pub
|
||||
signKeyPath = config.age.secrets.harmonia-privateKey.path;
|
||||
settings = {
|
||||
# default ip:hostname to bind to
|
||||
bind = "${host}:${toString port}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nix.settings.allowed-users = ["harmonia"];
|
||||
|
||||
services.nginx = {
|
||||
virtualHosts."cache.notashelf.dev" =
|
||||
{
|
||||
locations."/".extraConfig = ''
|
||||
proxy_pass http://127.0.0.1:${toString port};
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect http:// https://;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
zstd on;
|
||||
zstd_types application/x-nix-archive;
|
||||
'';
|
||||
|
||||
quic = true;
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
imports = [
|
||||
./mongodb.nix
|
||||
./postgresql.nix
|
||||
./mysql.nix
|
||||
./redis.nix
|
||||
./garage.nix
|
||||
];
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.database.garage.enable {
|
||||
networking.firewall.allowedTCPPorts = [3900 3901 3903];
|
||||
|
||||
environment.systemPackages = [
|
||||
pkgs.garage
|
||||
];
|
||||
|
||||
systemd = let
|
||||
sc = config.systemd.services.garage.serviceConfig;
|
||||
gc = config.services.garage.settings;
|
||||
in {
|
||||
tmpfiles.rules = [
|
||||
"d /srv/storage/garage 0755 ${sc.User} ${sc.Group}"
|
||||
"d '${gc.data_dir}' 0700 ${sc.User} ${sc.Group} - -"
|
||||
"d '${gc.metadata_dir}' 0700 ${sc.User} ${sc.Group} - -"
|
||||
];
|
||||
|
||||
services.garage = {
|
||||
# this lets custom data directory work by having a real user own the service process
|
||||
# the user and its group need to be created in the users section
|
||||
serviceConfig = {
|
||||
User = "garage";
|
||||
Group = "garage";
|
||||
ReadWritePaths = [gc.data_dir gc.metadata_dir];
|
||||
RequiresMountsFor = [gc.data_dir];
|
||||
DynamicUser = false;
|
||||
PrivateTmp = true;
|
||||
ProtectSystem = true;
|
||||
};
|
||||
|
||||
environment = {
|
||||
RUST_LOG = "debug";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
groups.garage = {};
|
||||
|
||||
users.garage = {
|
||||
isSystemUser = true;
|
||||
createHome = false;
|
||||
group = "garage";
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
garage = {
|
||||
enable = true;
|
||||
package = pkgs.garage;
|
||||
|
||||
environmentFile = config.age.secrets.garage-env.path;
|
||||
|
||||
settings = {
|
||||
metadata_dir = "/srv/storage/garage/meta";
|
||||
data_dir = "/srv/storage/garage/data";
|
||||
metadata_fsync = false; # synchronous mode for the database engine
|
||||
|
||||
db_engine = "lmdb";
|
||||
replication_mode = "none";
|
||||
compression_level = -1;
|
||||
|
||||
# For inter-node comms
|
||||
rpc_bind_addr = "[::]:3901";
|
||||
rpc_secret_file = config.age.secrets.garage-env.path;
|
||||
# rpc_public_addr = "127.0.0.1:3901";
|
||||
|
||||
# Standard S3 api endpoint
|
||||
s3_api = {
|
||||
s3_region = "helios";
|
||||
api_bind_addr = "[::]:3900";
|
||||
};
|
||||
|
||||
# Static file serve endpoint
|
||||
/*
|
||||
s3_web = {
|
||||
bind_addr = "[::1]:3902";
|
||||
root_domain = "s3.notashelf.dev";
|
||||
index = "index.html";
|
||||
};
|
||||
|
||||
"k2v_api" = {
|
||||
"api_bind_addr" = "[::1]:3904";
|
||||
};
|
||||
*/
|
||||
|
||||
# Admin api endpoint
|
||||
admin = {
|
||||
api_bind_addr = "[::]:3903";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."s3.notashelf.dev" =
|
||||
{
|
||||
locations."/".proxyPass = "http://127.0.0.1:3900";
|
||||
extraConfig = ''
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
# Disable buffering to a temporary file.
|
||||
proxy_max_temp_file_size 0;
|
||||
'';
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.database.mongodb.enable {
|
||||
services.mongodb = {
|
||||
enable = true;
|
||||
package = pkgs.mongodb;
|
||||
enableAuth = true;
|
||||
initialRootPassword = config.age.secrets.mongodb-secret.path;
|
||||
#bind_ip = "0.0.0.0";
|
||||
extraConfig = ''
|
||||
operationProfiling.mode: all
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.database.mysql.enable {
|
||||
services.mysql = {
|
||||
enable = true;
|
||||
package = pkgs.mariadb;
|
||||
|
||||
# databases and users
|
||||
ensureDatabases = ["mkm"];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "mkm";
|
||||
ensurePermissions = {
|
||||
"mkm.*" = "ALL PRIVILEGES";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.database.postgresql.enable {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
package = pkgs.postgresql_15;
|
||||
dataDir = "/srv/storage/postgresql/${config.services.postgresql.package.psqlSchema}";
|
||||
|
||||
ensureDatabases = [
|
||||
"nextcloud"
|
||||
"forgejo"
|
||||
"grafana"
|
||||
"vaultwarden"
|
||||
"roundcube"
|
||||
"headscale"
|
||||
"atticd"
|
||||
];
|
||||
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "postgres";
|
||||
ensureClauses = {
|
||||
superuser = true;
|
||||
login = true; # not implied by superuser
|
||||
createrole = true;
|
||||
createdb = true;
|
||||
replication = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "forgejo";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
{
|
||||
name = "grafana";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
{
|
||||
name = "vaultwarden";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
{
|
||||
name = "nextcloud";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
{
|
||||
name = "roundcube";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
{
|
||||
name = "headscale";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
{
|
||||
name = "atticd";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
|
||||
checkConfig = true;
|
||||
enableTCPIP = false;
|
||||
|
||||
# http://pgconfigurator.cybertec.at/;
|
||||
# https://git.darmstadt.ccc.de/maralorn/nixos-config/-/blob/master/nixos/roles/matrix-synapse/postgres-tuning.nix
|
||||
settings = {
|
||||
# Connectivity;
|
||||
max_connections = 100;
|
||||
superuser_reserved_connections = 3;
|
||||
|
||||
# Memory Settings;
|
||||
shared_buffers = "1024 MB";
|
||||
work_mem = "32 MB";
|
||||
maintenance_work_mem = "320 MB";
|
||||
huge_pages = "off";
|
||||
effective_cache_size = "2 GB";
|
||||
effective_io_concurrency = 100; # concurrent IO only really activated if OS supports posix_fadvise function;
|
||||
random_page_cost = 1.25; # speed of random disk access relative to sequential access (1.0);
|
||||
# Monitoring;
|
||||
shared_preload_libraries = "pg_stat_statements,auto_explain"; # per statement resource usage stats & log explain statements for slow queries
|
||||
track_io_timing = "on"; # measure exact block IO times;
|
||||
track_functions = "pl"; # track execution times of pl-language procedures if any;
|
||||
# Replication;
|
||||
wal_level = "replica"; # consider using at least "replica";
|
||||
max_wal_senders = 0;
|
||||
synchronous_commit = "on";
|
||||
|
||||
# Checkpointing: ;
|
||||
checkpoint_timeout = "15 min";
|
||||
checkpoint_completion_target = 0.9;
|
||||
max_wal_size = "1024 MB";
|
||||
min_wal_size = "512 MB";
|
||||
|
||||
# WAL writing;
|
||||
wal_compression = "on";
|
||||
wal_buffers = -1; # auto-tuned by Postgres till maximum of segment size (16MB by default);
|
||||
wal_writer_delay = "200ms";
|
||||
wal_writer_flush_after = "1MB";
|
||||
|
||||
# Background writer;
|
||||
bgwriter_delay = "200ms";
|
||||
bgwriter_lru_maxpages = 100;
|
||||
bgwriter_lru_multiplier = 2.0;
|
||||
bgwriter_flush_after = 0;
|
||||
|
||||
# Parallel queries: ;
|
||||
max_worker_processes = 6;
|
||||
max_parallel_workers_per_gather = 3;
|
||||
max_parallel_maintenance_workers = 3;
|
||||
max_parallel_workers = 6;
|
||||
parallel_leader_participation = "on";
|
||||
|
||||
# Advanced features ;
|
||||
enable_partitionwise_join = "on";
|
||||
enable_partitionwise_aggregate = "on";
|
||||
jit = "on";
|
||||
|
||||
jit_above_cost = 100000;
|
||||
jit_inline_above_cost = 150000;
|
||||
jit_optimize_above_cost = 500000;
|
||||
|
||||
# log slow queries
|
||||
log_min_duration_statement = 100;
|
||||
"auto_explain.log_min_duration" = 100;
|
||||
|
||||
# logging configuration
|
||||
log_connections = true;
|
||||
log_statement = "all";
|
||||
logging_collector = true;
|
||||
log_disconnections = true;
|
||||
log_destination = lib.mkForce "syslog";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.database.redis.enable {
|
||||
services.redis = {
|
||||
vmOverCommit = true;
|
||||
servers = mkIf cfg.nextcloud.enable {
|
||||
nextcloud = {
|
||||
enable = true;
|
||||
user = "nextcloud";
|
||||
port = 0;
|
||||
};
|
||||
|
||||
searxng = mkIf cfg.searxng.enable {
|
||||
enable = true;
|
||||
user = "searx";
|
||||
port = 6370;
|
||||
databases = 16;
|
||||
logLevel = "debug";
|
||||
requirePass = "searxng";
|
||||
};
|
||||
|
||||
forgejo = mkIf cfg.forgejo.enable {
|
||||
enable = true;
|
||||
user = "forgejo";
|
||||
port = 6371;
|
||||
databases = 16;
|
||||
logLevel = "debug";
|
||||
requirePass = "forgejo";
|
||||
};
|
||||
|
||||
mastodon = mkIf cfg.social.mastodon.enable {
|
||||
enable = true;
|
||||
user = "mastodon";
|
||||
port = 6372;
|
||||
databases = 16;
|
||||
logLevel = "debug";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
27
nyx/modules/core/roles/server/system/services/default.nix
Normal file
27
nyx/modules/core/roles/server/system/services/default.nix
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
imports = [
|
||||
# essentials
|
||||
./databases # mysql, postgreqsl, redis and more
|
||||
./nginx # base nginx webserver configuration
|
||||
|
||||
# other services
|
||||
./bincache # atticd and harmonia
|
||||
./monitoring # prometheus, grafana, loki and uptime-kuma
|
||||
./networking # wireguard and headscale
|
||||
./social # mastodon and matrix
|
||||
./forgejo.nix # lightweight git service, fork of gitea
|
||||
./forgejo-runner.nix # self-hosted runner for forgejo
|
||||
./nextcloud.nix # cloud storage (not a backup solution)
|
||||
./vaultwarden.nix # bitwarden compatible password manager
|
||||
./mailserver.nix # nixos-mailserver setup
|
||||
./jellyfin.nix # media server
|
||||
./tor.nix # tor relay
|
||||
./searxng.nix # searx search engine
|
||||
./reposilite.nix # self-hosted maven repository
|
||||
./elasticsearch.nix # elasticsearch
|
||||
./kanidm.nix # kanidm identity management
|
||||
|
||||
# misc
|
||||
./mkm.nix # holy fuck
|
||||
];
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.elasticsearch.enable {
|
||||
services.elasticsearch = {
|
||||
enable = true;
|
||||
single_node = true;
|
||||
cluster_name = "elasticsearch-${config.networking.hostName}";
|
||||
|
||||
extraConf = ''
|
||||
xpack.security.enabled: false
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.modules.system.services;
|
||||
|
||||
# construct each runner using the mkRunner function
|
||||
# you can pass additional configuration options in the instance submodule
|
||||
# it'll be merged to the below configuration
|
||||
mkRunner = {
|
||||
name,
|
||||
settings,
|
||||
}:
|
||||
{
|
||||
enable = true;
|
||||
inherit name;
|
||||
|
||||
url = "https://git.notashelf.dev";
|
||||
|
||||
# NOTE: changing (i.e adding or removing) labels causes your old registration token to expire
|
||||
# make sure your labels are final before deploying
|
||||
labels = [
|
||||
"debian-latest:docker://node:18-bullseye"
|
||||
"ubuntu-latest:docker://node:18-bullseye"
|
||||
"act:docker://ghcr.io/catthehacker/ubuntu:act-latest"
|
||||
#"native:host"
|
||||
];
|
||||
}
|
||||
// settings;
|
||||
in {
|
||||
config = mkIf cfg.forgejo.enable {
|
||||
users = {
|
||||
groups.gitea-runner = {};
|
||||
users.gitea-runner = {
|
||||
isSystemUser = true;
|
||||
createHome = true;
|
||||
home = "/var/lib/gitea-runner";
|
||||
group = "gitea-runner";
|
||||
extraGroups = ["docker"];
|
||||
};
|
||||
};
|
||||
|
||||
services.gitea-actions-runner = {
|
||||
package = pkgs.forgejo-actions-runner;
|
||||
instances = {
|
||||
"runner-01" = mkRunner {
|
||||
name = "runner-01";
|
||||
settings = {
|
||||
tokenFile = config.age.secrets.forgejo-runner-token.path;
|
||||
settings = {
|
||||
capacity = 4;
|
||||
container.network = "host";
|
||||
cache.enabled = true;
|
||||
};
|
||||
|
||||
# packages that'll be made available to the host
|
||||
# when the runner is configured with a host execution label.
|
||||
hostPackages = with pkgs; [
|
||||
bash
|
||||
curl
|
||||
coreutils
|
||||
wget
|
||||
gitMinimal
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
134
nyx/modules/core/roles/server/system/services/forgejo.nix
Normal file
134
nyx/modules/core/roles/server/system/services/forgejo.nix
Normal file
|
@ -0,0 +1,134 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.modules.system.services;
|
||||
domain = "git.notashelf.dev";
|
||||
|
||||
inherit (cfg.forgejo.settings) port;
|
||||
in {
|
||||
config = mkIf cfg.forgejo.enable {
|
||||
modules.system.services = {
|
||||
nginx.enable = true;
|
||||
database = {
|
||||
redis.enable = true;
|
||||
postgresql.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
# make sure the service is reachable from outside
|
||||
config.services.forgejo.settings.server.HTTP_PORT
|
||||
config.services.forgejo.settings.server.SSH_PORT
|
||||
];
|
||||
|
||||
users = {
|
||||
users.git = {
|
||||
isSystemUser = true;
|
||||
createHome = false;
|
||||
group = "git";
|
||||
};
|
||||
|
||||
groups.git = {};
|
||||
};
|
||||
|
||||
services = {
|
||||
forgejo = {
|
||||
enable = true;
|
||||
package = pkgs.forgejo;
|
||||
stateDir = "/srv/storage/forgejo/data";
|
||||
|
||||
mailerPasswordFile = config.age.secrets.mailserver-forgejo-secret.path;
|
||||
lfs.enable = true;
|
||||
|
||||
settings = {
|
||||
default.APP_NAME = "The Secret Shelf";
|
||||
|
||||
actions = {
|
||||
ENABLED = true;
|
||||
DEFAULT_ACTIONS_URL = "https://git.notashelf.dev";
|
||||
};
|
||||
|
||||
other = {
|
||||
SHOW_FOOTER_VERSION = false;
|
||||
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
|
||||
};
|
||||
|
||||
session = {
|
||||
COOKIE_SECURE = true;
|
||||
SAME_SITE = "strict";
|
||||
};
|
||||
|
||||
server = {
|
||||
PROTOCOL = "http+unix";
|
||||
HTTP_PORT = port;
|
||||
ROOT_URL = "https://${domain}";
|
||||
DOMAIN = "${domain}";
|
||||
DISABLE_ROUTER_LOG = true;
|
||||
SSH_CREATE_AUTHORIZED_KEYS_FILE = true;
|
||||
LANDING_PAGE = "/explore";
|
||||
|
||||
START_SSH_SERVER = true;
|
||||
SSH_PORT = 2222;
|
||||
SSH_LISTEN_PORT = 2222;
|
||||
};
|
||||
|
||||
database = {
|
||||
DB_TYPE = lib.mkForce "postgres";
|
||||
HOST = "/run/postgresql";
|
||||
NAME = "forgejo";
|
||||
USER = "forgejo";
|
||||
PASSWD = "forgejo";
|
||||
};
|
||||
|
||||
cache = {
|
||||
ENABLED = true;
|
||||
ADAPTER = "redis";
|
||||
HOST = "redis://:forgejo@localhost:6371";
|
||||
};
|
||||
|
||||
mailer = mkIf config.modules.system.services.mailserver.enable {
|
||||
ENABLED = true;
|
||||
PROTOCOL = "smtps";
|
||||
SMTP_ADDR = "mail.notashelf.dev";
|
||||
USER = "git@notashelf.dev";
|
||||
};
|
||||
|
||||
ui.DEFAULT_THEME = "arc-green";
|
||||
attachment.ALLOWED_TYPES = "*/*";
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
packages.ENABLED = false;
|
||||
repository.PREFERRED_LICENSES = "MIT,GPL-3.0,GPL-2.0,LGPL-3.0,LGPL-2.1";
|
||||
log.LEVEL = "Debug";
|
||||
"repository.upload" = {
|
||||
FILE_MAX_SIZE = 100;
|
||||
MAX_FILES = 10;
|
||||
};
|
||||
};
|
||||
|
||||
# backup
|
||||
dump = {
|
||||
enable = true;
|
||||
backupDir = "/srv/storage/forgejo/dump";
|
||||
interval = "06:00";
|
||||
type = "tar.zst";
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."git.notashelf.dev" =
|
||||
{
|
||||
locations."/" = {
|
||||
recommendedProxySettings = true;
|
||||
proxyPass = "http://unix:/run/forgejo/forgejo.sock";
|
||||
};
|
||||
|
||||
quic = true;
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
}
|
38
nyx/modules/core/roles/server/system/services/jellyfin.nix
Normal file
38
nyx/modules/core/roles/server/system/services/jellyfin.nix
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.jellyfin.enable {
|
||||
modules.system.services = {
|
||||
nginx.enable = true;
|
||||
};
|
||||
|
||||
services = {
|
||||
jellyfin = {
|
||||
enable = true;
|
||||
group = "jellyfin";
|
||||
user = "jellyfin";
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
nginx.virtualHosts. "fin.notashelf.dev" =
|
||||
{
|
||||
locations."/" = {
|
||||
# TODO: the port is not customizable in the upstream service, PR nixpkgs
|
||||
proxyPass = "http://127.0.0.1:${cfg.jellyfin.settings.port}/";
|
||||
proxyWebsockets = true;
|
||||
extraConfig = "proxy_pass_header Authorization;";
|
||||
};
|
||||
|
||||
quic = true;
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
}
|
47
nyx/modules/core/roles/server/system/services/kanidm.nix
Normal file
47
nyx/modules/core/roles/server/system/services/kanidm.nix
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
domain = "idm.notashelf.dev";
|
||||
certDir = config.security.acme.certs.${domain}.directory;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
|
||||
inherit (cfg.kanidm.settings) host port;
|
||||
in {
|
||||
config = mkIf cfg.kanidm.enable {
|
||||
services.kanidm = {
|
||||
enableServer = true;
|
||||
serverSettings = {
|
||||
inherit domain;
|
||||
origin = "https://${domain}";
|
||||
bindaddress = "${host}:${toString port}";
|
||||
trust_x_forward_for = true;
|
||||
#tls_chain = "${certDir}/fullchain.pem";
|
||||
#tls_key = "${certDir}/key.pem";
|
||||
online_backup = {
|
||||
path = "/srv/storage/kanidm/backups";
|
||||
schedule = "0 0 * * *"; # Every day at midnight.
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.kanidm = {
|
||||
after = ["acme-selfsigned-internal.${domain}.target"];
|
||||
serviceConfig = {
|
||||
SupplementaryGroups = [config.security.acme.certs.${domain}.group];
|
||||
BindReadOnlyPaths = [certDir];
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/".proxyPass = "https://${host}:${toString port}";
|
||||
};
|
||||
};
|
||||
}
|
193
nyx/modules/core/roles/server/system/services/mailserver.nix
Normal file
193
nyx/modules/core/roles/server/system/services/mailserver.nix
Normal file
|
@ -0,0 +1,193 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.age) secrets;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
imports = [
|
||||
inputs.simple-nixos-mailserver.nixosModule
|
||||
];
|
||||
|
||||
config = mkIf cfg.mailserver.enable {
|
||||
# required for roundcube
|
||||
networking.firewall.allowedTCPPorts = [80 443];
|
||||
|
||||
mailserver = {
|
||||
enable = true;
|
||||
mailDirectory = "/srv/storage/mail/vmail";
|
||||
dkimKeyDirectory = "/srv/storage/mail/dkim";
|
||||
sieveDirectory = "/srv/storage/mail/sieve";
|
||||
openFirewall = true;
|
||||
enableImap = true;
|
||||
enableImapSsl = true;
|
||||
enablePop3 = false;
|
||||
enablePop3Ssl = false;
|
||||
enableSubmission = false;
|
||||
enableSubmissionSsl = true;
|
||||
hierarchySeparator = "/";
|
||||
localDnsResolver = false;
|
||||
fqdn = "mail.notashelf.dev";
|
||||
certificateScheme = "acme-nginx";
|
||||
domains = ["notashelf.dev"];
|
||||
loginAccounts = {
|
||||
"raf@notashelf.dev" = {
|
||||
hashedPasswordFile = secrets.mailserver-secret.path;
|
||||
aliases = [
|
||||
"me"
|
||||
"raf"
|
||||
"me@notashelf.dev"
|
||||
"admin"
|
||||
"admin@notashelf.dev"
|
||||
"root"
|
||||
"root@notashelf.dev"
|
||||
"postmaster"
|
||||
"postmaster@notashelf.dev"
|
||||
];
|
||||
};
|
||||
|
||||
"noreply@notashelf.dev" = {
|
||||
aliases = ["noreply"];
|
||||
hashedPasswordFile = secrets.mailserver-noreply-secret.path;
|
||||
sendOnly = true;
|
||||
sendOnlyRejectMessage = "";
|
||||
};
|
||||
|
||||
"git@notashelf.dev" = mkIf cfg.forgejo.enable {
|
||||
aliases = ["git" "forgejo"];
|
||||
hashedPasswordFile = secrets.mailserver-forgejo-secret.path;
|
||||
sendOnly = true;
|
||||
sendOnlyRejectMessage = "";
|
||||
};
|
||||
|
||||
"vaultwarden@notashelf.dev" = mkIf cfg.vaultwarden.enable {
|
||||
aliases = ["vaultwarden" "vault"];
|
||||
hashedPasswordFile = secrets.mailserver-vaultwarden-secret.path;
|
||||
sendOnly = true;
|
||||
sendOnlyRejectMessage = "";
|
||||
};
|
||||
|
||||
"matrix@notashelf.dev" = mkIf cfg.social.matrix.enable {
|
||||
aliases = ["matrix"];
|
||||
hashedPasswordFile = secrets.mailserver-matrix-secret.path;
|
||||
sendOnly = true;
|
||||
sendOnlyRejectMessage = "";
|
||||
};
|
||||
|
||||
"cloud@notashelf.dev" = mkIf cfg.nextcloud.enable {
|
||||
aliases = ["cloud" "nextcloud"];
|
||||
hashedPasswordFile = secrets.mailserver-cloud-secret.path;
|
||||
sendOnly = true;
|
||||
sendOnlyRejectMessage = "";
|
||||
};
|
||||
};
|
||||
|
||||
mailboxes = {
|
||||
Archive = {
|
||||
auto = "subscribe";
|
||||
specialUse = "Archive";
|
||||
};
|
||||
Drafts = {
|
||||
auto = "subscribe";
|
||||
specialUse = "Drafts";
|
||||
};
|
||||
Sent = {
|
||||
auto = "subscribe";
|
||||
specialUse = "Sent";
|
||||
};
|
||||
Junk = {
|
||||
auto = "subscribe";
|
||||
specialUse = "Junk";
|
||||
};
|
||||
Trash = {
|
||||
auto = "subscribe";
|
||||
specialUse = "Trash";
|
||||
};
|
||||
};
|
||||
|
||||
fullTextSearch = {
|
||||
enable = true;
|
||||
# index new email as they arrive
|
||||
autoIndex = true;
|
||||
# this only applies to plain text attachments, binary attachments are never indexed
|
||||
indexAttachments = true;
|
||||
enforced = "body";
|
||||
};
|
||||
|
||||
vmailUserName = "vmail";
|
||||
vmailGroupName = "vmail";
|
||||
|
||||
useFsLayout = true;
|
||||
};
|
||||
|
||||
services = {
|
||||
roundcube = {
|
||||
enable = true;
|
||||
database.username = "roundcube";
|
||||
maxAttachmentSize = 50;
|
||||
dicts = with pkgs.aspellDicts; [en tr de];
|
||||
# this is the url of the vhost, not necessarily the same as the fqdn of
|
||||
# the mailserver
|
||||
hostName = "webmail.notashelf.dev";
|
||||
extraConfig = ''
|
||||
$config['imap_host'] = array(
|
||||
'tls://mail.notashelf.dev' => "NotAShelf's Mail Server",
|
||||
'ssl://imap.gmail.com:993' => 'Google Mail',
|
||||
);
|
||||
$config['username_domain'] = array(
|
||||
'mail.notashelf.dev' => 'notashelf.dev',
|
||||
'mail.gmail.com' => 'gmail.com',
|
||||
);
|
||||
$config['x_frame_options'] = false;
|
||||
# starttls needed for authentication, so the fqdn required to match
|
||||
# the certificate
|
||||
$config['smtp_host'] = "tls://${config.mailserver.fqdn}";
|
||||
$config['smtp_user'] = "%u";
|
||||
$config['smtp_pass'] = "%p";
|
||||
$config['plugins'] = [ "carddav" ];
|
||||
'';
|
||||
};
|
||||
|
||||
postfix = {
|
||||
dnsBlacklists = [
|
||||
"all.s5h.net"
|
||||
"b.barracudacentral.org"
|
||||
"bl.spamcop.net"
|
||||
"blacklist.woody.ch"
|
||||
];
|
||||
dnsBlacklistOverrides = ''
|
||||
notashelf.dev OK
|
||||
mail.notashelf.dev OK
|
||||
127.0.0.0/8 OK
|
||||
192.168.0.0/16 OK
|
||||
'';
|
||||
headerChecks = [
|
||||
{
|
||||
action = "IGNORE";
|
||||
pattern = "/^User-Agent.*Roundcube Webmail/";
|
||||
}
|
||||
];
|
||||
|
||||
config = {
|
||||
smtp_helo_name = config.mailserver.fqdn;
|
||||
};
|
||||
};
|
||||
|
||||
phpfpm.pools.roundcube.settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"listen.group" = config.services.nginx.group;
|
||||
};
|
||||
|
||||
nginx.virtualHosts = {
|
||||
"mail.notashelf.dev" = {quic = true;} // lib.sslTemplate;
|
||||
"webmail.notashelf.dev" = {quic = true;} // lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
92
nyx/modules/core/roles/server/system/services/miniflux.nix
Normal file
92
nyx/modules/core/roles/server/system/services/miniflux.nix
Normal file
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf getExe';
|
||||
|
||||
dev = config.modules.device;
|
||||
cfg = config.modules.system.services;
|
||||
acceptedTypes = ["server" "hybrid"];
|
||||
in {
|
||||
config = mkIf ((builtins.elem dev.type acceptedTypes) && cfg.miniflux.enable) {
|
||||
# https://github.com/Gerg-L/nixos/blob/master/hosts/gerg-desktop/services/miniflux.nix
|
||||
# miniflux setup courtesy of the funny frog man (he's bald)
|
||||
|
||||
systemd.services = {
|
||||
miniflux = {
|
||||
description = "Miniflux service";
|
||||
wantedBy = ["multi-user.target"];
|
||||
requires = ["miniflux-dbsetup.service"];
|
||||
after = ["network.target" "postgresql.service" "miniflux-dbsetup.service"];
|
||||
script = getExe' pkgs.miniflux "miniflux";
|
||||
|
||||
serviceConfig = {
|
||||
User = "miniflux";
|
||||
RuntimeDirectory = "miniflux";
|
||||
RuntimeDirectoryMode = "0770";
|
||||
EnvironmentFile = config.age.secrets.miniflux-env.path;
|
||||
|
||||
# Hardening
|
||||
CapabilityBoundingSet = [""];
|
||||
DeviceAllow = [""];
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
PrivateDevices = true;
|
||||
PrivateUsers = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_UNIX"];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = ["@system-service" "~@privileged"];
|
||||
UMask = "0077";
|
||||
};
|
||||
|
||||
environment = {
|
||||
BASE_URL = "https://flux.notashelf.dev";
|
||||
LISTEN_ADDR = "/run/miniflux/miniflux.sock";
|
||||
DATABASE_URL = "user=miniflux host=/run/postgresql dbname=miniflux";
|
||||
RUN_MIGRATIONS = "1";
|
||||
CREATE_ADMIN = "1";
|
||||
};
|
||||
};
|
||||
miniflux-dbsetup = {
|
||||
description = "Miniflux database setup";
|
||||
requires = ["postgresql.service"];
|
||||
after = ["network.target" "postgresql.service"];
|
||||
script = ''
|
||||
${lib.getExe' config.services.postgresql.package "psql"} "miniflux" -c "CREATE EXTENSION IF NOT EXISTS hstore"
|
||||
'';
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = config.services.postgresql.superUser;
|
||||
};
|
||||
};
|
||||
};
|
||||
users = {
|
||||
groups.miniflux = {
|
||||
gid = 377;
|
||||
};
|
||||
users = {
|
||||
miniflux = {
|
||||
group = "miniflux";
|
||||
extraGroups = ["postgres"];
|
||||
isSystemUser = true;
|
||||
uid = 377;
|
||||
};
|
||||
${config.services.nginx.user}.extraGroups = ["miniflux"];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
31
nyx/modules/core/roles/server/system/services/mkm.nix
Normal file
31
nyx/modules/core/roles/server/system/services/mkm.nix
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
inputs',
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
cfg = config.modules.system.services;
|
||||
in {
|
||||
config = mkIf cfg.mkm.enable {
|
||||
virtualisation.oci-containers = {
|
||||
backend = "podman";
|
||||
containers = {
|
||||
"mkm-web" = mkIf (config.networking.hostName == "helios") {
|
||||
autoStart = true;
|
||||
environmentFiles = [
|
||||
config.age.secrets.mkm-web.path
|
||||
];
|
||||
ports = [
|
||||
"3005:3005"
|
||||
"3306:3306"
|
||||
];
|
||||
extraOptions = ["--network=host"];
|
||||
|
||||
image = "mkm-web";
|
||||
imageFile = inputs'.mkm.packages.dockerImage;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
imports = [
|
||||
./grafana
|
||||
./prometheus.nix
|
||||
./loki.nix
|
||||
./uptime-kuma.nix
|
||||
];
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
loadDashboard = file:
|
||||
lib.pipe file [
|
||||
lib.importJSON
|
||||
({dashboard, ...}: rec {
|
||||
name = "provision-dashboard-${dashboard.uid}.json";
|
||||
path = builtins.toFile name (builtins.toJSON dashboard);
|
||||
})
|
||||
];
|
||||
|
||||
dashboardsDir =
|
||||
pkgs.linkFarm
|
||||
"grafana-provisioning-dashboards"
|
||||
(map loadDashboard (lib.filesystem.listFilesRecursive ./objects/dashboards));
|
||||
in {
|
||||
services.grafana.provision.dashboards.settings = {
|
||||
providers = lib.singleton {
|
||||
options.path = dashboardsDir;
|
||||
allowUiUpdates = true;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
# imports = [./dashboards.nix];
|
||||
config = mkIf cfg.monitoring.grafana.enable {
|
||||
networking.firewall.allowedTCPPorts = [config.services.grafana.settings.server.http_port];
|
||||
|
||||
modules.system.services.database = {
|
||||
postgresql.enable = true;
|
||||
};
|
||||
|
||||
services = {
|
||||
grafana = {
|
||||
enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
http_addr = "0.0.0.0";
|
||||
http_port = 3000;
|
||||
|
||||
root_url = "https://dash.notashelf.dev";
|
||||
domain = "dash.notashelf.dev";
|
||||
enforce_domain = true;
|
||||
};
|
||||
|
||||
database = {
|
||||
type = "postgres";
|
||||
host = "/run/postgresql";
|
||||
name = "grafana";
|
||||
user = "grafana";
|
||||
ssl_mode = "disable";
|
||||
};
|
||||
|
||||
security = {
|
||||
cookie_secure = true;
|
||||
disable_gravatar = true;
|
||||
};
|
||||
|
||||
analytics = {
|
||||
reporting_enabled = false;
|
||||
check_for_updates = false;
|
||||
};
|
||||
|
||||
"auth.anonymous".enabled = false;
|
||||
"auth.basic".enabled = false;
|
||||
|
||||
users = {
|
||||
allow_signup = false;
|
||||
};
|
||||
};
|
||||
|
||||
provision = {
|
||||
enable = true;
|
||||
datasources.settings = {
|
||||
datasources = [
|
||||
(mkIf sys.services.monitoring.prometheus.enable {
|
||||
name = "Prometheus";
|
||||
type = "prometheus";
|
||||
access = "proxy";
|
||||
orgId = 1;
|
||||
uid = "Y4SSG429DWCGDQ3R";
|
||||
url = "http://127.0.0.1:${toString config.services.prometheus.port}";
|
||||
isDefault = true;
|
||||
version = 1;
|
||||
editable = true;
|
||||
jsonData = {
|
||||
graphiteVersion = "1.1";
|
||||
tlsAuth = false;
|
||||
tlsAuthWithCACert = false;
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf sys.services.monitoring.loki.enable {
|
||||
name = "Loki";
|
||||
type = "loki";
|
||||
access = "proxy";
|
||||
url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}";
|
||||
})
|
||||
|
||||
(mkIf sys.services.database.postgresql.enable {
|
||||
name = "PostgreSQL";
|
||||
type = "postgres";
|
||||
access = "proxy";
|
||||
url = "http://127.0.0.1:9103";
|
||||
})
|
||||
];
|
||||
|
||||
# typos go here
|
||||
deleteDatasources = [
|
||||
{
|
||||
name = "postgres";
|
||||
orgId = 0;
|
||||
}
|
||||
{
|
||||
name = "redis";
|
||||
orgId = 0;
|
||||
}
|
||||
{
|
||||
name = "Endlessh-go";
|
||||
orgId = 0;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."dash.notashelf.dev" =
|
||||
{
|
||||
locations."/" = {
|
||||
proxyPass = with config.services.grafana.settings.server; "http://${toString http_addr}:${toString http_port}/";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
|
||||
quic = true;
|
||||
}
|
||||
// {
|
||||
addSSL = true;
|
||||
enableACME = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = config.services.loki;
|
||||
in {
|
||||
config = mkIf sys.services.monitoring.loki.enable {
|
||||
# https://gist.github.com/rickhull/895b0cb38fdd537c1078a858cf15d63e
|
||||
services.loki = {
|
||||
enable = true;
|
||||
dataDir = "/srv/storage/loki";
|
||||
extraFlags = ["--config.expand-env=true"];
|
||||
|
||||
configuration = {
|
||||
auth_enabled = false;
|
||||
|
||||
server = {
|
||||
http_listen_port = 3030;
|
||||
log_level = "warn";
|
||||
};
|
||||
|
||||
ingester = {
|
||||
lifecycler = {
|
||||
address = "127.0.0.1";
|
||||
ring = {
|
||||
kvstore = {
|
||||
store = "inmemory";
|
||||
};
|
||||
replication_factor = 1;
|
||||
};
|
||||
};
|
||||
chunk_idle_period = "1h";
|
||||
max_chunk_age = "1h";
|
||||
chunk_target_size = 999999;
|
||||
chunk_retain_period = "30s";
|
||||
max_transfer_retries = 0;
|
||||
};
|
||||
|
||||
schema_config.configs = [
|
||||
{
|
||||
from = "2022-05-14";
|
||||
store = "boltdb";
|
||||
object_store = "filesystem";
|
||||
schema = "v11";
|
||||
index = {
|
||||
prefix = "index_";
|
||||
period = "168h";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
storage_config = {
|
||||
boltdb.directory = "${cfg.dataDir}/boltdb-index";
|
||||
filesystem.directory = "${cfg.dataDir}/storage-chunks";
|
||||
|
||||
boltdb_shipper = {
|
||||
active_index_directory = "/srv/storage/loki/boltdb-shipper-active";
|
||||
cache_location = "/srv/storage/loki/boltdb-shipper-cache";
|
||||
cache_ttl = "24h";
|
||||
shared_store = "filesystem";
|
||||
};
|
||||
};
|
||||
|
||||
limits_config = {
|
||||
reject_old_samples = true;
|
||||
reject_old_samples_max_age = "168h";
|
||||
};
|
||||
|
||||
chunk_store_config = {
|
||||
max_look_back_period = "0s";
|
||||
};
|
||||
|
||||
table_manager = {
|
||||
retention_deletes_enabled = false;
|
||||
retention_period = "0s";
|
||||
};
|
||||
|
||||
compactor = {
|
||||
shared_store = "filesystem";
|
||||
working_directory = "${cfg.dataDir}/compactor-work";
|
||||
compactor_ring = {
|
||||
kvstore = {
|
||||
store = "inmemory";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
# user, group, dataDir, extraFlags, (configFile)
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.monitoring.prometheus.enable {
|
||||
services = {
|
||||
# Prometheus exporter for Grafana
|
||||
prometheus = {
|
||||
enable = true;
|
||||
port = 9100;
|
||||
|
||||
# relatively frequent scraping intervals
|
||||
globalConfig = {
|
||||
scrape_interval = "10s";
|
||||
scrape_timeout = "2s";
|
||||
};
|
||||
|
||||
# enabled exporters
|
||||
exporters = {
|
||||
node = {
|
||||
enable = true;
|
||||
port = 9101;
|
||||
enabledCollectors = ["systemd" "processes"];
|
||||
};
|
||||
|
||||
redis = {
|
||||
enable = true;
|
||||
port = 9102;
|
||||
user = "redis";
|
||||
};
|
||||
|
||||
postgres = {
|
||||
enable = true;
|
||||
port = 9103;
|
||||
user = "postgres";
|
||||
};
|
||||
|
||||
nginx = {
|
||||
enable = false;
|
||||
port = 9104;
|
||||
};
|
||||
|
||||
smartctl = {
|
||||
inherit (config.services.smartd) enable;
|
||||
openFirewall = config.services.smartd.enable;
|
||||
# Defaults:
|
||||
user = "smartctl-exporter";
|
||||
group = "disk";
|
||||
port = 9110;
|
||||
};
|
||||
};
|
||||
|
||||
scrapeConfigs = [
|
||||
# internal scrape jobs
|
||||
{
|
||||
job_name = "prometheus";
|
||||
scrape_interval = "30s";
|
||||
static_configs = [{targets = ["localhost:9100"];}];
|
||||
}
|
||||
{
|
||||
job_name = "node";
|
||||
scrape_interval = "30s";
|
||||
static_configs = [{targets = ["localhost:9101"];}];
|
||||
}
|
||||
{
|
||||
job_name = "redis";
|
||||
scrape_interval = "30s";
|
||||
static_configs = [{targets = ["localhost:9102"];}];
|
||||
}
|
||||
{
|
||||
job_name = "postgres";
|
||||
scrape_interval = "30s";
|
||||
static_configs = [{targets = ["localhost:9103"];}];
|
||||
}
|
||||
{
|
||||
job_name = "nginx";
|
||||
scrape_interval = "30s";
|
||||
static_configs = [{targets = ["localhost:9104"];}];
|
||||
}
|
||||
{
|
||||
job_name = "endlessh-go";
|
||||
scrape_interval = "30s";
|
||||
static_configs = [{targets = ["localhost:9105"];}];
|
||||
}
|
||||
|
||||
# TODO: exterenal scrape jobs - over tailscale/wireguard mesh
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
domain = "up.notashelf.dev";
|
||||
in {
|
||||
users = {
|
||||
users.uptime-kuma = {
|
||||
isSystemUser = true;
|
||||
group = "uptime-kuma";
|
||||
};
|
||||
groups.uptime-kuma = {};
|
||||
};
|
||||
|
||||
systemd.services.uptime-kuma = {
|
||||
serviceConfig = {
|
||||
DynamicUser = lib.mkForce false;
|
||||
User = "uptime-kuma";
|
||||
Group = "uptime-kuma";
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
uptime-kuma = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PORT = "4000";
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."${domain}" =
|
||||
{
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString config.services.uptime-kuma.settings.PORT}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
imports = [
|
||||
./wireguard
|
||||
./headscale.nix
|
||||
];
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
{
|
||||
inputs',
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.networking.headscale.enable {
|
||||
environment.systemPackages = [config.services.headscale.package];
|
||||
networking.firewall.allowedUDPPorts = [8086]; # DERP
|
||||
|
||||
services = {
|
||||
headscale = {
|
||||
enable = true;
|
||||
address = "127.0.0.1";
|
||||
port = 8085;
|
||||
|
||||
settings = {
|
||||
grpc_listen_addr = "127.0.0.1:50443";
|
||||
grpc_allow_insecure = false;
|
||||
|
||||
server_url = "https://hs.notashelf.dev";
|
||||
tls_cert_path = null;
|
||||
tls_key_path = null;
|
||||
|
||||
# default headscale prefix
|
||||
ip_prefixes = [
|
||||
"100.64.0.0/10"
|
||||
"fd7a:115c:a1e0::/48"
|
||||
];
|
||||
|
||||
dns_config = {
|
||||
override_local_dns = true;
|
||||
magic_dns = true;
|
||||
base_domain = "notashelf.dev";
|
||||
domains = [];
|
||||
nameservers = [
|
||||
"9.9.9.9" # no cloudflare, nice
|
||||
];
|
||||
|
||||
/*
|
||||
extra_records = [
|
||||
{
|
||||
name = "idm.notashelf.dev";
|
||||
type = "A";
|
||||
value = "100.64.0.1"; # NOTE: this should be the address of the "host" node - which is the server
|
||||
}
|
||||
];
|
||||
*/
|
||||
};
|
||||
|
||||
acl_policy_path = pkgs.writeText "headscale-acl" (builtins.toJSON {
|
||||
acls = [
|
||||
{
|
||||
# Allow client --> server traffic
|
||||
# but not the other way around.
|
||||
# Servers face the internet, clients
|
||||
# do so far less.
|
||||
action = "accept";
|
||||
proto = "tcp";
|
||||
src = ["tag:client"];
|
||||
dst = ["tag:server:*"];
|
||||
}
|
||||
];
|
||||
|
||||
# Allow all users to SSH into their own devices in check mode.
|
||||
ssh = [
|
||||
{
|
||||
action = "check";
|
||||
src = ["autogroup:member"];
|
||||
dst = ["autogroup:self"];
|
||||
users = ["autogroup:nonroot" "root"];
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
derp = {
|
||||
server = {
|
||||
enabled = true;
|
||||
region_id = 900;
|
||||
region_code = "headscale";
|
||||
region_name = "Headscale Embedded DERP";
|
||||
stun_listen_addr = "0.0.0.0:8344";
|
||||
};
|
||||
|
||||
urls = [];
|
||||
paths = [];
|
||||
|
||||
auto_update_enabled = false;
|
||||
update_frequency = "24h";
|
||||
};
|
||||
|
||||
disable_check_updates = true;
|
||||
ephemeral_node_inactivity_timeout = "30m";
|
||||
node_update_check_interval = "10s";
|
||||
|
||||
/*
|
||||
db_type = "postgres";
|
||||
db_host = "/run/postgresql";
|
||||
db_name = "headscale";
|
||||
db_user = "headscale";
|
||||
db_port = 5432; # not ignored for some reason
|
||||
*/
|
||||
|
||||
metrics_listen_addr = "127.0.0.1:8087";
|
||||
|
||||
log = {
|
||||
format = "text";
|
||||
level = "info";
|
||||
};
|
||||
|
||||
# TODO: logtail
|
||||
logtail = {
|
||||
enabled = false;
|
||||
};
|
||||
|
||||
randomize_client_port = false;
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."hs.notashelf.dev" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = "http://localhost:${toString config.services.headscale.port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
|
||||
# see <https://github.com/gurucomputing/headscale-ui/blob/master/SECURITY.md> before
|
||||
# possibly using the web frontend
|
||||
"/web" = {
|
||||
root = "${inputs'.nyxpkgs.packages.headscale-ui}/share";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
# TODO: consider enabling postgresql storage
|
||||
# postgresql is normally pretty neat, but unless you expect your setup to receive
|
||||
# very frequent logins, sqlite (default) storage may be more performant
|
||||
# headscale.requires = ["postgresql.service"];
|
||||
|
||||
create-headscale-user = {
|
||||
description = "Create a headscale user and preauth keys for this server";
|
||||
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["headscale.service"];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "headscale";
|
||||
};
|
||||
|
||||
path = [pkgs.headscale];
|
||||
script = ''
|
||||
if ! headscale users list | grep notashelf; then
|
||||
headscale users create notashelf
|
||||
headscale --user notashelf preauthkeys create --reusable --expiration 100y > /var/lib/headscale/preauth.key
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
imports = [
|
||||
./server.nix
|
||||
];
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
|
||||
dev = config.modules.device;
|
||||
acceptedTypes = ["server" "hybrid"];
|
||||
in {
|
||||
config = mkIf ((builtins.elem dev.type acceptedTypes) && cfg.networking.wireguard.enable) {
|
||||
networking = {
|
||||
nat = {
|
||||
enable = true;
|
||||
externalInterface = "ens3";
|
||||
internalInterfaces = ["wg0"];
|
||||
};
|
||||
|
||||
firewall = {
|
||||
allowedUDPPorts = [51820];
|
||||
trustedInterfaces = ["wg0"];
|
||||
};
|
||||
};
|
||||
|
||||
boot.kernelModules = [
|
||||
"wireguard"
|
||||
];
|
||||
|
||||
# Wireguard Server Peer Setup
|
||||
networking.wireguard = {
|
||||
enable = true;
|
||||
interfaces = {
|
||||
wg0 = {
|
||||
# General settings
|
||||
privateKeyFile = config.age.secrets.wg-server.path;
|
||||
listenPort = 51820;
|
||||
|
||||
# IPs
|
||||
ips = [
|
||||
"10.255.255.10/24" # v4 general
|
||||
"10.255.255.254/24" # v4 adtl
|
||||
"fe80::10/64" # v6 link local
|
||||
"2a01:4f9:c010:2cf9:f::10/80" #v6 general
|
||||
"2a01:4f9:c010:2cf9:f::ffff/80" #v6 adtl
|
||||
];
|
||||
|
||||
# Peers
|
||||
peers = [
|
||||
# enyo
|
||||
{
|
||||
allowedIPs = [
|
||||
"10.255.255.11/32"
|
||||
"fe80::11/128"
|
||||
"2a01:4f9:c010:2cf9:f::11/128"
|
||||
];
|
||||
publicKey = "u5Riuu4NEWEH06qATdnrPO+LacZTspoghqMnoWQ+uEQ=";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
networking = {
|
||||
firewall.allowedUDPPorts = [51820 51821];
|
||||
|
||||
nat.internalInterfaces = ["wg0"];
|
||||
|
||||
wireguard.interfaces = {
|
||||
wg0 = {
|
||||
ips = ["10.0.0.1/24"];
|
||||
listenPort = 51820;
|
||||
privateKeyFile = config.age.secrets.wireguard.path;
|
||||
peers = [
|
||||
{
|
||||
# enyo
|
||||
publicKey = "vv190fxSVr+u7Zv0ujPcwE4aYs0QcbObHwzWGwUNSUA=";
|
||||
allowedIPs = ["10.0.0.2/32"];
|
||||
}
|
||||
/*
|
||||
{
|
||||
# test
|
||||
publicKey = "";
|
||||
allowedIPs = ["10.0.0.3/32"];
|
||||
}
|
||||
*/
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
167
nyx/modules/core/roles/server/system/services/nextcloud.nix
Normal file
167
nyx/modules/core/roles/server/system/services/nextcloud.nix
Normal file
|
@ -0,0 +1,167 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
domain = "cloud.notashelf.dev";
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.nextcloud.enable {
|
||||
modules.system.services = {
|
||||
nginx.enable = true;
|
||||
database = {
|
||||
redis.enable = true;
|
||||
postgresql.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
nextcloud = {
|
||||
enable = true;
|
||||
package = pkgs.nextcloud28;
|
||||
|
||||
nginx.recommendedHttpHeaders = true;
|
||||
https = true;
|
||||
hostName = domain;
|
||||
|
||||
home = "/srv/storage/nextcloud";
|
||||
maxUploadSize = "4G";
|
||||
enableImagemagick = true;
|
||||
|
||||
extraApps = let
|
||||
inherit (config.services.nextcloud.package.packages) apps;
|
||||
in {
|
||||
# wtf is this formatting
|
||||
inherit (apps) mail polls onlyoffice contacts calendar tasks bookmarks deck forms cookbook impersonate groupfolders;
|
||||
};
|
||||
|
||||
autoUpdateApps = {
|
||||
enable = true;
|
||||
startAt = "03:00";
|
||||
};
|
||||
|
||||
caching = {
|
||||
apcu = true;
|
||||
memcached = true;
|
||||
redis = true;
|
||||
};
|
||||
|
||||
config = {
|
||||
# admin user settings
|
||||
# only effective during setup
|
||||
adminuser = "notashelf";
|
||||
adminpassFile = config.age.secrets.nextcloud-secret.path;
|
||||
|
||||
# database
|
||||
dbtype = "pgsql";
|
||||
dbhost = "/run/postgresql";
|
||||
dbname = "nextcloud";
|
||||
dbuser = "nextcloud";
|
||||
};
|
||||
|
||||
settings = {
|
||||
"memories.exiftool" = "${lib.getExe pkgs.exiftool}";
|
||||
"memories.vod.ffmpeg" = "${pkgs.ffmpeg-headless}/bin/ffmpeg";
|
||||
"memories.vod.ffprobe" = "${pkgs.ffmpeg-headless}/bin/ffprobe";
|
||||
|
||||
# be very specific about the preview providers
|
||||
enabledPreviewProviders = [
|
||||
"OC\\Preview\\BMP"
|
||||
"OC\\Preview\\GIF"
|
||||
"OC\\Preview\\JPEG"
|
||||
"OC\\Preview\\Krita"
|
||||
"OC\\Preview\\MarkDown"
|
||||
"OC\\Preview\\MP3"
|
||||
"OC\\Preview\\OpenDocument"
|
||||
"OC\\Preview\\PNG"
|
||||
"OC\\Preview\\TXT"
|
||||
"OC\\Preview\\XBitmap"
|
||||
"OC\\Preview\\HEIC"
|
||||
];
|
||||
|
||||
# run maintenance jobs at low-load hours
|
||||
# i.e. 01:00am UTC and 05:00am UTC
|
||||
maintenance_window_start = 1;
|
||||
|
||||
# force https
|
||||
overwriteprotocol = "https";
|
||||
trusted_domains = ["https://${toString domain}"];
|
||||
trusted_proxies = ["https://${toString domain}"];
|
||||
|
||||
redis = {
|
||||
host = "/run/redis-default/redis.sock";
|
||||
dbindex = 0;
|
||||
timeout = 3;
|
||||
};
|
||||
|
||||
# other stuff
|
||||
default_phone_region = "TR";
|
||||
lost_password_link = "disabled";
|
||||
};
|
||||
|
||||
phpOptions = {
|
||||
"opcache.enable" = "1";
|
||||
"opcache.enable_cli" = "1";
|
||||
"opcache.jit" = "1255";
|
||||
"opcache.jit_buffer_size" = "256M";
|
||||
"opcache.validate_timestamps" = "0";
|
||||
"opcache.save_comments" = "1";
|
||||
|
||||
# fix the opcache "buffer is almost full" error in admin overview
|
||||
"opcache.interned_strings_buffer" = "16";
|
||||
# try to resolve delays in displaying content or incomplete page rendering
|
||||
"output_buffering" = "off";
|
||||
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = "50";
|
||||
"pm.start_servers" = "15";
|
||||
"pm.min_spare_servers" = "15";
|
||||
"pm.max_spare_servers" = "25";
|
||||
"pm.max_requests" = "500";
|
||||
};
|
||||
|
||||
phpExtraExtensions = ext: [ext.redis];
|
||||
};
|
||||
|
||||
nginx.virtualHosts."cloud.notashelf.dev" =
|
||||
{
|
||||
quic = true;
|
||||
http3 = true;
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
phpfpm-nextcloud.aliases = ["nextcloud.service"];
|
||||
"nextcloud-setup" = {
|
||||
requires = ["postgresql.service"];
|
||||
after = ["postgresql.service"];
|
||||
serviceConfig = {
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
"nextcloud-preview" = {
|
||||
description = "Generate previews for all images that haven't been rendered";
|
||||
startAt = "01:00:00";
|
||||
requires = ["nextcloud.service"];
|
||||
after = ["nextcloud.service"];
|
||||
path = [config.services.nextcloud.occ];
|
||||
script = "nextcloud-occ preview:generate";
|
||||
|
||||
serviceConfig = {
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
};
|
||||
};
|
||||
*/
|
||||
};
|
||||
};
|
||||
}
|
168
nyx/modules/core/roles/server/system/services/nginx/default.nix
Normal file
168
nyx/modules/core/roles/server/system/services/nginx/default.nix
Normal file
|
@ -0,0 +1,168 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault;
|
||||
inherit (lib.strings) fileContents;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
|
||||
inherit (config.networking) domain;
|
||||
in {
|
||||
config = mkIf cfg.nginx.enable {
|
||||
security = {
|
||||
acme = {
|
||||
acceptTerms = true;
|
||||
defaults.email = "me@notashelf.dev";
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
nginx = {
|
||||
enable = true;
|
||||
package = pkgs.nginxQuic.override {withKTLS = true;};
|
||||
|
||||
# makes /nginx_status endpoint available t o localhost
|
||||
statusPage = true;
|
||||
|
||||
recommendedTlsSettings = true;
|
||||
recommendedBrotliSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedZstdSettings = true;
|
||||
|
||||
clientMaxBodySize = mkDefault "512m";
|
||||
serverNamesHashBucketSize = 1024;
|
||||
appendHttpConfig = ''
|
||||
# set the maximum size of the headers hash tables to 1024 bytes
|
||||
# this applies to the total size of all headers in a client request
|
||||
# or a server response.
|
||||
proxy_headers_hash_max_size 1024;
|
||||
|
||||
# set the bucket size for the headers hash tables to 256 bytes
|
||||
# bucket size determines how many entries can be stored in
|
||||
# each hash table bucket
|
||||
proxy_headers_hash_bucket_size 256;
|
||||
'';
|
||||
|
||||
# lets be more picky on our ciphers and protocols
|
||||
sslCiphers = "EECDH+aRSA+AESGCM:EDH+aRSA:EECDH+aRSA:+AES256:+AES128:+SHA1:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL";
|
||||
sslProtocols = "TLSv1.3 TLSv1.2";
|
||||
|
||||
commonHttpConfig = ''
|
||||
# map the scheme (HTTP or HTTPS) to the HSTS header for HTTPS
|
||||
# the header includes max-age, includeSubdomains and preload
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=31536000; includeSubdomains; preload";
|
||||
}
|
||||
|
||||
# add the Referrer-Policy header with a value of "no-referrer"
|
||||
# which instructs the browser not to send the 'Referer' header in
|
||||
# subsequent requests
|
||||
add_header "Referrer-Policy" "no-referrer";
|
||||
|
||||
# adds the Strict-Transport-Security header with a value derived from the mapped HSTS header
|
||||
# which instructs the browser to always use HTTPS instead of HTTP
|
||||
add_header Strict-Transport-Security $hsts_header;
|
||||
|
||||
# sets the path for cookies to "/", and adds attributes "secure", "HttpOnly", and "SameSite=strict"
|
||||
# "secure": ensures that the cookie is only sent over HTTPS
|
||||
# "HttpOnly": prevents the cookie from being accessed by JavaScript
|
||||
# "SameSite=strict": restricts the cookie to be sent only in requests originating from the same site
|
||||
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||||
|
||||
# define a new map that anonymizes the remote address
|
||||
# by replacing the last octet of IPv4 addresses with 0
|
||||
map $remote_addr $remote_addr_anon {
|
||||
~(?P<ip>\d+\.\d+\.\d+)\. $ip.0;
|
||||
~(?P<ip>[^:]+:[^:]+): $ip::;
|
||||
default 0.0.0.0;
|
||||
}
|
||||
|
||||
# define a new log format that anonymizes the remote address
|
||||
# and adds the remote user name, the time, the request line,
|
||||
log_format combined_anon '$remote_addr_anon - $remote_user [$time_local] '
|
||||
'"$request" $status $body_bytes_sent '
|
||||
'"$http_referer" "$http_user_agent"';
|
||||
|
||||
# write the access log to a file with the combined_anon format
|
||||
# and a buffer size of 32k, flushing every 5 minutes
|
||||
access_log /var/log/nginx/access.log combined_anon buffer=32k flush=5m;
|
||||
|
||||
# define a new log format that anonymizes the remote address
|
||||
# and adds remote user name, local time, the request line and http3
|
||||
# this is important for debugging quic enabled requests
|
||||
log_format quic '$remote_addr_anon - $remote_user [$time_local] '
|
||||
'"$request" $status $body_bytes_sent '
|
||||
'"$http_referer" "$http_user_agent" "$http3"';
|
||||
|
||||
# write the access log to a file with the quic format
|
||||
access_log /var/log/nginx/quic-access.log quic;
|
||||
|
||||
# error log should log only "warn" level and above
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
'';
|
||||
|
||||
virtualHosts = {
|
||||
"${domain}" = {
|
||||
default = true;
|
||||
serverAliases = ["www.${domain}"];
|
||||
|
||||
locations = let
|
||||
commonConfig = ''
|
||||
try_files $uri $uri/ =404;
|
||||
|
||||
default_type text/plain;
|
||||
charset utf-8;
|
||||
'';
|
||||
|
||||
# takes a path to a file and returns a
|
||||
# configuration for a location that serves that file
|
||||
mkStaticPage = {
|
||||
name,
|
||||
root,
|
||||
header ? "",
|
||||
footer ? "",
|
||||
}: let
|
||||
builtIndex = pkgs.writeTextDir "${name}" ''
|
||||
${header}
|
||||
${fileContents root}
|
||||
${footer}
|
||||
'';
|
||||
in {
|
||||
index = name;
|
||||
root = builtIndex.outPath;
|
||||
extraConfig = commonConfig;
|
||||
};
|
||||
in {
|
||||
# root location
|
||||
"/" = mkStaticPage {
|
||||
root = ./static/root.txt;
|
||||
name = "root.txt";
|
||||
header = builtins.readFile ./static/header.txt;
|
||||
footer = "> served by ${pkgs.nginx.outPath}";
|
||||
};
|
||||
|
||||
# /gpg endpoint for my gpg key
|
||||
"/gpg" = mkStaticPage {
|
||||
name = "gpg.txt";
|
||||
root = ./static/gpg.txt;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
logrotate.settings.nginx = {
|
||||
enable = true;
|
||||
minsize = "50M";
|
||||
rotate = "4"; # 4 files of 50mb each
|
||||
compress = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=QQXP
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,5 @@
|
|||
_ _ _ __
|
||||
_ __ ___ | |_ __ _ ___| |__ ___| |/ _|
|
||||
| '_ \ / _ \| __/ _` / __| '_ \ / _ \ | |_
|
||||
| | | | (_) | || (_| \__ \ | | | __/ | _|
|
||||
|_| |_|\___/ \__\__,_|___/_| |_|\___|_|_|.dev
|
|
@ -0,0 +1,90 @@
|
|||
Howdy!
|
||||
|
||||
I'm raf, more commonly known as NotAShelf on most online spaces. This
|
||||
is my personal webpage, which is actually pure plaintext due to my utmosts
|
||||
disdain for modern web technologies.
|
||||
|
||||
Frequently Asked Questions
|
||||
|
||||
***
|
||||
|
||||
Q: What do you do for a living?
|
||||
|
||||
A: I am a professional sailmaker. I design, manufacture and sell sails. I also
|
||||
work as a part-time Political Science instructor for the time being. Sometimes
|
||||
I do digital art, other times I do sailing as a sport.
|
||||
|
||||
***
|
||||
|
||||
Q: Did you study Computer Science? Why do you know programming?
|
||||
|
||||
A: No, I graduated as an International Relations major. I've been teaching
|
||||
myself programming and Linux system administration since 2018. I mostly enjoy
|
||||
open-source software, and my primary stack (as of now) is mostly backend
|
||||
development in Go. Programming is something I enjoy as a tool to help me get
|
||||
from point A to point B, which is why I am interested in learning new
|
||||
technologies as much as I can.
|
||||
|
||||
***
|
||||
|
||||
Q: How are the International Relations?
|
||||
|
||||
A: They're good, thanks for asking.
|
||||
|
||||
***
|
||||
|
||||
Q: What programming languages do you know?
|
||||
|
||||
A: I mostly work with JavaScript, Typescript, Go, C and Nix. I also have some
|
||||
experience with Rust, C++ and Python. There are other languages I've used, but
|
||||
don't really consider noteworthy. I hate PHP. PHP probably hates me back. Good.
|
||||
|
||||
***
|
||||
|
||||
Q: What do you do now?
|
||||
|
||||
A: I am currently working on my PhD in Political Science where I conduct
|
||||
research on the impact of digital technologies on political participation and
|
||||
executive functions as well as the effects of open-source software. on said
|
||||
fields. I would love to go into further detail but I also would like to avoid
|
||||
doxxing myself. Just know that I get the prefix of "Doctor" when I'm done.
|
||||
|
||||
I frequently work with Nix and NixOS, embedded programming and Linux systems
|
||||
in general. I also do some web development in my free time.
|
||||
|
||||
***
|
||||
|
||||
If you want to contact me for any reason, you may just shoot me an email
|
||||
@ raf [at] notashelf [dot] dev. In case you were unable to reach me
|
||||
via email (e.g. your smtp server uses an outdated cipher, or my domain is
|
||||
blacklisted by your provider), you may contact me via Matrix or Mastodon using
|
||||
the links below. I am also on Discord, going by the same handle as my github
|
||||
username. My public gpg key is available at https://notashelf.dev/gpg which
|
||||
is also in plaintext. If you're a bot, you're probably having a field day.
|
||||
|
||||
On that note, please stop scraping my website. I **do not** have anything
|
||||
of your interest.
|
||||
|
||||
***
|
||||
|
||||
List of stuff you might find interesting if you came here and are a human:
|
||||
|
||||
- E-mail | raf [at] notashelf [dot] dev
|
||||
- Matrix | https://matrix.to/#/@raf:notashelf.dev
|
||||
- Mastodon | https://social.notashelf.dev/
|
||||
- Github | https://github.com/notashelf
|
||||
- https://github.com/schizofox/schizofox
|
||||
- https://github.com/hyprland-community/hyprkeys
|
||||
- https://github.com/notashelf/catApi
|
||||
- https://github.com/notashelf/neovim-flake
|
||||
|
||||
|
||||
If you have found a vulnerability on this server, I'd be very grateful if you
|
||||
told me about it. Contact me through any of the ways above.
|
||||
|
||||
***
|
||||
|
||||
I can't have a footer but this is a good place to put a shoutout to the
|
||||
awesome motherfuckingwebsite.com.
|
||||
|
||||
***
|
46
nyx/modules/core/roles/server/system/services/reposilite.nix
Normal file
46
nyx/modules/core/roles/server/system/services/reposilite.nix
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
inputs',
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf sslTemplate;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
|
||||
inherit (cfg.reposilite.settings) port;
|
||||
in {
|
||||
config = mkIf sys.services.reposilite.enable {
|
||||
modules.system.services = {
|
||||
nginx.enable = true;
|
||||
};
|
||||
|
||||
services.reposilite = {
|
||||
enable = true;
|
||||
package = inputs'.nyxpkgs.packages.reposilite-bin;
|
||||
dataDir = "/srv/storage/reposilite";
|
||||
|
||||
openFirewall = true;
|
||||
|
||||
user = "reposilite";
|
||||
group = "reposilite";
|
||||
|
||||
settings = {
|
||||
inherit port;
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts = {
|
||||
"repo.notashelf.dev" =
|
||||
{
|
||||
locations."/".proxyPass = "http://127.0.0.1:${toString port}";
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/reposilite-access.log;
|
||||
error_log /var/log/nginx/reposilite-error.log;
|
||||
'';
|
||||
}
|
||||
// sslTemplate;
|
||||
};
|
||||
};
|
||||
}
|
146
nyx/modules/core/roles/server/system/services/searxng.nix
Normal file
146
nyx/modules/core/roles/server/system/services/searxng.nix
Normal file
|
@ -0,0 +1,146 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
|
||||
inherit (cfg.searxng.settings) host port;
|
||||
in {
|
||||
config = mkIf cfg.searxng.enable {
|
||||
networking.firewall.allowedTCPPorts = [port];
|
||||
|
||||
modules.system.services = {
|
||||
nginx.enable = true;
|
||||
database.redis.enable = true;
|
||||
};
|
||||
|
||||
users = {
|
||||
users.searx = {
|
||||
isSystemUser = true;
|
||||
createHome = false;
|
||||
group = lib.mkForce "searx-redis";
|
||||
};
|
||||
|
||||
groups.searx-redis = {};
|
||||
};
|
||||
|
||||
services = {
|
||||
searx = {
|
||||
enable = true;
|
||||
package = pkgs.searxng;
|
||||
environmentFile = config.age.secrets.searx-secretkey.path;
|
||||
settings = {
|
||||
use_default_settings = true;
|
||||
|
||||
general = {
|
||||
instance_name = "NotASearx";
|
||||
privacypolicy_url = false;
|
||||
donation_url = "https://ko-fi.com/notashelf";
|
||||
contact_url = "mailto:raf@notashelf.dev";
|
||||
enable_metrics = true;
|
||||
debug = false;
|
||||
};
|
||||
|
||||
search = {
|
||||
safe_search = 0; # 0 = None, 1 = Moderate, 2 = Strict
|
||||
formats = ["html" "json" "rss"];
|
||||
autocomplete = "google"; # "dbpedia", "duckduckgo", "google", "startpage", "swisscows", "qwant", "wikipedia" - leave blank to turn it off by default
|
||||
default_lang = "en";
|
||||
};
|
||||
|
||||
server = {
|
||||
inherit port;
|
||||
method = "GET";
|
||||
secret_key = "@SEARX_SECRET_KEY@"; # set in the environment file
|
||||
limiter = false;
|
||||
image_proxy = false; # no thanks, lol
|
||||
default_http_headers = {
|
||||
X-Content-Type-Options = "nosniff";
|
||||
X-XSS-Protection = "1; mode=block";
|
||||
X-Download-Options = "noopen";
|
||||
X-Robots-Tag = "noindex, nofollow";
|
||||
Referrer-Policy = "no-referrer";
|
||||
};
|
||||
};
|
||||
|
||||
ui = {
|
||||
query_in_title = true;
|
||||
theme_args.simple_style = "dark"; # auto, dark, light
|
||||
results_on_new_tab = false;
|
||||
};
|
||||
|
||||
redis = {
|
||||
url = "unix://searxng:localhost@/run/redis-searxng?db=0";
|
||||
#url = "unix:///run/redis-searxng/redis.sock?db=0";
|
||||
#url = "redis://searxng@localhost:6370/0";
|
||||
};
|
||||
|
||||
outgoing = {
|
||||
request_timeout = 15.0;
|
||||
max_request_timeout = 30.0;
|
||||
};
|
||||
|
||||
engines = [
|
||||
{
|
||||
name = "wikipedia";
|
||||
engine = "wikipedia";
|
||||
shortcut = "w";
|
||||
base_url = "https://wikipedia.org/";
|
||||
}
|
||||
{
|
||||
name = "duckduckgo";
|
||||
engine = "duckduckgo";
|
||||
shortcut = "ddg";
|
||||
}
|
||||
{
|
||||
name = "google";
|
||||
engine = "google";
|
||||
shortcut = "g";
|
||||
use_mobile_ui = false;
|
||||
}
|
||||
{
|
||||
name = "archwiki";
|
||||
engine = "archlinux";
|
||||
shortcut = "aw";
|
||||
}
|
||||
{
|
||||
name = "github";
|
||||
engine = "github";
|
||||
categories = "it";
|
||||
shortcut = "gh";
|
||||
}
|
||||
{
|
||||
name = "nixpkgs";
|
||||
shortcut = "nx";
|
||||
engine = "elasticsearch";
|
||||
categories = "dev,nix";
|
||||
base_url = "https://nixos-search-5886075189.us-east-1.bonsaisearch.net:443";
|
||||
index = "latest-31-nixos-unstable";
|
||||
query_type = "match";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."search.notashelf.dev" =
|
||||
{
|
||||
locations."/".proxyPass = "http://${host}:${toString port}";
|
||||
extraConfig = ''
|
||||
access_log /dev/null;
|
||||
error_log /dev/null;
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
'';
|
||||
|
||||
quic = true;
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
imports = [
|
||||
./matrix.nix # matrix communication server
|
||||
./mastodon.nix # decentralized social
|
||||
];
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
{
|
||||
inputs',
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services.social;
|
||||
in {
|
||||
config = mkIf cfg.mastodon.enable {
|
||||
modules.system.services = {
|
||||
elasticsearch.enable = true;
|
||||
database = {
|
||||
postgresql.enable = true;
|
||||
redis.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
mastodon = {
|
||||
enable = true;
|
||||
package = inputs'.nyxpkgs.packages.mastodon-bird-ui;
|
||||
|
||||
user = "mastodon";
|
||||
|
||||
configureNginx = false;
|
||||
trustedProxy = "127.0.0.1";
|
||||
localDomain = "social.notashelf.dev";
|
||||
streamingProcesses = 2;
|
||||
|
||||
webPort = 55001;
|
||||
sidekiqPort = 55002;
|
||||
enableUnixSocket = true;
|
||||
sidekiqThreads = 12;
|
||||
|
||||
elasticsearch.host = "127.0.0.1";
|
||||
|
||||
redis = {
|
||||
createLocally = false;
|
||||
host = "localhost";
|
||||
port = 6372;
|
||||
};
|
||||
|
||||
database = {
|
||||
createLocally = true;
|
||||
host = "/run/postgresql";
|
||||
name = "mastodon";
|
||||
user = "mastodon";
|
||||
};
|
||||
|
||||
# configure smtp
|
||||
smtp = {
|
||||
authenticate = true;
|
||||
createLocally = false;
|
||||
fromAddress = "noreply@notashelf.dev";
|
||||
user = "noreply";
|
||||
host = "mail.notashelf.dev";
|
||||
passwordFile = config.age.secrets.mailserver-noreply-secret.path;
|
||||
};
|
||||
|
||||
# extra config
|
||||
extraConfig = {
|
||||
SINGLE_USER_MODE = "true";
|
||||
WEB_DOMAIN = "social.notashelf.dev";
|
||||
AUTHORIZED_FETCH = "true";
|
||||
};
|
||||
};
|
||||
|
||||
# this does what configureNginx option under the mastodon service is supposed to
|
||||
# to be able to fine-grain the service, we move it to its own configuration block
|
||||
# and also, I don't trust nixpkgs maintainers to properly maintain a service - so this is a safety net
|
||||
# in case they break another thing without proper documentation
|
||||
# /rant
|
||||
nginx = {
|
||||
virtualHosts."social.notashelf.dev" =
|
||||
{
|
||||
root = "${config.services.mastodon.package}/public/";
|
||||
quic = true;
|
||||
|
||||
locations = {
|
||||
"/" = {
|
||||
tryFiles = "$uri @proxy";
|
||||
};
|
||||
|
||||
"/system/".alias = "/var/lib/mastodon/public-system/";
|
||||
|
||||
"@proxy" = {
|
||||
proxyPass = "http://unix:/run/mastodon-web/web.socket";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
|
||||
"/api/v1/streaming/" = {
|
||||
proxyPass = "http://unix:/run/mastodon-streaming/streaming.socket";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
|
||||
users.groups.mastodon.members = [config.services.nginx.user];
|
||||
};
|
||||
}
|
201
nyx/modules/core/roles/server/system/services/social/matrix.nix
Normal file
201
nyx/modules/core/roles/server/system/services/social/matrix.nix
Normal file
|
@ -0,0 +1,201 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services.social;
|
||||
|
||||
inherit (cfg.matrix.settings) port;
|
||||
bindAddress = "::1";
|
||||
serverConfig."m.server" = "${config.services.matrix-synapse.settings.server_name}:443";
|
||||
clientConfig = {
|
||||
"m.homeserver".base_url = "https://${config.networking.domain}";
|
||||
"m.identity_server" = {};
|
||||
};
|
||||
|
||||
mkWellKnown = data: ''
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header 'Referrer-Policy' 'origin-when-cross-origin';
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
return 200 '${builtins.toJSON data}';
|
||||
'';
|
||||
in {
|
||||
config = mkIf cfg.matrix.enable {
|
||||
networking.firewall.allowedTCPPorts = [port];
|
||||
|
||||
modules.system.services.database = {
|
||||
postgresql.enable = true;
|
||||
};
|
||||
|
||||
services = {
|
||||
postgresql = {
|
||||
initialScript = pkgs.writeText "synapse-init.sql" ''
|
||||
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
|
||||
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
|
||||
TEMPLATE template0
|
||||
LC_COLLATE = "C"
|
||||
LC_CTYPE = "C";
|
||||
'';
|
||||
};
|
||||
|
||||
nginx.virtualHosts = {
|
||||
"notashelf.dev" =
|
||||
{
|
||||
serverAliases = ["matrix.notashelf.dev"];
|
||||
locations = {
|
||||
"= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
|
||||
"= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
|
||||
"/_matrix".proxyPass = "http://[${bindAddress}]:${toString port}";
|
||||
"/_synapse/client".proxyPass = "http://[${bindAddress}]:${toString port}";
|
||||
};
|
||||
|
||||
quic = true;
|
||||
http3 = true;
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
|
||||
matrix-synapse = {
|
||||
enable = true;
|
||||
|
||||
extraConfigFiles = [config.age.secrets.matrix-secret.path];
|
||||
settings = {
|
||||
server_name = "notashelf.dev";
|
||||
public_baseurl = "https://notashelf.dev";
|
||||
|
||||
withJemalloc = true;
|
||||
enable_registration = true;
|
||||
registration_requires_token = true;
|
||||
|
||||
bcrypt_rounds = 14;
|
||||
|
||||
# Don't report anonymized usage statistics
|
||||
report_stats = false;
|
||||
|
||||
# db
|
||||
database = {
|
||||
name = "psycopg2";
|
||||
args = {
|
||||
host = "/run/postgresql";
|
||||
user = "matrix-synapse";
|
||||
database = "matrix-synapse";
|
||||
cp_min = 5;
|
||||
cp_max = 10;
|
||||
};
|
||||
};
|
||||
|
||||
# media
|
||||
media_retention.remote_media_lifetime = "30d";
|
||||
max_upload_size = "100M";
|
||||
url_preview_enabled = true;
|
||||
url_preview_ip_range_blacklist = [
|
||||
"127.0.0.0/8"
|
||||
"10.0.0.0/8"
|
||||
"172.16.0.0/12"
|
||||
"192.168.0.0/16"
|
||||
"100.64.0.0/10"
|
||||
"192.0.0.0/24"
|
||||
"169.254.0.0/16"
|
||||
"192.88.99.0/24"
|
||||
"198.18.0.0/15"
|
||||
"192.0.2.0/24"
|
||||
"198.51.100.0/24"
|
||||
"203.0.113.0/24"
|
||||
"224.0.0.0/4"
|
||||
"::1/128"
|
||||
"fe80::/10"
|
||||
"fc00::/7"
|
||||
"2001:db8::/32"
|
||||
"ff00::/8"
|
||||
"fec0::/10"
|
||||
];
|
||||
|
||||
thumbnail_sizes = [
|
||||
{
|
||||
width = 32;
|
||||
height = 32;
|
||||
method = "crop";
|
||||
}
|
||||
{
|
||||
width = 96;
|
||||
height = 96;
|
||||
method = "crop";
|
||||
}
|
||||
{
|
||||
width = 320;
|
||||
height = 240;
|
||||
method = "scale";
|
||||
}
|
||||
{
|
||||
width = 640;
|
||||
height = 480;
|
||||
method = "scale";
|
||||
}
|
||||
{
|
||||
width = 800;
|
||||
height = 600;
|
||||
method = "scale";
|
||||
}
|
||||
];
|
||||
|
||||
# listener configuration
|
||||
listeners = [
|
||||
{
|
||||
inherit port;
|
||||
bind_addresses = ["${bindAddress}"];
|
||||
resources = [
|
||||
{
|
||||
names = ["client" "federation"];
|
||||
compress = true;
|
||||
}
|
||||
];
|
||||
tls = false;
|
||||
type = "http";
|
||||
x_forwarded = true;
|
||||
}
|
||||
];
|
||||
|
||||
experimental_features = {
|
||||
msc3202_device_masquerading = true;
|
||||
msc3202_transaction_extensions = true;
|
||||
msc2409_to_device_messages_enabled = true;
|
||||
};
|
||||
|
||||
logConfig = ''
|
||||
version: 1
|
||||
|
||||
# In systemd's journal, loglevel is implicitly stored, so let's omit it
|
||||
# from the message text.
|
||||
formatters:
|
||||
journal_fmt:
|
||||
format: '%(name)s: [%(request)s] %(message)s'
|
||||
|
||||
filters:
|
||||
context:
|
||||
(): synapse.util.logcontext.LoggingContextFilter
|
||||
request: ""
|
||||
|
||||
handlers:
|
||||
journal:
|
||||
class: systemd.journal.JournalHandler
|
||||
formatter: journal_fmt
|
||||
filters: [context]
|
||||
SYSLOG_IDENTIFIER: synapse
|
||||
|
||||
root:
|
||||
level: WARNING
|
||||
handlers: [journal]
|
||||
|
||||
disable_existing_loggers: False
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
35
nyx/modules/core/roles/server/system/services/tor.nix
Normal file
35
nyx/modules/core/roles/server/system/services/tor.nix
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
in {
|
||||
config = mkIf cfg.tor.enable {
|
||||
services = {
|
||||
tor = {
|
||||
settings = {
|
||||
AutomapHostsOnResolve = true;
|
||||
AutomapHostsSuffixes = [".exit" ".onion"];
|
||||
EnforceDistinctSubnets = true;
|
||||
ExitNodes = "{de}";
|
||||
EntryNodes = "{de}";
|
||||
NewCircuitPeriod = 120;
|
||||
DNSPort = 9053;
|
||||
BandWidthRate = "15 MBytes";
|
||||
};
|
||||
|
||||
relay.onionServices = {
|
||||
# hide ssh from script kiddies
|
||||
ssh = {
|
||||
version = 3;
|
||||
map = [{port = builtins.elemAt config.services.openssh.ports 0;}];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
sys = config.modules.system;
|
||||
cfg = sys.services;
|
||||
|
||||
inherit (cfg.vaultwarden.settings) port host;
|
||||
in {
|
||||
config = mkIf cfg.vaultwarden.enable {
|
||||
modules.system.services = {
|
||||
nginx.enable = true;
|
||||
};
|
||||
|
||||
# this forces the system to create backup folder
|
||||
systemd.services.backup-vaultwarden.serviceConfig = {
|
||||
User = "root";
|
||||
Group = "root";
|
||||
};
|
||||
|
||||
services = {
|
||||
vaultwarden = {
|
||||
enable = true;
|
||||
environmentFile = config.age.secrets.vaultwarden-env.path;
|
||||
backupDir = "/srv/storage/vaultwarden/backup";
|
||||
config = {
|
||||
DOMAIN = "https://vault.notashelf.dev";
|
||||
SIGNUPS_ALLOWED = false;
|
||||
ROCKET_ADDRESS = host;
|
||||
ROCKET_PORT = port;
|
||||
extendedLogging = true;
|
||||
invitationsAllowed = false;
|
||||
useSyslog = true;
|
||||
logLevel = "warn";
|
||||
showPasswordHint = false;
|
||||
signupsAllowed = false;
|
||||
signupsDomainsWhitelist = "notashelf.dev";
|
||||
signupsVerify = true;
|
||||
smtpAuthMechanism = "Login";
|
||||
smtpFrom = "vaultwarden@notashelf.dev";
|
||||
smtpFromName = "NotAShelf's Vaultwarden Service";
|
||||
smtpHost = "mail.notashelf.dev";
|
||||
smtpPort = 465;
|
||||
smtpSecurity = "force_tls";
|
||||
dataDir = "/srv/storage/vaultwarden";
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts."vault.notashelf.dev" =
|
||||
{
|
||||
locations."/" = {
|
||||
proxyPass = "http://${host}:${toString port}";
|
||||
extraConfig = "proxy_pass_header Authorization;";
|
||||
};
|
||||
|
||||
quic = true;
|
||||
}
|
||||
// lib.sslTemplate;
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue