tighten service boundaries and clean up config structure
This commit is contained in:
55
README.md
Normal file
55
README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# NixOS Config
|
||||||
|
|
||||||
|
Personal Nix flake for four machines:
|
||||||
|
|
||||||
|
- `michael` - x86_64 Linux server
|
||||||
|
- `tahani` - x86_64 Linux home server / workstation
|
||||||
|
- `chidi` - aarch64 Darwin work laptop
|
||||||
|
- `jason` - aarch64 Darwin personal laptop
|
||||||
|
|
||||||
|
## Repository Map
|
||||||
|
|
||||||
|
- `modules/` - flake-parts modules, auto-imported via `import-tree`
|
||||||
|
- `modules/_hosts/` - host-specific submodules like hardware, disks, and services
|
||||||
|
- `modules/_lib/` - local helper functions
|
||||||
|
- `apps/` - Nushell apps exposed through the flake
|
||||||
|
- `secrets/` - SOPS-encrypted secrets
|
||||||
|
- `flake.nix` - generated flake entrypoint
|
||||||
|
- `modules/dendritic.nix` - source of truth for flake inputs and `flake.nix` generation
|
||||||
|
|
||||||
|
## How It Is Structured
|
||||||
|
|
||||||
|
This repo uses `den` and organizes configuration around aspects instead of putting everything directly in host files.
|
||||||
|
|
||||||
|
- shared behavior lives in `den.aspects.<name>.<class>` modules
|
||||||
|
- hosts are declared in `modules/hosts.nix`
|
||||||
|
- host composition happens in `modules/<host>.nix`
|
||||||
|
- user-level config mostly lives in Home Manager aspects
|
||||||
|
|
||||||
|
Common examples:
|
||||||
|
|
||||||
|
- `modules/core.nix` - shared Nix and shell foundation
|
||||||
|
- `modules/dev-tools.nix` - VCS, language, and developer tooling
|
||||||
|
- `modules/network.nix` - SSH, fail2ban, and tailscale aspects
|
||||||
|
- `modules/michael.nix` - server composition for `michael`
|
||||||
|
- `modules/tahani.nix` - server/workstation composition for `tahani`
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix run .#build
|
||||||
|
nix run .#build -- michael
|
||||||
|
nix run .#apply
|
||||||
|
nix run .#deploy -- .#tahani
|
||||||
|
nix flake check
|
||||||
|
alejandra .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updating The Flake
|
||||||
|
|
||||||
|
`flake.nix` is generated. Update inputs in `modules/dendritic.nix`, then regenerate:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix run .#write-flake
|
||||||
|
alejandra .
|
||||||
|
```
|
||||||
@@ -45,7 +45,7 @@ in {
|
|||||||
{path = "/System/Applications/Music.app/";}
|
{path = "/System/Applications/Music.app/";}
|
||||||
{path = "/System/Applications/System Settings.app/";}
|
{path = "/System/Applications/System Settings.app/";}
|
||||||
{
|
{
|
||||||
path = "${config.users.users.cschmatzler.home}/Downloads";
|
path = "/Users/cschmatzler/Downloads";
|
||||||
section = "others";
|
section = "others";
|
||||||
options = "--sort name --view grid --display stack";
|
options = "--sort name --view grid --display stack";
|
||||||
}
|
}
|
||||||
|
|||||||
58
modules/_hosts/michael/backups.nix
Normal file
58
modules/_hosts/michael/backups.nix
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
services.restic.backups.gitea = {
|
||||||
|
repository = "s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories";
|
||||||
|
paths = ["/var/lib/gitea"];
|
||||||
|
exclude = [
|
||||||
|
"/var/lib/gitea/log"
|
||||||
|
"/var/lib/gitea/data/gitea.db"
|
||||||
|
"/var/lib/gitea/data/gitea.db-shm"
|
||||||
|
"/var/lib/gitea/data/gitea.db-wal"
|
||||||
|
];
|
||||||
|
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
|
||||||
|
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
||||||
|
pruneOpts = [
|
||||||
|
"--keep-daily 7"
|
||||||
|
"--keep-weekly 4"
|
||||||
|
"--keep-monthly 6"
|
||||||
|
];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "daily";
|
||||||
|
Persistent = true;
|
||||||
|
RandomizedDelaySec = "1h";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.restic-backups-gitea = {
|
||||||
|
wants = ["restic-init-gitea.service"];
|
||||||
|
after = ["restic-init-gitea.service"];
|
||||||
|
serviceConfig = {
|
||||||
|
User = lib.mkForce "gitea";
|
||||||
|
Group = lib.mkForce "gitea";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.restic-init-gitea = {
|
||||||
|
description = "Initialize Restic repository for Gitea backups";
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
after = ["network-online.target"];
|
||||||
|
wants = ["network-online.target"];
|
||||||
|
path = [pkgs.restic];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "gitea";
|
||||||
|
Group = "gitea";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
EnvironmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
export RESTIC_PASSWORD=$(cat ${config.sops.secrets.michael-gitea-restic-password.path})
|
||||||
|
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories snapshots &>/dev/null || \
|
||||||
|
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories init
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
114
modules/_hosts/michael/gitea.nix
Normal file
114
modules/_hosts/michael/gitea.nix
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
sops.secrets = {
|
||||||
|
michael-gitea-litestream = {
|
||||||
|
sopsFile = ../../../secrets/michael-gitea-litestream;
|
||||||
|
format = "binary";
|
||||||
|
owner = "gitea";
|
||||||
|
group = "gitea";
|
||||||
|
path = "/run/secrets/michael-gitea-litestream";
|
||||||
|
};
|
||||||
|
michael-gitea-restic-password = {
|
||||||
|
sopsFile = ../../../secrets/michael-gitea-restic-password;
|
||||||
|
format = "binary";
|
||||||
|
owner = "gitea";
|
||||||
|
group = "gitea";
|
||||||
|
path = "/run/secrets/michael-gitea-restic-password";
|
||||||
|
};
|
||||||
|
michael-gitea-restic-env = {
|
||||||
|
sopsFile = ../../../secrets/michael-gitea-restic-env;
|
||||||
|
format = "binary";
|
||||||
|
owner = "gitea";
|
||||||
|
group = "gitea";
|
||||||
|
path = "/run/secrets/michael-gitea-restic-env";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [80 443];
|
||||||
|
|
||||||
|
services.redis.servers.gitea = {
|
||||||
|
enable = true;
|
||||||
|
port = 6380;
|
||||||
|
bind = "127.0.0.1";
|
||||||
|
settings = {
|
||||||
|
maxmemory = "64mb";
|
||||||
|
maxmemory-policy = "allkeys-lru";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gitea = {
|
||||||
|
enable = true;
|
||||||
|
database = {
|
||||||
|
type = "sqlite3";
|
||||||
|
path = "/var/lib/gitea/data/gitea.db";
|
||||||
|
};
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
ROOT_URL = "https://git.schmatzler.com/";
|
||||||
|
DOMAIN = "git.schmatzler.com";
|
||||||
|
HTTP_ADDR = "127.0.0.1";
|
||||||
|
HTTP_PORT = 3000;
|
||||||
|
LANDING_PAGE = "explore";
|
||||||
|
};
|
||||||
|
service.DISABLE_REGISTRATION = true;
|
||||||
|
security.INSTALL_LOCK = true;
|
||||||
|
cache = {
|
||||||
|
ADAPTER = "redis";
|
||||||
|
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
|
||||||
|
ITEM_TTL = "16h";
|
||||||
|
};
|
||||||
|
"cache.last_commit" = {
|
||||||
|
ITEM_TTL = "8760h";
|
||||||
|
COMMITS_COUNT = 100;
|
||||||
|
};
|
||||||
|
session = {
|
||||||
|
PROVIDER = "redis";
|
||||||
|
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
|
||||||
|
COOKIE_SECURE = true;
|
||||||
|
SAME_SITE = "strict";
|
||||||
|
};
|
||||||
|
api.ENABLE_SWAGGER = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.litestream = {
|
||||||
|
enable = true;
|
||||||
|
environmentFile = config.sops.secrets.michael-gitea-litestream.path;
|
||||||
|
settings = {
|
||||||
|
dbs = [
|
||||||
|
{
|
||||||
|
path = "/var/lib/gitea/data/gitea.db";
|
||||||
|
replicas = [
|
||||||
|
{
|
||||||
|
type = "s3";
|
||||||
|
bucket = "michael-gitea-litestream";
|
||||||
|
path = "gitea";
|
||||||
|
endpoint = "s3.eu-central-003.backblazeb2.com";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.litestream.serviceConfig = {
|
||||||
|
User = lib.mkForce "gitea";
|
||||||
|
Group = lib.mkForce "gitea";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.caddy = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts."git.schmatzler.com".extraConfig = ''
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "DENY"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
reverse_proxy localhost:3000
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{config, ...}: {
|
||||||
services.adguardhome = {
|
services.adguardhome = {
|
||||||
enable = true;
|
enable = true;
|
||||||
host = "0.0.0.0";
|
host = "127.0.0.1";
|
||||||
port = 10000;
|
port = 10000;
|
||||||
settings = {
|
settings = {
|
||||||
dhcp = {
|
dhcp = {
|
||||||
@@ -57,4 +57,13 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.caddy.virtualHosts."adguard.manticore-hippocampus.ts.net" = {
|
||||||
|
extraConfig = ''
|
||||||
|
tls {
|
||||||
|
get_certificate tailscale
|
||||||
|
}
|
||||||
|
reverse_proxy localhost:${toString config.services.adguardhome.port}
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,11 @@
|
|||||||
virtualisation.oci-containers = {
|
virtualisation.oci-containers = {
|
||||||
backend = "docker";
|
backend = "docker";
|
||||||
containers.paperless-ai = {
|
containers.paperless-ai = {
|
||||||
image = "clusterzx/paperless-ai:latest";
|
image = "clusterzx/paperless-ai:v3.0.9";
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
|
ports = [
|
||||||
|
"127.0.0.1:3000:3000"
|
||||||
|
];
|
||||||
volumes = [
|
volumes = [
|
||||||
"paperless-ai-data:/app/data"
|
"paperless-ai-data:/app/data"
|
||||||
];
|
];
|
||||||
@@ -36,11 +39,10 @@
|
|||||||
PAPERLESS_AI_PORT = "3000";
|
PAPERLESS_AI_PORT = "3000";
|
||||||
# Initial setup wizard will configure the rest
|
# Initial setup wizard will configure the rest
|
||||||
PAPERLESS_AI_INITIAL_SETUP = "yes";
|
PAPERLESS_AI_INITIAL_SETUP = "yes";
|
||||||
# Paperless-ngx API URL accessible from container (using host network)
|
PAPERLESS_API_URL = "http://host.docker.internal:${toString config.services.paperless.port}/api";
|
||||||
PAPERLESS_API_URL = "http://127.0.0.1:${toString config.services.paperless.port}/api";
|
|
||||||
};
|
};
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
"--network=host"
|
"--add-host=host.docker.internal:host-gateway"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -57,7 +59,7 @@
|
|||||||
|
|
||||||
services.paperless = {
|
services.paperless = {
|
||||||
enable = true;
|
enable = true;
|
||||||
address = "0.0.0.0";
|
address = "127.0.0.1";
|
||||||
passwordFile = config.sops.secrets.tahani-paperless-password.path;
|
passwordFile = config.sops.secrets.tahani-paperless-password.path;
|
||||||
settings = {
|
settings = {
|
||||||
PAPERLESS_DBENGINE = "sqlite";
|
PAPERLESS_DBENGINE = "sqlite";
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
user = "cschmatzler";
|
|
||||||
|
|
||||||
sshKeys = [
|
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHfRZQ+7ejD3YHbyMTrV0gN1Gc0DxtGgl5CVZSupo5ws"
|
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/I+/2QT47raegzMIyhwMEPKarJP/+Ox9ewA4ZFJwk/"
|
|
||||||
];
|
|
||||||
|
|
||||||
stateVersions = {
|
|
||||||
darwin = 6;
|
|
||||||
nixos = "25.11";
|
|
||||||
homeManager = "25.11";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{pkgs}:
|
|
||||||
pkgs.writeShellScriptBin "open-project" ''
|
|
||||||
TARGET=$(fd -t d --exact-depth 1 . $HOME/Projects |
|
|
||||||
sed "s~$HOME/Projects/~~" |
|
|
||||||
fzf --prompt "project > ")
|
|
||||||
|
|
||||||
if [ -n "$TARGET" ]; then
|
|
||||||
echo "$HOME/Projects/$TARGET"
|
|
||||||
fi
|
|
||||||
''
|
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
ExecStart = "${inputs'.llm-agents.packages.opencode}/bin/opencode serve --port 18822";
|
ExecStart = "${inputs'.llm-agents.packages.opencode}/bin/opencode serve --port 18822";
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = 5;
|
RestartSec = 5;
|
||||||
Environment = "PATH=${config.home.profileDirectory}/bin:/run/current-system/sw/bin";
|
Environment = "PATH=${pkgs.lib.makeBinPath [inputs'.llm-agents.packages.opencode pkgs.coreutils pkgs.nodejs_24 pkgs.nushell]}:/run/current-system/sw/bin";
|
||||||
};
|
};
|
||||||
Install = {
|
Install = {
|
||||||
WantedBy = ["default.target"];
|
WantedBy = ["default.target"];
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
nix = {
|
nix = {
|
||||||
settings.trusted-users = ["@admin" "cschmatzler"];
|
settings.trusted-users = ["cschmatzler"];
|
||||||
gc.interval = {
|
gc.interval = {
|
||||||
Weekday = 0;
|
Weekday = 0;
|
||||||
Hour = 2;
|
Hour = 2;
|
||||||
|
|||||||
@@ -23,16 +23,19 @@
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
flake.flakeModules = {
|
flake.flakeModules = {
|
||||||
|
# Shared system foundations
|
||||||
|
core = ./core.nix;
|
||||||
|
network = ./network.nix;
|
||||||
|
nixos-system = ./nixos-system.nix;
|
||||||
|
|
||||||
|
# User environment
|
||||||
ai-tools = ./ai-tools.nix;
|
ai-tools = ./ai-tools.nix;
|
||||||
atuin = ./atuin.nix;
|
atuin = ./atuin.nix;
|
||||||
core = ./core.nix;
|
|
||||||
desktop = ./desktop.nix;
|
desktop = ./desktop.nix;
|
||||||
dev-tools = ./dev-tools.nix;
|
dev-tools = ./dev-tools.nix;
|
||||||
email = ./email.nix;
|
email = ./email.nix;
|
||||||
finance = ./finance.nix;
|
finance = ./finance.nix;
|
||||||
neovim = ./neovim.nix;
|
neovim = ./neovim.nix;
|
||||||
network = ./network.nix;
|
|
||||||
nixos-system = ./nixos-system.nix;
|
|
||||||
shell = ./shell.nix;
|
shell = ./shell.nix;
|
||||||
ssh-client = ./ssh-client.nix;
|
ssh-client = ./ssh-client.nix;
|
||||||
terminal = ./terminal.nix;
|
terminal = ./terminal.nix;
|
||||||
|
|||||||
@@ -378,21 +378,23 @@
|
|||||||
ast-grep
|
ast-grep
|
||||||
bun
|
bun
|
||||||
delta
|
delta
|
||||||
|
deadnix
|
||||||
devenv
|
devenv
|
||||||
docker
|
docker
|
||||||
docker-compose
|
docker-compose
|
||||||
gh
|
gh
|
||||||
git
|
|
||||||
gnumake
|
gnumake
|
||||||
hyperfine
|
hyperfine
|
||||||
jj-ryu
|
jj-ryu
|
||||||
jj-starship
|
jj-starship
|
||||||
|
nil
|
||||||
nodejs_24
|
nodejs_24
|
||||||
nurl
|
nurl
|
||||||
pnpm
|
pnpm
|
||||||
postgresql_17
|
postgresql_17
|
||||||
serie
|
serie
|
||||||
sqlite
|
sqlite
|
||||||
|
statix
|
||||||
tea
|
tea
|
||||||
tokei
|
tokei
|
||||||
tree-sitter
|
tree-sitter
|
||||||
|
|||||||
@@ -11,180 +11,16 @@
|
|||||||
den.aspects.tailscale
|
den.aspects.tailscale
|
||||||
];
|
];
|
||||||
|
|
||||||
den.aspects.michael.nixos = {
|
den.aspects.michael.nixos = {modulesPath, ...}: {
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
modulesPath,
|
|
||||||
...
|
|
||||||
}: {
|
|
||||||
imports = [
|
imports = [
|
||||||
(modulesPath + "/installer/scan/not-detected.nix")
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
./_hosts/michael/backups.nix
|
||||||
./_hosts/michael/disk-config.nix
|
./_hosts/michael/disk-config.nix
|
||||||
|
./_hosts/michael/gitea.nix
|
||||||
./_hosts/michael/hardware-configuration.nix
|
./_hosts/michael/hardware-configuration.nix
|
||||||
inputs.disko.nixosModules.default
|
inputs.disko.nixosModules.default
|
||||||
];
|
];
|
||||||
|
|
||||||
networking.hostName = "michael";
|
networking.hostName = "michael";
|
||||||
|
|
||||||
sops.secrets = {
|
|
||||||
michael-gitea-litestream = {
|
|
||||||
sopsFile = ../secrets/michael-gitea-litestream;
|
|
||||||
format = "binary";
|
|
||||||
owner = "gitea";
|
|
||||||
group = "gitea";
|
|
||||||
};
|
|
||||||
michael-gitea-restic-password = {
|
|
||||||
sopsFile = ../secrets/michael-gitea-restic-password;
|
|
||||||
format = "binary";
|
|
||||||
owner = "gitea";
|
|
||||||
group = "gitea";
|
|
||||||
};
|
|
||||||
michael-gitea-restic-env = {
|
|
||||||
sopsFile = ../secrets/michael-gitea-restic-env;
|
|
||||||
format = "binary";
|
|
||||||
owner = "gitea";
|
|
||||||
group = "gitea";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [80 443];
|
|
||||||
|
|
||||||
services.redis.servers.gitea = {
|
|
||||||
enable = true;
|
|
||||||
port = 6380;
|
|
||||||
bind = "127.0.0.1";
|
|
||||||
settings = {
|
|
||||||
maxmemory = "64mb";
|
|
||||||
maxmemory-policy = "allkeys-lru";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.gitea = {
|
|
||||||
enable = true;
|
|
||||||
database = {
|
|
||||||
type = "sqlite3";
|
|
||||||
path = "/var/lib/gitea/data/gitea.db";
|
|
||||||
};
|
|
||||||
settings = {
|
|
||||||
server = {
|
|
||||||
ROOT_URL = "https://git.schmatzler.com/";
|
|
||||||
DOMAIN = "git.schmatzler.com";
|
|
||||||
HTTP_ADDR = "127.0.0.1";
|
|
||||||
HTTP_PORT = 3000;
|
|
||||||
LANDING_PAGE = "explore";
|
|
||||||
};
|
|
||||||
service.DISABLE_REGISTRATION = true;
|
|
||||||
security.INSTALL_LOCK = true;
|
|
||||||
cache = {
|
|
||||||
ADAPTER = "redis";
|
|
||||||
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
|
|
||||||
ITEM_TTL = "16h";
|
|
||||||
};
|
|
||||||
"cache.last_commit" = {
|
|
||||||
ITEM_TTL = "8760h";
|
|
||||||
COMMITS_COUNT = 100;
|
|
||||||
};
|
|
||||||
session = {
|
|
||||||
PROVIDER = "redis";
|
|
||||||
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
|
|
||||||
COOKIE_SECURE = true;
|
|
||||||
SAME_SITE = "strict";
|
|
||||||
};
|
|
||||||
api.ENABLE_SWAGGER = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.litestream = {
|
|
||||||
enable = true;
|
|
||||||
environmentFile = config.sops.secrets.michael-gitea-litestream.path;
|
|
||||||
settings = {
|
|
||||||
dbs = [
|
|
||||||
{
|
|
||||||
path = "/var/lib/gitea/data/gitea.db";
|
|
||||||
replicas = [
|
|
||||||
{
|
|
||||||
type = "s3";
|
|
||||||
bucket = "michael-gitea-litestream";
|
|
||||||
path = "gitea";
|
|
||||||
endpoint = "s3.eu-central-003.backblazeb2.com";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.litestream = {
|
|
||||||
serviceConfig = {
|
|
||||||
User = lib.mkForce "gitea";
|
|
||||||
Group = lib.mkForce "gitea";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.caddy = {
|
|
||||||
enable = true;
|
|
||||||
virtualHosts."git.schmatzler.com".extraConfig = ''
|
|
||||||
header {
|
|
||||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
||||||
X-Content-Type-Options "nosniff"
|
|
||||||
X-Frame-Options "DENY"
|
|
||||||
Referrer-Policy "strict-origin-when-cross-origin"
|
|
||||||
}
|
|
||||||
reverse_proxy localhost:3000
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services.restic.backups.gitea = {
|
|
||||||
repository = "s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories";
|
|
||||||
paths = ["/var/lib/gitea"];
|
|
||||||
exclude = [
|
|
||||||
"/var/lib/gitea/log"
|
|
||||||
"/var/lib/gitea/data/gitea.db"
|
|
||||||
"/var/lib/gitea/data/gitea.db-shm"
|
|
||||||
"/var/lib/gitea/data/gitea.db-wal"
|
|
||||||
];
|
|
||||||
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
|
|
||||||
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
|
||||||
pruneOpts = [
|
|
||||||
"--keep-daily 7"
|
|
||||||
"--keep-weekly 4"
|
|
||||||
"--keep-monthly 6"
|
|
||||||
];
|
|
||||||
timerConfig = {
|
|
||||||
OnCalendar = "daily";
|
|
||||||
Persistent = true;
|
|
||||||
RandomizedDelaySec = "1h";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.restic-backups-gitea = {
|
|
||||||
wants = ["restic-init-gitea.service"];
|
|
||||||
after = ["restic-init-gitea.service"];
|
|
||||||
serviceConfig = {
|
|
||||||
User = lib.mkForce "gitea";
|
|
||||||
Group = lib.mkForce "gitea";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.restic-init-gitea = {
|
|
||||||
description = "Initialize Restic repository for Gitea backups";
|
|
||||||
wantedBy = ["multi-user.target"];
|
|
||||||
after = ["network-online.target"];
|
|
||||||
wants = ["network-online.target"];
|
|
||||||
path = [pkgs.restic];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
User = "gitea";
|
|
||||||
Group = "gitea";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
EnvironmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
export RESTIC_PASSWORD=$(cat ${config.sops.secrets.michael-gitea-restic-password.path})
|
|
||||||
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories snapshots &>/dev/null || \
|
|
||||||
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories init
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,7 +284,6 @@
|
|||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
vivid
|
vivid
|
||||||
(callPackage ./_lib/open-project.nix {})
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
{...}: {
|
{...}: {
|
||||||
den.aspects.ssh-client.homeManager = {
|
den.aspects.ssh-client.homeManager = {
|
||||||
config,
|
config,
|
||||||
lib,
|
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}: let
|
||||||
|
homeDir = "${
|
||||||
|
if pkgs.stdenv.hostPlatform.isDarwin
|
||||||
|
then "/Users"
|
||||||
|
else "/home"
|
||||||
|
}/${config.home.username}";
|
||||||
|
in {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableDefaultConfig = false;
|
enableDefaultConfig = false;
|
||||||
includes = [
|
includes = [
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux "/home/${config.home.username}/.ssh/config_external")
|
"${homeDir}/.ssh/config_external"
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isDarwin "/Users/${config.home.username}/.ssh/config_external")
|
|
||||||
];
|
];
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
"*" = {};
|
"*" = {};
|
||||||
"github.com" = {
|
"github.com" = {
|
||||||
identitiesOnly = true;
|
identitiesOnly = true;
|
||||||
identityFile = [
|
identityFile = [
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux "/home/${config.home.username}/.ssh/id_ed25519")
|
"${homeDir}/.ssh/id_ed25519"
|
||||||
(lib.mkIf pkgs.stdenv.hostPlatform.isDarwin "/Users/${config.home.username}/.ssh/id_ed25519")
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
home.packages = [pkgs.openssh];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,13 @@
|
|||||||
tahani-paperless-password = {
|
tahani-paperless-password = {
|
||||||
sopsFile = ../secrets/tahani-paperless-password;
|
sopsFile = ../secrets/tahani-paperless-password;
|
||||||
format = "binary";
|
format = "binary";
|
||||||
|
path = "/run/secrets/tahani-paperless-password";
|
||||||
};
|
};
|
||||||
tahani-email-password = {
|
tahani-email-password = {
|
||||||
sopsFile = ../secrets/tahani-email-password;
|
sopsFile = ../secrets/tahani-email-password;
|
||||||
format = "binary";
|
format = "binary";
|
||||||
owner = "cschmatzler";
|
owner = "cschmatzler";
|
||||||
|
path = "/run/secrets/tahani-email-password";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
virtualisation.docker.enable = true;
|
virtualisation.docker.enable = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user