Compare commits
No commits in common. "c41de5cd4689e5e6be7609b6399efbe2d5390082" and "14ec1eca2eb99b256eb972202ee65a78cb70439b" have entirely different histories.
c41de5cd46
...
14ec1eca2e
12 changed files with 216 additions and 942 deletions
12
flake.nix
12
flake.nix
|
|
@ -57,7 +57,6 @@
|
||||||
|
|
||||||
mkSharedModules = pkgs: pkgs-unstable: [
|
mkSharedModules = pkgs: pkgs-unstable: [
|
||||||
./nixos/modules/base.nix
|
./nixos/modules/base.nix
|
||||||
./nixos/modules/services/wireguard-peer.nix
|
|
||||||
inputs.home-manager.nixosModules.home-manager
|
inputs.home-manager.nixosModules.home-manager
|
||||||
({ ... }: {
|
({ ... }: {
|
||||||
home-manager.useGlobalPkgs = true;
|
home-manager.useGlobalPkgs = true;
|
||||||
|
|
@ -76,7 +75,6 @@
|
||||||
nixosModules ? [ ],
|
nixosModules ? [ ],
|
||||||
hmModules ? [ ],
|
hmModules ? [ ],
|
||||||
extraModules ? [ ],
|
extraModules ? [ ],
|
||||||
homeManagerUsers ? true,
|
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
pkgs = mkPkgs system;
|
pkgs = mkPkgs system;
|
||||||
|
|
@ -93,7 +91,7 @@
|
||||||
++ [ (./nixos/hosts + "/${hostName}/configuration.nix") ]
|
++ [ (./nixos/hosts + "/${hostName}/configuration.nix") ]
|
||||||
++ nixosModules
|
++ nixosModules
|
||||||
++ extraModules
|
++ extraModules
|
||||||
++ nixpkgs.lib.optionals homeManagerUsers [
|
++ [
|
||||||
{
|
{
|
||||||
home-manager.users.alisceon.imports =
|
home-manager.users.alisceon.imports =
|
||||||
[
|
[
|
||||||
|
|
@ -169,14 +167,6 @@
|
||||||
nixosModules = serverModules;
|
nixosModules = serverModules;
|
||||||
hmModules = serverHomeModules;
|
hmModules = serverHomeModules;
|
||||||
};
|
};
|
||||||
|
|
||||||
blogbox = mkHost {
|
|
||||||
hostName = "blogbox";
|
|
||||||
system = "x86_64-linux";
|
|
||||||
nixosModules = serverModules;
|
|
||||||
hmModules = serverHomeModules;
|
|
||||||
homeManagerUsers = false;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
{ pkgs, repoRoot, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
let
|
||||||
commands = import ../../../../lib/commands.nix { inherit pkgs; };
|
commands = import ../../../../lib/commands.nix { inherit pkgs; };
|
||||||
inherit (commands) uwsm term;
|
inherit (commands) uwsm term;
|
||||||
height = 20;
|
height = 20;
|
||||||
wireguardToggle = "${pkgs.xonsh}/bin/xonsh ${repoRoot}/util/toggle_wg.xsh";
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
|
@ -36,12 +35,11 @@ in
|
||||||
};
|
};
|
||||||
"modules" = [
|
"modules" = [
|
||||||
"clock"
|
"clock"
|
||||||
"idle_inhibitor"
|
|
||||||
"sway/language"
|
"sway/language"
|
||||||
"network"
|
"network"
|
||||||
"custom/wireguard"
|
|
||||||
"bluetooth"
|
"bluetooth"
|
||||||
"pulseaudio"
|
"pulseaudio"
|
||||||
|
"idle_inhibitor"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
"sway/workspaces" = {
|
"sway/workspaces" = {
|
||||||
|
|
@ -55,7 +53,7 @@ in
|
||||||
spacing = 8;
|
spacing = 8;
|
||||||
};
|
};
|
||||||
idle_inhibitor = {
|
idle_inhibitor = {
|
||||||
format = "| {icon} ";
|
format = "| {icon}";
|
||||||
start-activated = true;
|
start-activated = true;
|
||||||
format-icons = {
|
format-icons = {
|
||||||
activated = "🫨";
|
activated = "🫨";
|
||||||
|
|
@ -63,8 +61,7 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"sway/language" = {
|
"sway/language" = {
|
||||||
# this one gobbles all trailing ascii whitespace for some reason. use this unicode instead
|
format = "| {short}";
|
||||||
format = "| {short} ";
|
|
||||||
tooltip-format = "{long}";
|
tooltip-format = "{long}";
|
||||||
};
|
};
|
||||||
clock = {
|
clock = {
|
||||||
|
|
@ -75,36 +72,29 @@ in
|
||||||
};
|
};
|
||||||
battery = {
|
battery = {
|
||||||
interval = 60;
|
interval = 60;
|
||||||
format = "| {capacity}% ";
|
format = "| {capacity}%";
|
||||||
format-charging = "| ch:{capacity}% ";
|
format-charging = "| ch:{capacity}%";
|
||||||
};
|
};
|
||||||
network = {
|
network = {
|
||||||
tooltip-format = "{ifname} = {ipaddr}/{cidr}";
|
tooltip-format = "{ifname} = {ipaddr}/{cidr}";
|
||||||
format-wifi = "| w:{essid} ";
|
format-wifi = "| w:{ipaddr}";
|
||||||
format-ethernet = "| e:{ipaddr} ";
|
format-ethernet = "| e:{ipaddr}";
|
||||||
format-linked = "| l:{ipaddr} ";
|
format-linked = "| l:{ipaddr}";
|
||||||
format-disconnected = "| w:d ";
|
format-disconnected = "| d";
|
||||||
interval = 15;
|
interval = 15;
|
||||||
on-click = "${uwsm} ${term} -e nmtui";
|
on-click = "${uwsm} ${term} -e nmtui";
|
||||||
};
|
};
|
||||||
"custom/wireguard" = {
|
|
||||||
exec = "${wireguardToggle} status";
|
|
||||||
on-click = "${wireguardToggle} toggle";
|
|
||||||
format = "| wg:{text} ";
|
|
||||||
interval = 15;
|
|
||||||
tooltip = false;
|
|
||||||
};
|
|
||||||
bluetooth = {
|
bluetooth = {
|
||||||
format = "| bt:{num_connections} ";
|
format = "| bt:{num_connections}";
|
||||||
format-disabled = "";
|
format-disabled = "";
|
||||||
format-no-controller = "";
|
format-no-controller = "";
|
||||||
interval = 15;
|
interval = 15;
|
||||||
on-click = "${uwsm} ${term} -e bluetui";
|
on-click = "${uwsm} ${term} -e bluetui";
|
||||||
};
|
};
|
||||||
pulseaudio = {
|
pulseaudio = {
|
||||||
format = "| snd{volume}% ";
|
format = "| snd{volume}%";
|
||||||
format-muted = "| snd:- ";
|
format-muted = "| snd:-";
|
||||||
format-bluetooth = "| snd(bt):{volume}% ";
|
format-bluetooth = "| snd(bt):{volume}%";
|
||||||
on-click = "${uwsm} pavucontrol";
|
on-click = "${uwsm} pavucontrol";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,63 @@
|
||||||
{ lib, pkgs, modulesPath, ... }:
|
{ lib, pkgs, modulesPath, ... }:
|
||||||
|
let
|
||||||
|
forgejoDomain = "git.alisceon.com";
|
||||||
|
forgejoRunnerTokenFile = "/var/lib/forgejo/runner_token";
|
||||||
|
|
||||||
|
fetchOciAuthorizedKeys = pkgs.writeShellApplication {
|
||||||
|
name = "fetch-oci-authorized-keys";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.curl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
install -d -m 0700 -o alisceon -g users /home/alisceon/.ssh
|
||||||
|
|
||||||
|
if [ -s /home/alisceon/.ssh/authorized_keys ]; then
|
||||||
|
echo "OCI authorized_keys already present for alisceon"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl --fail --silent --show-error --location \
|
||||||
|
--header "Authorization: Bearer Oracle" \
|
||||||
|
--output /home/alisceon/.ssh/authorized_keys \
|
||||||
|
http://169.254.169.254/opc/v2/instance/metadata/ssh_authorized_keys
|
||||||
|
|
||||||
|
chown alisceon:users /home/alisceon/.ssh/authorized_keys
|
||||||
|
chmod 0600 /home/alisceon/.ssh/authorized_keys
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
generateForgejoRunnerToken = pkgs.writeShellApplication {
|
||||||
|
name = "generate-forgejo-runner-token";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.util-linux
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
token_file=${lib.escapeShellArg forgejoRunnerTokenFile}
|
||||||
|
|
||||||
|
if [ -s "$token_file" ]; then
|
||||||
|
chmod 0600 "$token_file"
|
||||||
|
chown root:root "$token_file"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -d -m 0750 -o forgejo -g forgejo /var/lib/forgejo
|
||||||
|
token="$(runuser -u forgejo -- env \
|
||||||
|
FORGEJO_WORK_DIR=/var/lib/forgejo \
|
||||||
|
FORGEJO_CUSTOM=/var/lib/forgejo/custom \
|
||||||
|
${lib.getExe pkgs.forgejo-lts} actions generate-runner-token)"
|
||||||
|
|
||||||
|
umask 0077
|
||||||
|
printf 'TOKEN=%s\n' "$token" > "$token_file"
|
||||||
|
chown root:root "$token_file"
|
||||||
|
chmod 0600 "$token_file"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
"${modulesPath}/virtualisation/oci-image.nix"
|
"${modulesPath}/virtualisation/oci-image.nix"
|
||||||
../../modules/services/cloud-init.nix
|
|
||||||
../../modules/services/forgejo.nix
|
|
||||||
../../modules/services/nginx.nix
|
|
||||||
../../modules/services/oci-authorized-keys.nix
|
|
||||||
../../modules/services/tor.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
|
||||||
|
|
@ -18,12 +69,8 @@
|
||||||
22
|
22
|
||||||
80
|
80
|
||||||
443
|
443
|
||||||
22000
|
|
||||||
24601
|
24601
|
||||||
];
|
];
|
||||||
firewall.allowedUDPPorts = [
|
|
||||||
22000
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
boot = {
|
boot = {
|
||||||
|
|
@ -63,14 +110,6 @@
|
||||||
|
|
||||||
users.users.alisceon.extraGroups = [ "systemd-journal" ];
|
users.users.alisceon.extraGroups = [ "systemd-journal" ];
|
||||||
|
|
||||||
alisceon = {
|
|
||||||
cloud-init = {
|
|
||||||
enable = true;
|
|
||||||
defaultShell = "/run/current-system/sw/bin/xonsh";
|
|
||||||
};
|
|
||||||
ociAuthorizedKeys.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
security = {
|
security = {
|
||||||
acme = {
|
acme = {
|
||||||
acceptTerms = true;
|
acceptTerms = true;
|
||||||
|
|
@ -84,94 +123,169 @@
|
||||||
PermitRootLogin = lib.mkForce "prohibit-password";
|
PermitRootLogin = lib.mkForce "prohibit-password";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.syncthing = {
|
services.forgejo = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = "/var/lib/syncthing";
|
package = pkgs.forgejo-lts;
|
||||||
guiAddress = "127.0.0.1:8384";
|
database.type = "sqlite3";
|
||||||
openDefaultPorts = false;
|
lfs.enable = true;
|
||||||
overrideDevices = false;
|
|
||||||
overrideFolders = false;
|
|
||||||
settings = {
|
settings = {
|
||||||
gui = {
|
server = {
|
||||||
insecureAdminAccess = false;
|
DOMAIN = forgejoDomain;
|
||||||
insecureSkipHostcheck = false;
|
ROOT_URL = "https://${forgejoDomain}/";
|
||||||
|
HTTP_ADDR = "127.0.0.1";
|
||||||
|
HTTP_PORT = 3000;
|
||||||
|
SSH_DOMAIN = forgejoDomain;
|
||||||
|
SSH_PORT = 22;
|
||||||
|
DISABLE_SSH = false;
|
||||||
};
|
};
|
||||||
options = {
|
session.COOKIE_SECURE = true;
|
||||||
globalAnnounceEnabled = false;
|
service = {
|
||||||
localAnnounceEnabled = false;
|
DISABLE_REGISTRATION = true;
|
||||||
listenAddresses = [
|
REQUIRE_SIGNIN_VIEW = false;
|
||||||
"tcp://0.0.0.0:22000"
|
};
|
||||||
"quic://0.0.0.0:22000"
|
actions.ENABLED = true;
|
||||||
];
|
repository = {
|
||||||
natEnabled = false;
|
DEFAULT_PRIVATE = "private";
|
||||||
relaysEnabled = false;
|
DISABLE_HTTP_GIT = false;
|
||||||
urAccepted = -1;
|
};
|
||||||
|
"cron.archive_cleanup" = {
|
||||||
|
ENABLED = true;
|
||||||
|
RUN_AT_START = true;
|
||||||
|
SCHEDULE = "@every 24h";
|
||||||
|
OLDER_THAN = "72h";
|
||||||
|
};
|
||||||
|
log.LEVEL = "Warn";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gitea-actions-runner = {
|
||||||
|
package = pkgs.forgejo-runner;
|
||||||
|
instances.alisceon-core-podman = {
|
||||||
|
enable = true;
|
||||||
|
name = "alisceon-core-podman";
|
||||||
|
url = "https://${forgejoDomain}";
|
||||||
|
tokenFile = forgejoRunnerTokenFile;
|
||||||
|
labels = [
|
||||||
|
"ubuntu-latest:docker://node:22-bookworm"
|
||||||
|
"debian-latest:docker://node:22-bookworm"
|
||||||
|
];
|
||||||
|
settings = {
|
||||||
|
container = {
|
||||||
|
network = "host";
|
||||||
|
privileged = false;
|
||||||
|
valid_volumes = [ ];
|
||||||
|
};
|
||||||
|
cache.enabled = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
alisceon.forgejo.domain = "forgejo.alisceon.com";
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
services.gitea-actions-runner.instances.alisceon-core-podman.labels = [
|
recommendedGzipSettings = true;
|
||||||
"podman"
|
recommendedOptimisation = true;
|
||||||
"aarch64"
|
recommendedProxySettings = true;
|
||||||
"arm64"
|
recommendedTlsSettings = true;
|
||||||
];
|
virtualHosts = {
|
||||||
|
"_" = {
|
||||||
services.nginx.virtualHosts = {
|
default = true;
|
||||||
${"forgejo.alisceon.com"} = {
|
rejectSSL = true;
|
||||||
serverName = "forgejo.alisceon.com";
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:3000";
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
${"syncthing.alisceon.com"} = {
|
|
||||||
serverName = "syncthing.alisceon.com";
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8384";
|
|
||||||
recommendedProxySettings = false;
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_set_header Host $proxy_host;
|
return 421;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
${forgejoDomain} = {
|
||||||
|
serverName = forgejoDomain;
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.syncthing = {
|
services.tor = {
|
||||||
serviceConfig = {
|
enable = true;
|
||||||
LockPersonality = true;
|
client.enable = false;
|
||||||
PrivateIPC = true;
|
relay = {
|
||||||
ProcSubset = "pid";
|
enable = true;
|
||||||
ProtectClock = true;
|
role = "relay";
|
||||||
ProtectHome = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
ReadWritePaths = [ "/var/lib/syncthing" ];
|
|
||||||
RemoveIPC = true;
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK"
|
|
||||||
"AF_UNIX"
|
|
||||||
];
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
UMask = "0077";
|
|
||||||
};
|
};
|
||||||
|
settings = {
|
||||||
|
Nickname = "alisceondotcom";
|
||||||
|
ORPort = 24601;
|
||||||
|
DataDirectory = "/var/lib/tor";
|
||||||
|
ExitRelay = false;
|
||||||
|
ExitPolicy = [ "reject *:*" ];
|
||||||
|
RelayBandwidthRate = "25 MBytes";
|
||||||
|
RelayBandwidthBurst = "25 MBytes";
|
||||||
|
BandwidthRate = "25 MBytes";
|
||||||
|
BandwidthBurst = "25 MBytes";
|
||||||
|
AccountingStart = "month 1 00:00";
|
||||||
|
AccountingMax = "8500 GBytes";
|
||||||
|
DirCache = true;
|
||||||
|
AvoidDiskWrites = 1;
|
||||||
|
Sandbox = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.cloud-init = {
|
||||||
|
enable = true;
|
||||||
|
network.enable = true;
|
||||||
|
settings = {
|
||||||
|
datasource_list = [ "Oracle" "ConfigDrive" "NoCloud" ];
|
||||||
|
users = [ "default" ];
|
||||||
|
system_info.default_user = {
|
||||||
|
name = "alisceon";
|
||||||
|
gecos = "Alisceon";
|
||||||
|
groups = [ "wheel" "systemd-journal" ];
|
||||||
|
shell = "/run/current-system/sw/bin/xonsh";
|
||||||
|
lock_passwd = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.fetch-oci-authorized-keys = {
|
||||||
|
description = "Fetch OCI metadata authorized_keys for alisceon";
|
||||||
|
wantedBy = [ "sshd.service" ];
|
||||||
|
before = [ "sshd.service" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
StandardError = "journal+console";
|
||||||
|
StandardOutput = "journal+console";
|
||||||
|
};
|
||||||
|
script = lib.getExe fetchOciAuthorizedKeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.fetch-ssh-keys.enable = false;
|
||||||
|
|
||||||
|
systemd.services.forgejo-runner-token = {
|
||||||
|
description = "Generate Forgejo runner registration token";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "forgejo.service" ];
|
||||||
|
requires = [ "forgejo.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
StandardError = "journal+console";
|
||||||
|
StandardOutput = "journal+console";
|
||||||
|
};
|
||||||
|
script = lib.getExe generateForgejoRunnerToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services."gitea-runner-alisceon\\x2dcore\\x2dpodman" = {
|
||||||
|
after = [ "forgejo-runner-token.service" ];
|
||||||
|
requires = [ "forgejo-runner-token.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
curl
|
curl
|
||||||
|
forgejo-lts
|
||||||
git
|
git
|
||||||
htop
|
htop
|
||||||
jq
|
jq
|
||||||
|
|
|
||||||
|
|
@ -1,401 +0,0 @@
|
||||||
{ lib, pkgs, modulesPath, ... }:
|
|
||||||
let
|
|
||||||
siteDomain = "blogbox.alisceon.com";
|
|
||||||
repoDir = "/home/alisceon/blogbox-site";
|
|
||||||
stateDir = "/var/lib/blogbox";
|
|
||||||
publicDir = "${stateDir}/www";
|
|
||||||
|
|
||||||
updateBlogboxSite = pkgs.writeShellApplication {
|
|
||||||
name = "update-blogbox-site";
|
|
||||||
runtimeInputs = [
|
|
||||||
pkgs.coreutils
|
|
||||||
pkgs.git
|
|
||||||
pkgs.hugo
|
|
||||||
pkgs.rsync
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [ ! -d ${lib.escapeShellArg repoDir}/.git ]; then
|
|
||||||
echo "${repoDir} is not a git checkout yet; skipping Hugo publish"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
install -d -m 0755 ${lib.escapeShellArg stateDir} ${lib.escapeShellArg publicDir}
|
|
||||||
|
|
||||||
git -C ${lib.escapeShellArg repoDir} pull --ff-only
|
|
||||||
git -C ${lib.escapeShellArg repoDir} submodule sync --recursive
|
|
||||||
git -C ${lib.escapeShellArg repoDir} submodule update --init --recursive
|
|
||||||
|
|
||||||
rm -rf ${lib.escapeShellArg stateDir}/hugo-public
|
|
||||||
hugo \
|
|
||||||
--source ${lib.escapeShellArg repoDir} \
|
|
||||||
--destination ${lib.escapeShellArg stateDir}/hugo-public \
|
|
||||||
--minify \
|
|
||||||
--cleanDestinationDir
|
|
||||||
|
|
||||||
rsync -a --delete ${lib.escapeShellArg stateDir}/hugo-public/ ${lib.escapeShellArg publicDir}/
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
updateNamecheapDyndns = pkgs.writeShellApplication {
|
|
||||||
name = "update-namecheap-dyndns";
|
|
||||||
runtimeInputs = [
|
|
||||||
pkgs.coreutils
|
|
||||||
pkgs.ddclient
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
: "''${NAMECHEAP_DOMAIN:?Set NAMECHEAP_DOMAIN in /etc/blogbox-namecheap-ddns.env}"
|
|
||||||
: "''${NAMECHEAP_PASSWORD:?Set NAMECHEAP_PASSWORD in /etc/blogbox-namecheap-ddns.env}"
|
|
||||||
: "''${NAMECHEAP_HOSTS:?Set NAMECHEAP_HOSTS in /etc/blogbox-namecheap-ddns.env}"
|
|
||||||
|
|
||||||
config_file="''${RUNTIME_DIRECTORY}/ddclient.conf"
|
|
||||||
install -m 0600 /dev/null "$config_file"
|
|
||||||
|
|
||||||
{
|
|
||||||
printf 'daemon=0\n'
|
|
||||||
printf 'cache=/var/cache/blogbox-dyndns/ddclient.cache\n'
|
|
||||||
printf 'ssl=yes\n'
|
|
||||||
printf 'protocol=namecheap\n'
|
|
||||||
printf 'usev4=webv4, webv4=dynamicdns.park-your-domain.com/getip\n'
|
|
||||||
printf 'server=dynamicdns.park-your-domain.com\n'
|
|
||||||
printf 'login=%s\n' "$NAMECHEAP_DOMAIN"
|
|
||||||
printf 'password=%s\n' "$NAMECHEAP_PASSWORD"
|
|
||||||
printf '%s\n' "$NAMECHEAP_HOSTS"
|
|
||||||
} > "$config_file"
|
|
||||||
|
|
||||||
ddclient -file "$config_file"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
ensureBlogboxSwapfile = pkgs.writeShellApplication {
|
|
||||||
name = "ensure-blogbox-swapfile";
|
|
||||||
runtimeInputs = [
|
|
||||||
pkgs.coreutils
|
|
||||||
pkgs.gnugrep
|
|
||||||
pkgs.util-linux
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if swapon --show=NAME --noheadings | grep -Fxq /swapfile; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f /swapfile ] || [ "$(stat -c %s /swapfile)" -ne 8589934592 ]; then
|
|
||||||
rm -f /swapfile
|
|
||||||
install -m 0600 /dev/null /swapfile
|
|
||||||
fallocate -l 8G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=8192 status=none
|
|
||||||
chmod 0600 /swapfile
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkswap -f /swapfile
|
|
||||||
swapon /swapfile
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
"${modulesPath}/virtualisation/oci-image.nix"
|
|
||||||
../../modules/services/cloud-init.nix
|
|
||||||
../../modules/services/nginx.nix
|
|
||||||
../../modules/services/oci-authorized-keys.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
|
||||||
|
|
||||||
oci.efi = lib.mkForce false;
|
|
||||||
virtualisation.diskSize = lib.mkForce (16 * 1024);
|
|
||||||
|
|
||||||
networking = {
|
|
||||||
hostName = "blogbox";
|
|
||||||
networkmanager.enable = lib.mkForce false;
|
|
||||||
firewall.allowedTCPPorts = [
|
|
||||||
22
|
|
||||||
80
|
|
||||||
443
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
boot = {
|
|
||||||
initrd.availableKernelModules = [
|
|
||||||
"virtio_pci"
|
|
||||||
"virtio_blk"
|
|
||||||
"virtio_scsi"
|
|
||||||
"virtio_net"
|
|
||||||
"xhci_pci"
|
|
||||||
];
|
|
||||||
kernelParams = lib.mkForce [
|
|
||||||
"nvme.shutdown_timeout=10"
|
|
||||||
"nvme_core.shutdown_timeout=10"
|
|
||||||
"libiscsi.debug_libiscsi_eh=1"
|
|
||||||
"crash_kexec_post_notifiers"
|
|
||||||
"console=tty1"
|
|
||||||
"console=ttyS0,115200n8"
|
|
||||||
];
|
|
||||||
kernelPackages = lib.mkForce pkgs.linuxPackages;
|
|
||||||
loader.systemd-boot.configurationLimit = lib.mkForce 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
documentation = {
|
|
||||||
enable = lib.mkForce false;
|
|
||||||
man.enable = lib.mkForce false;
|
|
||||||
doc.enable = lib.mkForce false;
|
|
||||||
info.enable = lib.mkForce false;
|
|
||||||
nixos.enable = lib.mkForce false;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
defaultPackages = lib.mkForce [ ];
|
|
||||||
shells = lib.mkForce [ pkgs.bash ];
|
|
||||||
systemPackages = lib.mkForce (with pkgs; [
|
|
||||||
curl
|
|
||||||
git
|
|
||||||
hugo
|
|
||||||
vim
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
programs = {
|
|
||||||
command-not-found.enable = lib.mkForce false;
|
|
||||||
fish.enable = lib.mkForce false;
|
|
||||||
fzf.fuzzyCompletion = lib.mkForce false;
|
|
||||||
xonsh.enable = lib.mkForce false;
|
|
||||||
};
|
|
||||||
|
|
||||||
users = {
|
|
||||||
defaultUserShell = lib.mkForce pkgs.bash;
|
|
||||||
groups.blogbox-dyndns = { };
|
|
||||||
users.alisceon = {
|
|
||||||
createHome = true;
|
|
||||||
extraGroups = lib.mkForce [ "wheel" "systemd-journal" ];
|
|
||||||
openssh.authorizedKeys.keys = [
|
|
||||||
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPN1Cd2UlHo03Jqgi5Yb4io/3gh/X4wCb8LcmKlpAovQa271CKDBtYOUKn+Fts03g6dBMfaWMty6VGPMGDMONmc= alisceon@electra"
|
|
||||||
];
|
|
||||||
shell = lib.mkForce pkgs.bash;
|
|
||||||
};
|
|
||||||
users.blogbox-dyndns = {
|
|
||||||
group = "blogbox-dyndns";
|
|
||||||
isSystemUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
alisceon = {
|
|
||||||
cloud-init.enable = true;
|
|
||||||
ociAuthorizedKeys.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
nix = {
|
|
||||||
settings = {
|
|
||||||
cores = lib.mkForce 1;
|
|
||||||
max-jobs = lib.mkForce 1;
|
|
||||||
min-free = lib.mkForce (256 * 1024 * 1024);
|
|
||||||
max-free = lib.mkForce (1024 * 1024 * 1024);
|
|
||||||
};
|
|
||||||
gc = {
|
|
||||||
dates = lib.mkForce "daily";
|
|
||||||
options = lib.mkForce "--delete-older-than 3d";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
system.autoUpgrade = {
|
|
||||||
persistent = lib.mkForce false;
|
|
||||||
randomizedDelaySec = lib.mkForce "4h";
|
|
||||||
};
|
|
||||||
|
|
||||||
security = {
|
|
||||||
acme = {
|
|
||||||
acceptTerms = true;
|
|
||||||
defaults.email = "acme@alisceon.com";
|
|
||||||
};
|
|
||||||
sudo-rs.wheelNeedsPassword = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
openssh.settings = {
|
|
||||||
KbdInteractiveAuthentication = false;
|
|
||||||
PasswordAuthentication = false;
|
|
||||||
PermitRootLogin = lib.mkForce "prohibit-password";
|
|
||||||
};
|
|
||||||
|
|
||||||
journald.extraConfig = ''
|
|
||||||
SystemMaxUse=64M
|
|
||||||
RuntimeMaxUse=32M
|
|
||||||
'';
|
|
||||||
|
|
||||||
nginx.virtualHosts.${siteDomain} = {
|
|
||||||
serverName = siteDomain;
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
root = publicDir;
|
|
||||||
locations."/".extraConfig = ''
|
|
||||||
try_files $uri $uri/ =404;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd = {
|
|
||||||
tmpfiles.rules = [
|
|
||||||
"d ${repoDir} 0755 alisceon users - -"
|
|
||||||
"d ${stateDir} 0755 alisceon users - -"
|
|
||||||
"d ${publicDir} 0755 alisceon users - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
services.update-blogbox-site = {
|
|
||||||
description = "Pull and publish the Blogbox Hugo site";
|
|
||||||
after = [ "network-online.target" ];
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
User = "alisceon";
|
|
||||||
Group = "users";
|
|
||||||
ExecStart = lib.getExe updateBlogboxSite;
|
|
||||||
Nice = 10;
|
|
||||||
IOSchedulingClass = "idle";
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryHigh = "384M";
|
|
||||||
MemoryMax = "512M";
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
OOMPolicy = "stop";
|
|
||||||
PrivateDevices = true;
|
|
||||||
PrivateIPC = true;
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
ReadWritePaths = [
|
|
||||||
repoDir
|
|
||||||
stateDir
|
|
||||||
];
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_UNIX"
|
|
||||||
];
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
TimeoutStartSec = "15min";
|
|
||||||
UMask = "0022";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.blogbox-dyndns = {
|
|
||||||
description = "Update Namecheap dynamic DNS records for Blogbox";
|
|
||||||
after = [ "network-online.target" ];
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
unitConfig.ConditionPathExists = "/etc/blogbox-namecheap-ddns.env";
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
User = "blogbox-dyndns";
|
|
||||||
Group = "blogbox-dyndns";
|
|
||||||
ExecStart = lib.getExe updateNamecheapDyndns;
|
|
||||||
CacheDirectory = "blogbox-dyndns";
|
|
||||||
EnvironmentFile = "/etc/blogbox-namecheap-ddns.env";
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryMax = "128M";
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
OOMPolicy = "stop";
|
|
||||||
PrivateDevices = true;
|
|
||||||
PrivateIPC = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK"
|
|
||||||
];
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
RuntimeDirectory = "blogbox-dyndns";
|
|
||||||
RuntimeDirectoryMode = "0700";
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
SystemCallErrorNumber = "EPERM";
|
|
||||||
SystemCallFilter = "@system-service";
|
|
||||||
TimeoutStartSec = "2min";
|
|
||||||
UMask = "0177";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
timers.update-blogbox-site = {
|
|
||||||
wantedBy = [ "timers.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnBootSec = "10min";
|
|
||||||
OnUnitInactiveSec = "5min";
|
|
||||||
Persistent = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
timers.blogbox-dyndns = {
|
|
||||||
wantedBy = [ "timers.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnBootSec = "5min";
|
|
||||||
OnUnitInactiveSec = "10min";
|
|
||||||
Persistent = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.nixos-upgrade.serviceConfig = {
|
|
||||||
IOSchedulingClass = "idle";
|
|
||||||
MemoryHigh = "512M";
|
|
||||||
MemoryMax = "768M";
|
|
||||||
Nice = 15;
|
|
||||||
OOMPolicy = "stop";
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.growpart.serviceConfig = {
|
|
||||||
IOSchedulingClass = "idle";
|
|
||||||
Nice = 15;
|
|
||||||
TimeoutStartSec = "2min";
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.blogbox-swapfile = {
|
|
||||||
description = "Create and enable Blogbox swapfile";
|
|
||||||
after = [
|
|
||||||
"sshd.service"
|
|
||||||
"systemd-growfs-root.service"
|
|
||||||
];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
ExecStart = lib.getExe ensureBlogboxSwapfile;
|
|
||||||
IOSchedulingClass = "idle";
|
|
||||||
Nice = 19;
|
|
||||||
RemainAfterExit = true;
|
|
||||||
TimeoutStartSec = "20min";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
zramSwap = {
|
|
||||||
enable = true;
|
|
||||||
memoryPercent = 50;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtualisation = {
|
|
||||||
containers.enable = lib.mkForce false;
|
|
||||||
docker.enable = lib.mkForce false;
|
|
||||||
libvirtd = {
|
|
||||||
enable = lib.mkForce false;
|
|
||||||
qemu.swtpm.enable = lib.mkForce false;
|
|
||||||
};
|
|
||||||
podman.enable = lib.mkForce false;
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = lib.mkForce "25.11";
|
|
||||||
}
|
|
||||||
|
|
@ -24,8 +24,6 @@ in
|
||||||
|
|
||||||
security.sudo.wheelNeedsPassword = false;
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
|
||||||
alisceon.wireguardPeer.enable = true;
|
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
printing.enable = true;
|
printing.enable = true;
|
||||||
pulseaudio.enable = false;
|
pulseaudio.enable = false;
|
||||||
|
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
{ config, lib, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.alisceon.cloud-init;
|
|
||||||
defaultShell =
|
|
||||||
if cfg.defaultShell != null then
|
|
||||||
cfg.defaultShell
|
|
||||||
else
|
|
||||||
lib.getExe config.users.users.${cfg.user}.shell;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.alisceon.cloud-init = {
|
|
||||||
enable = lib.mkEnableOption "shared cloud-init defaults";
|
|
||||||
|
|
||||||
user = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "alisceon";
|
|
||||||
description = "Default cloud-init user to configure.";
|
|
||||||
};
|
|
||||||
|
|
||||||
gecos = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "Alisceon";
|
|
||||||
description = "GECOS field for the default cloud-init user.";
|
|
||||||
};
|
|
||||||
|
|
||||||
groups = lib.mkOption {
|
|
||||||
type = lib.types.listOf lib.types.str;
|
|
||||||
default = [
|
|
||||||
"wheel"
|
|
||||||
"systemd-journal"
|
|
||||||
];
|
|
||||||
description = "Groups assigned to the default cloud-init user.";
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultShell = lib.mkOption {
|
|
||||||
type = lib.types.nullOr lib.types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Shell path for the default cloud-init user.";
|
|
||||||
};
|
|
||||||
|
|
||||||
datasourceList = lib.mkOption {
|
|
||||||
type = lib.types.listOf lib.types.str;
|
|
||||||
default = [
|
|
||||||
"Oracle"
|
|
||||||
"ConfigDrive"
|
|
||||||
"NoCloud"
|
|
||||||
];
|
|
||||||
description = "cloud-init datasources to allow.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
networking.useNetworkd = lib.mkDefault true;
|
|
||||||
|
|
||||||
services.cloud-init = {
|
|
||||||
enable = true;
|
|
||||||
network.enable = true;
|
|
||||||
settings = {
|
|
||||||
datasource_list = cfg.datasourceList;
|
|
||||||
users = [ "default" ];
|
|
||||||
system_info.default_user = {
|
|
||||||
name = cfg.user;
|
|
||||||
gecos = cfg.gecos;
|
|
||||||
groups = cfg.groups;
|
|
||||||
shell = defaultShell;
|
|
||||||
lock_passwd = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.alisceon.forgejo;
|
|
||||||
forgejoDomain = cfg.domain;
|
|
||||||
|
|
||||||
generateForgejoRunnerToken = pkgs.writeShellApplication {
|
|
||||||
name = "generate-forgejo-runner-token";
|
|
||||||
runtimeInputs = [
|
|
||||||
pkgs.coreutils
|
|
||||||
pkgs.util-linux
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
token_file=${lib.escapeShellArg "/var/lib/forgejo/runner_token"}
|
|
||||||
|
|
||||||
if [ -s "$token_file" ]; then
|
|
||||||
chmod 0600 "$token_file"
|
|
||||||
chown root:root "$token_file"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
install -d -m 0750 -o forgejo -g forgejo /var/lib/forgejo
|
|
||||||
token="$(runuser -u forgejo -- env \
|
|
||||||
FORGEJO_WORK_DIR=/var/lib/forgejo \
|
|
||||||
FORGEJO_CUSTOM=/var/lib/forgejo/custom \
|
|
||||||
${lib.getExe pkgs.forgejo-lts} actions generate-runner-token)"
|
|
||||||
|
|
||||||
umask 0077
|
|
||||||
printf 'TOKEN=%s\n' "$token" > "$token_file"
|
|
||||||
chown root:root "$token_file"
|
|
||||||
chmod 0600 "$token_file"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.alisceon.forgejo.domain = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = "Public domain name for Forgejo.";
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
services.forgejo = {
|
|
||||||
enable = true;
|
|
||||||
package = pkgs.forgejo-lts;
|
|
||||||
database.type = "sqlite3";
|
|
||||||
lfs.enable = true;
|
|
||||||
settings = {
|
|
||||||
server = {
|
|
||||||
DOMAIN = forgejoDomain;
|
|
||||||
ROOT_URL = "https://${forgejoDomain}/";
|
|
||||||
HTTP_ADDR = "127.0.0.1";
|
|
||||||
HTTP_PORT = 3000;
|
|
||||||
SSH_DOMAIN = forgejoDomain;
|
|
||||||
SSH_PORT = 22;
|
|
||||||
DISABLE_SSH = false;
|
|
||||||
};
|
|
||||||
session.COOKIE_SECURE = true;
|
|
||||||
service = {
|
|
||||||
DISABLE_REGISTRATION = true;
|
|
||||||
REQUIRE_SIGNIN_VIEW = false;
|
|
||||||
};
|
|
||||||
actions.ENABLED = true;
|
|
||||||
repository = {
|
|
||||||
DEFAULT_PRIVATE = "private";
|
|
||||||
DISABLE_HTTP_GIT = false;
|
|
||||||
};
|
|
||||||
"cron.archive_cleanup" = {
|
|
||||||
ENABLED = true;
|
|
||||||
RUN_AT_START = true;
|
|
||||||
SCHEDULE = "@every 24h";
|
|
||||||
OLDER_THAN = "72h";
|
|
||||||
};
|
|
||||||
log.LEVEL = "Warn";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.gitea-actions-runner = {
|
|
||||||
package = pkgs.forgejo-runner;
|
|
||||||
instances.alisceon-core-podman = {
|
|
||||||
enable = true;
|
|
||||||
name = "alisceon-core-podman";
|
|
||||||
url = "https://${forgejoDomain}";
|
|
||||||
tokenFile = "/var/lib/forgejo/runner_token";
|
|
||||||
labels = lib.mkDefault [
|
|
||||||
"podman"
|
|
||||||
];
|
|
||||||
settings = {
|
|
||||||
container = {
|
|
||||||
network = "host";
|
|
||||||
privileged = false;
|
|
||||||
valid_volumes = [ ];
|
|
||||||
};
|
|
||||||
cache.enabled = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.forgejo-runner-token = {
|
|
||||||
description = "Generate Forgejo runner registration token";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "forgejo.service" ];
|
|
||||||
requires = [ "forgejo.service" ];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
StandardError = "journal+console";
|
|
||||||
StandardOutput = "journal+console";
|
|
||||||
};
|
|
||||||
script = lib.getExe generateForgejoRunnerToken;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services."gitea-runner-alisceon\\x2dcore\\x2dpodman" = {
|
|
||||||
after = [ "forgejo-runner-token.service" ];
|
|
||||||
requires = [ "forgejo-runner-token.service" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.forgejo-lts ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
services.nginx = {
|
|
||||||
enable = true;
|
|
||||||
recommendedGzipSettings = true;
|
|
||||||
recommendedOptimisation = true;
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
recommendedTlsSettings = true;
|
|
||||||
virtualHosts."_" = {
|
|
||||||
default = true;
|
|
||||||
rejectSSL = true;
|
|
||||||
extraConfig = ''
|
|
||||||
return 421;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.alisceon.ociAuthorizedKeys;
|
|
||||||
home = config.users.users.${cfg.user}.home;
|
|
||||||
sshDir = "${home}/.ssh";
|
|
||||||
authorizedKeysFile = "${sshDir}/authorized_keys";
|
|
||||||
staticAuthorizedKeys = config.users.users.${cfg.user}.openssh.authorizedKeys.keys or [ ];
|
|
||||||
staticAuthorizedKeysText =
|
|
||||||
(lib.concatStringsSep "\n" staticAuthorizedKeys)
|
|
||||||
+ lib.optionalString (staticAuthorizedKeys != [ ]) "\n";
|
|
||||||
staticAuthorizedKeysFile = pkgs.writeText "static-authorized-keys-${cfg.user}" staticAuthorizedKeysText;
|
|
||||||
|
|
||||||
fetchOciAuthorizedKeys = pkgs.writeShellApplication {
|
|
||||||
name = "fetch-oci-authorized-keys";
|
|
||||||
runtimeInputs = [
|
|
||||||
pkgs.coreutils
|
|
||||||
pkgs.curl
|
|
||||||
pkgs.gnugrep
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
install -d -m 0700 -o ${lib.escapeShellArg cfg.user} -g ${lib.escapeShellArg cfg.group} ${lib.escapeShellArg sshDir}
|
|
||||||
|
|
||||||
if [ ! -e ${lib.escapeShellArg authorizedKeysFile} ]; then
|
|
||||||
install -m 0600 -o ${lib.escapeShellArg cfg.user} -g ${lib.escapeShellArg cfg.group} /dev/null ${lib.escapeShellArg authorizedKeysFile}
|
|
||||||
fi
|
|
||||||
|
|
||||||
chown ${lib.escapeShellArg "${cfg.user}:${cfg.group}"} ${lib.escapeShellArg authorizedKeysFile}
|
|
||||||
chmod 0600 ${lib.escapeShellArg authorizedKeysFile}
|
|
||||||
|
|
||||||
append_keys() {
|
|
||||||
while IFS= read -r key; do
|
|
||||||
[ -n "$key" ] || continue
|
|
||||||
grep -qxF -- "$key" ${lib.escapeShellArg authorizedKeysFile} || printf '%s\n' "$key" >> ${lib.escapeShellArg authorizedKeysFile}
|
|
||||||
done < "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
append_keys ${lib.escapeShellArg staticAuthorizedKeysFile}
|
|
||||||
|
|
||||||
metadata_keys="$(mktemp)"
|
|
||||||
trap 'rm -f "$metadata_keys"' EXIT
|
|
||||||
|
|
||||||
curl --fail --silent --show-error --location \
|
|
||||||
--connect-timeout 3 \
|
|
||||||
--max-time 10 \
|
|
||||||
--retry 3 \
|
|
||||||
--retry-delay 2 \
|
|
||||||
--header ${lib.escapeShellArg "Authorization: Bearer Oracle"} \
|
|
||||||
--output "$metadata_keys" \
|
|
||||||
${lib.escapeShellArg cfg.metadataUrl} || {
|
|
||||||
echo "Unable to fetch OCI authorized_keys for ${cfg.user}; leaving existing keys unchanged"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
append_keys "$metadata_keys"
|
|
||||||
|
|
||||||
chown ${lib.escapeShellArg "${cfg.user}:${cfg.group}"} ${lib.escapeShellArg authorizedKeysFile}
|
|
||||||
chmod 0600 ${lib.escapeShellArg authorizedKeysFile}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.alisceon.ociAuthorizedKeys = {
|
|
||||||
enable = lib.mkEnableOption "fetching SSH authorized_keys from OCI metadata";
|
|
||||||
|
|
||||||
user = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "alisceon";
|
|
||||||
description = "User whose authorized_keys file should be populated.";
|
|
||||||
};
|
|
||||||
|
|
||||||
group = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "users";
|
|
||||||
description = "Group owner for the user's SSH files.";
|
|
||||||
};
|
|
||||||
|
|
||||||
metadataUrl = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "http://169.254.169.254/opc/v2/instance/metadata/ssh_authorized_keys";
|
|
||||||
description = "OCI metadata endpoint containing SSH authorized keys.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
systemd.services.fetch-oci-authorized-keys = {
|
|
||||||
description = "Fetch OCI metadata authorized_keys for ${cfg.user}";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network-online.target" ];
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
StandardError = "journal+console";
|
|
||||||
StandardOutput = "journal+console";
|
|
||||||
TimeoutStartSec = "30s";
|
|
||||||
};
|
|
||||||
script = lib.getExe fetchOciAuthorizedKeys;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.fetch-ssh-keys.enable = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
services.tor = {
|
|
||||||
enable = true;
|
|
||||||
client.enable = false;
|
|
||||||
relay = {
|
|
||||||
enable = true;
|
|
||||||
role = "relay";
|
|
||||||
};
|
|
||||||
settings = {
|
|
||||||
Nickname = "alisceondotcom";
|
|
||||||
ORPort = 24601;
|
|
||||||
DataDirectory = "/var/lib/tor";
|
|
||||||
ExitRelay = false;
|
|
||||||
ExitPolicy = [ "reject *:*" ];
|
|
||||||
RelayBandwidthRate = "25 MBytes";
|
|
||||||
RelayBandwidthBurst = "25 MBytes";
|
|
||||||
BandwidthRate = "25 MBytes";
|
|
||||||
BandwidthBurst = "25 MBytes";
|
|
||||||
AccountingStart = "month 1 00:00";
|
|
||||||
AccountingMax = "8500 GBytes";
|
|
||||||
DirCache = true;
|
|
||||||
AvoidDiskWrites = 1;
|
|
||||||
Sandbox = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
{ config, lib, pkgs, repoLocalPath, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.alisceon.wireguardPeer;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.alisceon.wireguardPeer = {
|
|
||||||
enable = lib.mkEnableOption "a single WireGuard peer managed by wg-quick";
|
|
||||||
|
|
||||||
interface = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "wg0";
|
|
||||||
description = "WireGuard interface name.";
|
|
||||||
};
|
|
||||||
|
|
||||||
configFile = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "/etc/wireguard/${cfg.interface}.conf";
|
|
||||||
defaultText = "/etc/wireguard/<interface>.conf";
|
|
||||||
description = ''
|
|
||||||
Path to an external wg-quick config file. Keep it root-owned and mode
|
|
||||||
0600 so private keys and peer material stay outside Git and the Nix store.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
autostart = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
default = true;
|
|
||||||
description = "Whether to bring the WireGuard interface up at boot.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = lib.hasPrefix "/" cfg.configFile;
|
|
||||||
message = "alisceon.wireguardPeer.configFile must be an absolute path outside the repo.";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = !(lib.hasPrefix repoLocalPath cfg.configFile);
|
|
||||||
message = "alisceon.wireguardPeer.configFile must be outside ${repoLocalPath}.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.wg-quick.interfaces.${cfg.interface} = {
|
|
||||||
inherit (cfg) autostart configFile;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services."wg-quick-${cfg.interface}".unitConfig.ConditionPathExists = cfg.configFile;
|
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.wireguard-tools ];
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d /etc/wireguard 0700 root root -"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
import sys
|
|
||||||
|
|
||||||
isup = "does not exist." not in $(ip link show dev wg0 2>&1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
match sys.argv[1]:
|
|
||||||
case "toggle":
|
|
||||||
if isup:
|
|
||||||
footclient wg-quick down wg0
|
|
||||||
else:
|
|
||||||
footclient wg-quick up wg0
|
|
||||||
case "status":
|
|
||||||
if isup:
|
|
||||||
print("u")
|
|
||||||
else:
|
|
||||||
print("d")
|
|
||||||
case _:
|
|
||||||
raise RuntimeError
|
|
||||||
|
|
||||||
except (RuntimeError, IndexError):
|
|
||||||
print('"toggle" or "status" must be provided')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue