feat: inital public commit

This commit is contained in:
2025-08-15 19:54:31 -04:00
commit 00315a990a
55 changed files with 2527 additions and 0 deletions

62
host/ark/default.nix Normal file
View File

@@ -0,0 +1,62 @@
{ config, lib, pkgs, ... }: {
imports = [
./hardware-configuration.nix
./options.nix
../common/core/default.nix
./user.nix
./sops.nix
./service/audio.nix
./service/auth.nix
./service/docs.nix
./service/git.nix
./service/home.nix
./service/photos.nix
./service/radicale.nix
./service/wakapi.nix
];
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
networking.hostName = "ark"; # Define your hostname.
oauth.name = "KoonFamily";
oauth.secrets = import ./oauth-secrets.nix;
security.sudo.wheelNeedsPassword = false;
services.cloudflared = {
enable = true;
tunnels = {
"91d31395-fbc7-45a1-ae13-148957b32ecd" = {
credentialsFile = config.sops.secrets.tunnel-credentials.path;
ingress = {
"auth.koon.us" = "http://localhost:1411";
"photos.koon.us" = "http://localhost:2283";
"home.koon.us" = "http://localhost:8123";
"docs.koon.us" = "http://localhost:3004";
"git.koon.us" = "http://localhost:3000";
"ssh.koon.us" = "ssh://localhost:2222";
"audio.koon.us" = "http://localhost:8021";
"radicale.koon.us" = "http://localhost:5232";
"waka.koon.us" = "http://localhost:3006";
};
default = "http_status:404";
};
};
};
fileSystems."/mnt/hdd" = {
device = "/dev/sdb";
fsType = "ext4";
};
services.openssh.enable = true;
networking.firewall.allowedTCPPorts = [ 8123 22 ];
system.stateVersion = "25.05"; # Did you read the comment?
}

View File

@@ -0,0 +1,39 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot.initrd.availableKernelModules =
[ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/56034a80-72ea-4e67-be41-2e8cb642fb44";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/DE8B-01DE";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.eno1.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp1s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode =
lib.mkDefault config.hardware.enableRedistributableFirmware;
}

7
host/ark/options.nix Normal file
View File

@@ -0,0 +1,7 @@
{ lib, ... }: {
options.oauth = {
name = lib.mkOption { type = lib.types.str; };
secrets = lib.mkOption { type = lib.types.attrs; };
};
}

View File

@@ -0,0 +1,6 @@
{ ... }: {
services.audiobookshelf = {
enable = true;
port = 8021;
};
}

14
host/ark/service/auth.nix Normal file
View File

@@ -0,0 +1,14 @@
{ config, pkgs, ... }: {
services.pocket-id = {
enable = true;
settings = {
APP_URL = "https://auth.koon.us";
TRUST_PROXY = true;
ANALYTICS_DISABLED = true;
UI_CONFIG_DISABLED = true;
APP_NAME = config.oauth.name;
};
};
}

94
host/ark/service/docs.nix Normal file
View File

@@ -0,0 +1,94 @@
{ config, lib, pkgs, ... }: {
nixpkgs.config.allowUnfree = true;
services.outline = {
enable = true;
publicUrl = "https://docs.koon.us";
port = 3004;
forceHttps = true;
storage.storageType = "local";
logo = "https://i.imgur.com/fKJ1I63.png";
oidcAuthentication = {
authUrl = "https://auth.koon.us/authorize";
tokenUrl = "https://auth.koon.us/api/oidc/token";
userinfoUrl = "https://auth.koon.us/api/oidc/userinfo";
clientId = "";
clientSecretFile = config.sops.secrets."docs/clientSecret".path;
scopes = [ "openid" "email" "profile" ];
usernameClaim = "preferred_username";
displayName = config.oauth.name;
};
};
systemd.services.outline = {
script =
let
localPostgresqlUrl = "postgres://localhost/outline?host=/run/postgresql";
cfg = config.services.outline;
in lib.mkForce ''
export SECRET_KEY="$(head -n1 ${lib.escapeShellArg cfg.secretKeyFile})"
export UTILS_SECRET="$(head -n1 ${lib.escapeShellArg cfg.utilsSecretFile})"
${lib.optionalString (cfg.storage.storageType == "s3") ''
export AWS_SECRET_ACCESS_KEY="$(head -n1 ${lib.escapeShellArg cfg.storage.secretKeyFile})"
''}
${lib.optionalString (cfg.slackAuthentication != null) ''
export SLACK_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.slackAuthentication.secretFile})"
''}
${lib.optionalString (cfg.googleAuthentication != null) ''
export GOOGLE_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.googleAuthentication.clientSecretFile})"
''}
${lib.optionalString (cfg.azureAuthentication != null) ''
export AZURE_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.azureAuthentication.clientSecretFile})"
''}
${lib.optionalString (cfg.oidcAuthentication != null) ''
export OIDC_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.oidcAuthentication.clientSecretFile})"
export OIDC_CLIENT_ID="$(cat ${config.sops.secrets."docs/clientId".path})"
''}
${lib.optionalString (cfg.sslKeyFile != null) ''
export SSL_KEY="$(head -n1 ${lib.escapeShellArg cfg.sslKeyFile})"
''}
${lib.optionalString (cfg.sslCertFile != null) ''
export SSL_CERT="$(head -n1 ${lib.escapeShellArg cfg.sslCertFile})"
''}
${lib.optionalString (cfg.slackIntegration != null) ''
export SLACK_VERIFICATION_TOKEN="$(head -n1 ${lib.escapeShellArg cfg.slackIntegration.verificationTokenFile})"
''}
${lib.optionalString (cfg.smtp != null) ''
export SMTP_PASSWORD="$(head -n1 ${lib.escapeShellArg cfg.smtp.passwordFile})"
''}
${
if (cfg.databaseUrl == "local") then
''
export DATABASE_URL=${lib.escapeShellArg localPostgresqlUrl}
export PGSSLMODE=disable
''
else
''
export DATABASE_URL=${lib.escapeShellArg cfg.databaseUrl}
''
}
${cfg.package}/bin/outline-server
'';
};
# systemd.services.outline = {
# serviceConfig = {
# # Load the client ID from the sops secret file
# ExecStartPre = let
# script = pkgs.writeShellScript "outline-set-oauth" ''
# CLIENT_ID=$(cat ${config.sops.secrets."docs/clientId".path})
# # Export as environment variable that Outline will use
# echo "OIDC_CLIENT_ID=$CLIENT_ID" >> $RUNTIME_DIRECTORY/env
# '';
# in "+${script}";
#
# # Load the environment file
# EnvironmentFile = "-/run/outline/env";
# };
#
# # Ensure sops secrets are available before starting
# after = [ "sops-nix.service" ];
# wants = [ "sops-nix.service" ];
# };
}

111
host/ark/service/git.nix Normal file
View File

@@ -0,0 +1,111 @@
{ lib, config, pkgs, ... }: {
services.gitea = {
enable = true;
user = "git";
group = "git";
database = {
user = "git";
name = "git";
type = "postgres";
};
settings = {
server = {
DOMAIN = "git.koon.us";
ROOT_URL = "https://git.koon.us";
HTTP_PORT = 3000;
LANDING_PAGE = "/max";
SSH_DOMAIN = "ssh.koon.us";
SSH_PORT = 2222;
START_SSH_SERVER = true;
};
oauth2_client = {
ACCOUNT_LINKING = "auto";
ENABLE_AUTO_REGISTRATION = true;
UPDATE_AVATAR = true;
USERNAME = "email";
};
service = {
DISABLE_REGISTRATION = true;
ENABLE_PASSWORD_SIGNIN_FORM = false;
ENABLE_PASSKEY_AUTHENTICATION = false;
SHOW_MILESTONES_DASHBOARD_PAGE = false;
};
"service.explore" = {
DISABLE_USERS_PAGE = true;
DISABLE_ORGANIZATIONS_PAGE = true;
DISABLE_CODE_PAGE = true;
};
};
};
users.users.git = {
isSystemUser = true;
group = "git";
home = "/var/lib/gitea";
description = "Git server (Gitea)";
createHome = true;
};
users.groups.git = { };
systemd.services.gitea = {
serviceConfig = {
RestartSec = "60"; # Retry every minute
};
preStart = let
exe = lib.getExe config.services.gitea.package;
clientIdPath = config.sops.secrets."git/clientId".path;
clientSecretPath = config.sops.secrets."git/clientSecret".path;
args = lib.escapeShellArgs (lib.concatLists [
[ "--name" config.oauth.name ]
[ "--provider" "openidConnect" ]
# [ "--key" config.oauth.secrets.git.clientId ]
[
"--auto-discover-url"
"https://auth.koon.us/.well-known/openid-configuration"
]
[ "--scopes" "email" ]
[ "--scopes" "profile" ]
[ "--group-claim-name" "groups" ]
[ "--admin-group" "admin" ]
[ "--skip-local-2fa" ]
]);
in lib.mkAfter ''
CLIENT_ID=$(cat ${clientIdPath})
CLIENT_SECRET=$(cat ${clientSecretPath})
provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${config.oauth.name}' | cut -f1)
if [[ -z "$provider_id" ]]; then
${exe} admin auth add-oauth ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
else
${exe} admin auth update-oauth --id "$provider_id" ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
fi
mkdir -p /var/lib/gitea/custom/public/assets/img/
ln -sf ${
./git/assets/img/logo.svg
} /var/lib/gitea/custom/public/assets/img/logo.svg
ln -sf ${
./git/assets/img/favicon.svg
} /var/lib/gitea/custom/public/assets/img/favicon.svg
mkdir -p /var/lib/gitea/custom/templates/base/
ln -sf ${
./git/templates/base/head_navbar.tmpl
} /var/lib/gitea/custom/templates/base/head_navbar.tmpl
ln -sf ${
./git/templates/base/footer_content.tmpl
} /var/lib/gitea/custom/templates/base/footer_content.tmpl
mkdir -p /var/lib/gitea/custom/templates/custom/
ln -sf ${
./git/templates/custom/header.tmpl
} /var/lib/gitea/custom/templates/custom/header.tmpl
'';
};
}

View File

@@ -0,0 +1,15 @@
/* custom.css */
:root {
--color-primary: #2e7d32;
--color-primary-dark: #1b5e20;
}
/* Hide "Powered by Gitea" */
.footer .ui.container .ui.left {
display: none;
}
/* Custom header background */
.ui.top.menu {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

View File

@@ -0,0 +1,6 @@
<svg width="321" height="524" viewBox="0 0 321 524" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M321 249C267.137 251.03 192 393.5 192 524L192 249L321 249Z" fill="black"/>
<path d="M0 190C54.6982 188.598 131 85 131 0V190H0Z" fill="black"/>
<path d="M70 249H131V310H70V249Z" fill="black"/>
<path d="M192 129H253V190H192V129Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 359 B

View File

@@ -0,0 +1,6 @@
<svg width="321" height="524" viewBox="0 0 321 524" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M321 249C267.137 251.03 192 393.5 192 524L192 249L321 249Z" fill="black"/>
<path d="M0 190C54.6982 188.598 131 85 131 0V190H0Z" fill="black"/>
<path d="M70 249H131V310H70V249Z" fill="black"/>
<path d="M192 129H253V190H192V129Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 359 B

View File

@@ -0,0 +1,3 @@
<footer class="page-footer" role="group" aria-label="{{ctx.Locale.Tr "aria.footer"}}">
© MMXXV Koon Family
</footer>

View File

@@ -0,0 +1,190 @@
{{$notificationUnreadCount := 0}}
{{if and .IsSigned .NotificationUnreadCount}}
{{$notificationUnreadCount = call .NotificationUnreadCount ctx}}
{{end}}
{{$activeStopwatch := NIL}}
{{if and .IsSigned EnableTimetracking .GetActiveStopwatch}}
{{$activeStopwatch = call .GetActiveStopwatch ctx}}
{{end}}
<nav id="navbar" aria-label="{{ctx.Locale.Tr "aria.navbar"}}">
<div class="navbar-left">
<!-- the logo -->
<a class="item" id="navbar-logo" href="{{AppSubUrl}}/" aria-label="{{if .IsSigned}}{{ctx.Locale.Tr "dashboard"}}{{else}}{{ctx.Locale.Tr "home"}}{{end}}">
<img width="30" height="30" src="{{AssetUrlPrefix}}/img/logo.svg" alt="{{ctx.Locale.Tr "logo"}}" aria-hidden="true">
</a>
<!-- mobile right menu, it must be here because in mobile view, each item is a flex column, the first item is a full row column -->
<div class="ui secondary menu navbar-mobile-right only-mobile">
{{if $activeStopwatch}}
<a id="mobile-stopwatch-icon" class="active-stopwatch item" href="{{$activeStopwatch.IssueLink}}" title="{{ctx.Locale.Tr "active_stopwatch"}}" data-seconds="{{$activeStopwatch.Seconds}}">
<div class="tw-relative">
{{svg "octicon-stopwatch"}}
<span class="header-stopwatch-dot"></span>
</div>
</a>
{{end}}
{{if .IsSigned}}
<a id="mobile-notifications-icon" class="item" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{ctx.Locale.Tr "notifications"}}" aria-label="{{ctx.Locale.Tr "notifications"}}">
<div class="tw-relative">
{{svg "octicon-bell"}}
<span class="notification_count{{if not $notificationUnreadCount}} tw-hidden{{end}}">{{$notificationUnreadCount}}</span>
</div>
</a>
{{end}}
<button class="item ui icon mini button tw-m-0" id="navbar-expand-toggle" aria-label="{{ctx.Locale.Tr "home.nav_menu"}}">{{svg "octicon-three-bars"}}</button>
</div>
</div>
<!-- the full dropdown menus -->
<div class="navbar-right">
{{if and .IsSigned .MustChangePassword}}
<div class="ui dropdown jump item" data-tooltip-content="{{ctx.Locale.Tr "user_profile_and_more"}}">
<span>
{{ctx.AvatarUtils.Avatar .SignedUser 24 "tw-mr-1"}}
<span class="only-mobile">{{.SignedUser.Name}}</span>
<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
</span>
<div class="menu user-menu">
<div class="header">
{{ctx.Locale.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong>
</div>
<div class="divider"></div>
<a class="item link-action" href data-url="{{AppSubUrl}}/user/logout">
{{svg "octicon-sign-out"}}
{{ctx.Locale.Tr "sign_out"}}
</a>
</div><!-- end content avatar menu -->
</div><!-- end dropdown avatar menu -->
{{else if .IsSigned}}
{{if $activeStopwatch}}
<a class="item not-mobile active-stopwatch" href="{{$activeStopwatch.IssueLink}}" title="{{ctx.Locale.Tr "active_stopwatch"}}" data-seconds="{{$activeStopwatch.Seconds}}">
<div class="tw-relative">
{{svg "octicon-stopwatch"}}
<span class="header-stopwatch-dot"></span>
</div>
</a>
{{end}}
<a class="item not-mobile" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{ctx.Locale.Tr "notifications"}}" aria-label="{{ctx.Locale.Tr "notifications"}}">
<div class="tw-relative">
{{svg "octicon-bell"}}
<span class="notification_count{{if not $notificationUnreadCount}} tw-hidden{{end}}">{{$notificationUnreadCount}}</span>
</div>
</a>
<div class="ui dropdown jump item" data-tooltip-content="{{ctx.Locale.Tr "create_new"}}">
<span class="text">
{{svg "octicon-plus"}}
<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
<span class="only-mobile">{{ctx.Locale.Tr "create_new"}}</span>
</span>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/repo/create">
{{svg "octicon-plus"}} {{ctx.Locale.Tr "new_repo"}}
</a>
{{if not .DisableMigrations}}
<a class="item" href="{{AppSubUrl}}/repo/migrate">
{{svg "octicon-repo-push"}} {{ctx.Locale.Tr "new_migrate"}}
</a>
{{end}}
{{if .SignedUser.CanCreateOrganization}}
<a class="item" href="{{AppSubUrl}}/org/create">
{{svg "octicon-organization"}} {{ctx.Locale.Tr "new_org"}}
</a>
{{end}}
</div><!-- end content create new menu -->
</div><!-- end dropdown menu create new -->
<div class="ui dropdown jump item" data-tooltip-content="{{ctx.Locale.Tr "user_profile_and_more"}}">
<span>
{{ctx.AvatarUtils.Avatar .SignedUser 24 "tw-mr-1"}}
<span class="only-mobile">{{.SignedUser.Name}}</span>
<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
</span>
<div class="menu user-menu">
<div class="header">
{{ctx.Locale.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong>
</div>
<div class="divider"></div>
<a class="item" href="{{.SignedUser.HomeLink}}">
{{svg "octicon-person"}}
{{ctx.Locale.Tr "your_profile"}}
</a>
{{if not .DisableStars}}
<a class="item" href="{{.SignedUser.HomeLink}}?tab=stars">
{{svg "octicon-star"}}
{{ctx.Locale.Tr "your_starred"}}
</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/notifications/subscriptions">
{{svg "octicon-bell"}}
{{ctx.Locale.Tr "notification.subscriptions"}}
</a>
<a class="{{if .PageIsUserSettings}}active {{end}}item" href="{{AppSubUrl}}/user/settings">
{{svg "octicon-tools"}}
{{ctx.Locale.Tr "your_settings"}}
</a>
<a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.com">
{{svg "octicon-question"}}
{{ctx.Locale.Tr "help"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>
<a class="{{if .PageIsAdmin}}active {{end}}item" href="{{AppSubUrl}}/-/admin">
{{svg "octicon-server"}}
{{ctx.Locale.Tr "admin_panel"}}
</a>
{{end}}
<div class="divider"></div>
<a class="item link-action" href data-url="{{AppSubUrl}}/user/logout">
{{svg "octicon-sign-out"}}
{{ctx.Locale.Tr "sign_out"}}
</a>
</div><!-- end content avatar menu -->
</div><!-- end dropdown avatar menu -->
{{else}}
{{if .ShowRegistrationButton}}
<a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up">
{{svg "octicon-person"}}
<span class="tw-ml-1">{{ctx.Locale.Tr "register"}}</span>
</a>
{{end}}
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/oauth2/KoonFamily{{if not .PageIsSignIn}}?redirect_to={{.CurrentURL}}{{end}}">
{{svg "octicon-sign-in"}}
<span class="tw-ml-1">{{ctx.Locale.Tr "sign_in"}}</span>
</a>
{{end}}
</div><!-- end full right menu -->
{{if $activeStopwatch}}
<div class="active-stopwatch-popup tippy-target">
<div class="tw-flex tw-items-center tw-gap-2 tw-p-3">
<a class="stopwatch-link tw-flex tw-items-center tw-gap-2 muted" href="{{$activeStopwatch.IssueLink}}">
{{svg "octicon-issue-opened" 16}}
<span class="stopwatch-issue">{{$activeStopwatch.RepoSlug}}#{{$activeStopwatch.IssueIndex}}</span>
</a>
<div class="tw-flex tw-gap-1">
<form class="stopwatch-commit form-fetch-action" method="post" action="{{$activeStopwatch.IssueLink}}/times/stopwatch/toggle">
{{.CsrfTokenHtml}}
<button
type="submit"
class="ui button mini compact basic icon tw-mr-0"
data-tooltip-content="{{ctx.Locale.Tr "repo.issues.stop_tracking"}}"
>{{svg "octicon-square-fill"}}</button>
</form>
<form class="stopwatch-cancel form-fetch-action" method="post" action="{{$activeStopwatch.IssueLink}}/times/stopwatch/cancel">
{{.CsrfTokenHtml}}
<button
type="submit"
class="ui button mini compact basic icon tw-mr-0"
data-tooltip-content="{{ctx.Locale.Tr "repo.issues.cancel_tracking"}}"
>{{svg "octicon-trash"}}</button>
</form>
</div>
</div>
</div>
{{end}}
</nav>

View File

@@ -0,0 +1,10 @@
<style>
:root {
--color-primary: #a68746;
--color-primary-dark: #a68746;
}
img.ui.avatar {
border-radius: 100%;
}
</style>

28
host/ark/service/home.nix Normal file
View File

@@ -0,0 +1,28 @@
{ pkgs, ... }: {
virtualisation.oci-containers = let
hass_config = pkgs.writeText "configuration.yaml" ''
# Discovery
default_config:
# Web Server configuration
http:
server_host: 127.0.0.1
use_x_forwarded_for: true
trusted_proxies: 127.0.0.1
'';
in {
backend = "podman";
containers.homeassistant = {
volumes = [
"home-assistant:/config"
# "/data/docker/hass:/config"
"${hass_config}:/config/configuration.yaml"
# "/run/secrets/home-assistant:/config/secrets.yaml"
];
environment.TZ = "America/New_York";
image =
"ghcr.io/home-assistant/home-assistant:stable"; # Warning: if the tag does not change, the image will not be updated
extraOptions = [ "--network=host" ];
};
};
}

117
host/ark/service/photos.nix Normal file
View File

@@ -0,0 +1,117 @@
{ lib, config, pkgs, ... }: {
sops = {
templates = {
"immich-config.json" = {
content = builtins.toJSON {
passwordLogin.enabled = false;
# We will do this ourselves
backup.database.enabled = false;
oauth = {
enabled = true;
autoLaunch = true;
autoRegister = true;
buttonText =
lib.strings.concatStrings [ "Login To " config.oauth.name ];
clientId = config.sops.placeholder."photos/clientId";
clientSecret = config.sops.placeholder."photos/clientSecret";
issuerUrl = "https://auth.koon.us/.well-known/openid-configuration";
};
};
owner = config.users.users.immich.name;
mode = "0400";
restartUnits = [ "immich-server.service" "pocket-id.service" ];
};
};
};
services.immich = {
enable = true;
port = 2283;
environment.IMMICH_CONFIG_FILE = config.sops.templates."immich-config.json".path;
accelerationDevices = null;
machine-learning.environment = {
HF_XET_CACHE = "/var/cache/immich/huggingface-xet";
};
};
users.users.immich = {
home = "/var/lib/immich";
createHome = true;
extraGroups = [ "video" "render" ];
};
hardware.graphics = {
enable = true;
extraPackages = with pkgs; [ intel-media-driver ];
};
environment.sessionVariables = { LIBVA_DRIVER_NAME = "iHD"; };
services.restic.backups = {
immich-local = {
repository = "/mnt/hdd/restic/immich";
passwordFile = config.sops.secrets.restic-password.path;
initialize = true;
paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
backupPrepareCommand = ''
mkdir -p /var/backup/immich
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
--clean \
--if-exists \
--dbname=immich > /var/backup/immich/postgres.sql
'';
backupCleanupCommand = ''
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
'';
};
immich-remote = {
repository = "rest:http://m1:8000/immich";
passwordFile = config.sops.secrets.restic-password.path;
initialize = true;
paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
backupPrepareCommand = ''
mkdir -p /var/backup/immich
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
--clean \
--if-exists \
--dbname=immich > /var/backup/immich/postgres.sql
'';
backupCleanupCommand = ''
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
'';
};
};
environment.systemPackages = with pkgs;
let
scripts = with pkgs; {
restore_immich_pg = writeShellScriptBin "restore_immich_pg" ''
${pkgs.sudo}/bin/sudo -u postgres psql --dbname=immich < /var/backup/immich/postgres.sql
'';
restore_immich = writeShellScriptBin "restore_immich" ''
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
${pkgs.sudo}/bin/sudo ${restic}/bin/restic -r /mnt/hdd/restic/immich restore latest --target /
${scripts.restore_immich_pg}/bin/restore_immich_pg
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
'';
};
in [ scripts.restore_immich_pg scripts.restore_immich ];
}

View File

@@ -0,0 +1,9 @@
{ ... }: {
services.radicale = {
enable = true;
settings = {
auth.type = "none";
server.hosts = [ "0.0.0.0:5232" ];
};
};
}

View File

@@ -0,0 +1,28 @@
{ config, ... }:
{
nixpkgs.overlays = [
(final: prev: {
wakapi = prev.wakapi.overrideAttrs (oldAttrs: rec {
src = final.fetchFromGitHub {
owner = "k2on";
repo = "wakapi";
rev = "theming";
# hash = "";
hash = "sha256-mbQ2cA9tbuDA5OXEP+qVfsrBC90budAzWE7x4oN6ypY=";
};
# vendorHash = final.lib.fakeHash;
vendorHash = "sha256-lb6u9NQbB3bizIRbCRaB7Ngv9T5mAYtSl+g13gL7VEU=";
});
})
];
services.wakapi = {
enable = true;
passwordSaltFile = config.sops.secrets."waka-password-salt".path;
settings = {
server.port = 3006;
app.avatar_url_template = "https://auth.koon.us/api/users/fbffa48a-faf7-4230-a89f-0da184f5948c/profile-picture.png";
};
};
}

50
host/ark/sops.nix Normal file
View File

@@ -0,0 +1,50 @@
{ config, ... }:
{
sops = {
defaultSopsFile = ../../secrets/sops/host/ark/default.yaml;
validateSopsFiles = false;
age.keyFile = "/var/lib/sops-nix/key.txt";
secrets = {
"host_age_key" = {
path = "/var/lib/sops-nix/key.txt";
};
"restic-password" = {};
"tunnel-credentials" = {};
"admin-password" = {};
"waka-password-salt" = {
owner = config.users.users.wakapi.name;
};
"photos/clientId" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
};
"photos/clientSecret" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
};
"git/clientId" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
owner = config.services.gitea.user;
};
"git/clientSecret" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
owner = config.services.gitea.user;
};
"docs/clientId" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
owner = config.services.outline.user;
};
"docs/clientSecret" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
owner = config.services.outline.user;
};
};
};
}

12
host/ark/user.nix Normal file
View File

@@ -0,0 +1,12 @@
{ pkgs, config, ... }: {
sops.secrets.admin-password.neededForUsers = true;
users.mutableUsers = false;
users.users.admin = {
isNormalUser = true;
extraGroups = [ "wheel" ];
hashedPasswordFile = config.sops.secrets.admin-password.path;
packages = with pkgs; [ tree vim tmux restic ];
};
}

View File

@@ -0,0 +1,9 @@
{ inputs, ... }: {
time.timeZone = "America/New_York";
services.tailscale.enable = true;
# security.sudo.wheelNeedsPassword = false;
nix.settings.experimental-features = [ "nix-command" "flakes" ];
}

View File

@@ -0,0 +1,63 @@
{ lib, ... }: {
programs.firefox = let
lock-false = {
Value = false;
Status = "locked";
};
lock-true = {
Value = true;
Status = "locked";
};
lock-empty-string = {
Value = "";
Status = "locked";
};
in {
enable = true;
policies = {
DisableTelemetry = true;
DisableFirefoxStudies = true;
DontCheckDefaultBrowser = true;
DisablePocket = true;
DisableAccounts = true;
Preferences = {
"extensions.pocket.enabled" = lock-false;
"browser.topsites.contile.enabled" = lock-false;
"browser.newtabpage.pinned" = lock-empty-string;
"browser.newtabpage.activity-stream.showSponsored" = lock-false;
"browser.newtabpage.activity-stream.system.showSponsored" = lock-false;
"browser.newtabpage.activity-stream.showSponsoredTopSites" = lock-false;
};
ExtensionSettings = {
"uBlock0@raymondhill.net" = {
install_url =
"https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi";
installation_mode = "force_installed";
};
"{446900e4-71c2-419f-a6a7-df9c091e268b}" = {
install_url =
"https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi";
installation_mode = "force_installed";
};
"{d7742d87-e61d-4b78-b8a1-b469842139fa}" = {
install_url =
"https://addons.mozilla.org/firefox/downloads/latest/vimium-ff/latest.xpi";
installation_mode = "force_installed";
};
"myallychou@gmail.com" = {
install_url =
"https://addons.mozilla.org/firefox/downloads/latest/youtube-recommended-videos/latest.xpi";
installation_mode = "force_installed";
};
};
UserMessaging = {
UrlbarInterventions = false;
SkipOnboarding = true;
};
};
};
}

View File

@@ -0,0 +1,28 @@
{ pkgs, ... }: {
services = {
desktopManager.plasma6.enable = true;
displayManager.sddm.enable = true;
displayManager.sddm.wayland.enable = true;
};
environment.systemPackages = with pkgs; [
kdePackages.discover # Optional: Install if you use Flatpak or fwupd firmware update sevice
kdePackages.kcalc # Calculator
kdePackages.kcharselect # Tool to select and copy special characters from all installed fonts
kdePackages.kcolorchooser # A small utility to select a color
kdePackages.kolourpaint # Easy-to-use paint program
kdePackages.ksystemlog # KDE SystemLog Application
kdePackages.sddm-kcm # Configuration module for SDDM
kdiff3 # Compares and merges 2 or 3 files or directories
kdePackages.isoimagewriter # Optional: Program to write hybrid ISO files onto USB disks
kdePackages.partitionmanager # Optional Manage the disk devices, partitions and file systems on your computer
kdePackages.merkuro
kdePackages.korganizer
kdePackages.kdepim-addons
hardinfo2 # System information and benchmarks for Linux systems
haruna # Open source video player built with Qt/QML and libmpv
wayland-utils # Wayland utilities
wl-clipboard # Command-line copy/paste utilities for Wayland
];
}

View File

@@ -0,0 +1 @@
{ ... }: { programs.thunderbird.enable = true; }

View File

@@ -0,0 +1,18 @@
{ pkgs, ... }: {
fonts.packages = with pkgs; [
monocraft
(stdenv.mkDerivation {
name = "apple-color-emoji";
src = fetchurl {
url =
"https://github.com/samuelngs/apple-emoji-linux/releases/download/v17.4/AppleColorEmoji.ttf";
sha256 = "1wahjmbfm1xgm58madvl21451a04gxham5vz67gqz1cvpi0cjva8";
};
dontUnpack = true;
installPhase = ''
install -Dm644 $src $out/share/fonts/truetype/AppleColorEmoji.ttf
'';
})
];
}

View File

@@ -0,0 +1,14 @@
{ pkgs, ... }: {
i18n.defaultLocale = "en_US.UTF-8";
i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" "zh_CN.UTF-8/UTF-8" ];
i18n.inputMethod = {
enabled = "fcitx5";
fcitx5.addons = with pkgs; [
# fcitx5-gtk # alternatively, kdePackages.fcitx5-qt
kdePackages.fcitx5-qt # alternatively, kdePackages.fcitx5-qt
fcitx5-chinese-addons # table input method support
fcitx5-nord # a color theme
];
};
}

View File

@@ -0,0 +1,32 @@
{ lib, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
yubioath-flutter # gui
yubikey-manager # `ykman`
pam_u2f # yubikey with sudo
];
services.pcscd.enable = true;
services.udev.packages = [ pkgs.yubikey-personalization ];
services.yubikey-agent.enable = true;
security.pam = {
sshAgentAuth.enable = true;
u2f = {
enable = true;
settings = {
cue = true;
authFile = "/home/max/.config/Yubico/u2f_keys";
};
};
services = {
login.u2fAuth = true;
sudo = {
u2fAuth = true;
sshAgentAuth = true;
};
};
};
}

116
host/max/default.nix Normal file
View File

@@ -0,0 +1,116 @@
{ pkgs, config, pkgs-unstable, ... }: {
imports = [
./hardware-configuration.nix
../common/core/default.nix
./user.nix
./work.nix
./sops.nix
../common/optional/yubikey.nix
../common/optional/browser.nix
../common/optional/desktop.nix
../common/optional/fonts.nix
../common/optional/locale.nix
../common/optional/email.nix
./zero-cache.nix
];
services.zero-cache.enable = false;
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = false;
boot.m1n1CustomLogo = ../../assets/logo.png;
hardware = {
asahi = {
peripheralFirmwareDirectory = ./firmware;
useExperimentalGPUDriver = true;
experimentalGPUInstallMode = "replace";
setupAsahiSound = true;
};
};
# networking.hostName = "nixos"; # Define your hostname.
# Pick only one of the below networking options.
networking.networkmanager.enable =
true; # Easiest to use and most distros use this by default.
hardware.bluetooth = {
enable = true;
powerOnBoot = true;
};
environment.variables = {
XDG_DATA_HOME = "/home/max/.local/share";
GSK_RENDERER = "ngl";
EDITOR = "nvim";
};
programs.wireshark.enable = true;
programs.adb.enable = true;
programs.kdeconnect.enable = true;
environment.systemPackages = with pkgs; [
vim
git
wget
# mpc
gurk-rs
libreoffice-qt
# ncmpcpp
brave
signal-desktop
gnupg
(pass.withExtensions (exts: [ exts.pass-otp ]))
pinentry
pinentry-curses
pinentry-qt
zathura
fzf
ffmpeg
ripgrep
unzip
zbar
tt
sc-im
libqalculate
librespeed-cli
tea
kubectl
cloudflared
# gcc
prismlauncher
gimp
inkscape
wireshark
# arm support
pkgs-unstable.sparrow
];
programs.zsh.enable = true;
programs.gnupg.agent = {
enable = true;
pinentryPackage = pkgs.pinentry-qt;
enableSSHSupport = true;
};
system.stateVersion = "25.05";
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,35 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot.initrd.availableKernelModules = [ "usb_storage" "sdhci_pci" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/664ec8c7-4c36-414c-bf99-c5346a4579dd";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/02E4-1CF8";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.wlan0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
}

18
host/max/home.nix Normal file
View File

@@ -0,0 +1,18 @@
{ ... }:
{
imports = [
./home/sops.nix
./home/ssh.nix
./home/git.nix
./home/browser.nix
./home/desktop.nix
./home/nvim.nix
./home/terminal.nix
];
home.username = "max";
home.homeDirectory = "/home/max";
home.stateVersion = "25.05";
}

57
host/max/home/browser.nix Normal file
View File

@@ -0,0 +1,57 @@
{
programs.firefox = {
enable = true;
profiles = {
personal = {
id = 0;
name = "1. Personal";
isDefault = true;
settings = {
"browser.search.defaultenginename" = "ddg";
"browser.search.order.1" = "ddg";
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
};
search = {
force = true;
default = "ddg";
order = [ "ddg" "google" ];
};
userChrome = builtins.readFile ./browser/userChrome.css;
};
work = {
id = 1;
name = "2. Work";
settings = {
"browser.search.defaultenginename" = "ddg";
"browser.search.order.1" = "ddg";
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
};
search = {
force = true;
default = "ddg";
order = [ "ddg" "google" ];
};
userChrome = builtins.readFile ./browser/userChrome.css;
};
school = {
id = 2;
name = "3. School";
settings = {
"browser.search.defaultenginename" = "ddg";
"browser.search.order.1" = "ddg";
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
};
search = {
force = true;
default = "ddg";
order = [ "ddg" "google" ];
};
userChrome = builtins.readFile ./browser/userChrome.css;
};
};
};
}

View File

@@ -0,0 +1,6 @@
.browserContainer > findbar {
top: 0 !important;
position: fixed !important;
width: 1000px !important;
right: 0 !important;
}

15
host/max/home/desktop.nix Normal file
View File

@@ -0,0 +1,15 @@
{ lib, ... }: {
programs.plasma = {
enable = true;
workspace = { wallpaper = "/home/max/bg.jpg"; };
kwin = { virtualDesktops = { number = 9; }; };
input = {
keyboard = {
options = [ "caps:escape" ];
layouts = [ { layout = "us"; } { layout = "cn"; } ];
};
};
};
}

29
host/max/home/git.nix Normal file
View File

@@ -0,0 +1,29 @@
{ lib, ... }:
let
publicGitEmail = "22125083+k2on@users.noreply.github.com";
publicKey = "/home/max/.ssh/id_maxkey.pub";
in
{
programs.git = {
enable = true;
userName = "Max Koon";
userEmail = publicGitEmail;
extraConfig = {
init.defaultBranch = "main";
commit.gpgsign = true;
gpg.format = "ssh";
user.signing.key = publicKey;
gpg.ssh.allowedSignersFile = "/home/max/.ssh/allowed_signers";
};
signing = {
signByDefault = true;
key = publicKey;
};
};
home.file.".ssh/allowed_signers".text = ''
${publicGitEmail} ${lib.fileContents ../keys/id_maxkey.pub}
'';
}

262
host/max/home/nvim.nix Normal file
View File

@@ -0,0 +1,262 @@
{ pkgs, ... }: {
programs.nixvim = {
enable = true;
colorschemes.one.enable = true;
globals = {
mapleader = " ";
maplocalleader = " ";
};
clipboard = {
providers.wl-copy.enable = true;
register = "unnamedplus";
};
opts = {
background = "light";
relativenumber = true;
cursorline = true;
number = true;
signcolumn = "yes";
updatetime = 250;
list = true;
listchars.__raw = "{ tab = '» ', trail = '·', nbsp = '' }";
};
extraConfigLua = ''
require('stay-centered').setup({ enable = true })
require('mini.ai').setup()
'';
keymaps = [
{
mode = "n";
key = "<Esc>";
action = "<cmd>nohlsearch<CR>";
}
{
mode = "n";
key = "<leader>a";
action.__raw = "function() require'harpoon':list():add() end";
}
{
mode = "n";
key = "<C-e>";
action.__raw =
"function() require'harpoon'.ui:toggle_quick_menu(require'harpoon':list()) end";
}
{
mode = "n";
key = "<C-j>";
action.__raw = "function() require'harpoon':list():select(1) end";
}
{
mode = "n";
key = "<C-k>";
action.__raw = "function() require'harpoon':list():select(2) end";
}
{
mode = "n";
key = "<C-l>";
action.__raw = "function() require'harpoon':list():select(3) end";
}
{
mode = "n";
key = "<C-;>";
action.__raw = "function() require'harpoon':list():select(4) end";
}
{
mode = "n";
key = "<leader>b";
action = "<cmd>Neotree<CR>";
}
{
mode = "n";
key = "<leader>l";
action = "<cmd>Neotree reveal<CR>";
}
];
diagnostic.settings.virtual_text = true;
userCommands.W.command = "w";
plugins = {
sleuth.enable = true;
lastplace.enable = true;
gitsigns.enable = true;
highlight-colors.enable = true;
todo-comments.enable = true;
# smear-cursor.enable = true;
goyo.enable = true;
treesitter = {
enable = true;
settings = {
ensureInstalled =
[ "typescript" "rust" "php" "blade" "python" "nix" ];
highlight = { enable = true; };
indent = { enable = true; };
};
};
lsp = {
enable = true;
servers = {
ts_ls.enable = true;
rust_analyzer = {
enable = true;
installCargo = true;
installRustc = true;
};
clangd.enable = true;
tailwindcss.enable = true;
phpactor.enable = true;
pylsp.enable = true;
pyright.enable = true;
nixd.enable = true;
};
keymaps = {
extra = [
{
mode = "n";
key = "gd";
action.__raw = "require('telescope.builtin').lsp_definitions";
options = { desc = "LSP: [G]oto [D]efinition"; };
}
{
mode = "n";
key = "gr";
action.__raw = "require('telescope.builtin').lsp_references";
options = { desc = "LSP: [G]oto [R]eferences"; };
}
];
lspBuf = {
"<leader>." = {
mode = [ "n" "x" ];
action = "code_action";
desc = "Code action";
};
};
};
};
lazydev.enable = true;
luasnip.enable = true;
telescope = {
enable = true;
extensions = {
fzf-native.enable = true;
ui-select.enable = true;
};
keymaps = {
"<leader>sf" = {
mode = "n";
action = "find_files";
options = { desc = "[S]earch [F]iles"; };
};
"<leader>sk" = {
mode = "n";
action = "live_grep";
options = { desc = "[S]earch [S]tring"; };
};
};
settings = {
extensions.__raw =
"{ ['ui-select'] = { require('telescope.themes').get_dropdown() } }";
};
};
cmp = {
enable = true;
settings = {
snippet = {
expand = ''
function(args)
require('luasnip').lsp_expand(args.body)
end
'';
};
completion = { completeopt = "menu,menuone,noinsert"; };
formatting = {
format = ''require("nvim-highlight-colors").format'';
};
mapping = {
"<CR>" = "cmp.mapping.confirm { select = true }";
"<Tab>" = "cmp.mapping.select_next_item()";
"<S-Tab>" = "cmp.mapping.select_prev_item()";
"<Down>" = "cmp.mapping.select_next_item()";
"<Up>" = "cmp.mapping.select_prev_item()";
"<C-j>" = "cmp.mapping.select_next_item()";
"<C-k>" = "cmp.mapping.select_prev_item()";
};
sources = [
{
name = "lazydev";
group_index = 0;
}
{ name = "nvim_lsp"; }
{ name = "luasnip"; }
{ name = "path"; }
{ name = "nvim_lsp_signature_help"; }
];
};
};
harpoon = {
enable = true;
settings.settings = { save_on_toggle = true; };
};
neo-tree = {
enable = true;
extraOptions = {
filesystem = {
filtered_items = {
visible = true;
};
};
};
};
wakatime.enable = true;
autoclose.enable = true;
ts-autotag.enable = true;
spider = {
enable = true;
extraOptions = {
subwordMovement = true;
skipInsignificantPunctuation = false;
};
keymaps = {
motions = {
"w" = "w";
"e" = "e";
"b" = "b";
};
};
};
};
extraPlugins = with pkgs.vimPlugins; [ stay-centered-nvim mini-ai ];
};
}

19
host/max/home/sops.nix Normal file
View File

@@ -0,0 +1,19 @@
{ ... }:
{
sops = {
age.keyFile = "/home/max/.config/sops/age/keys.txt";
defaultSopsFile = ../../../secrets/sops/host/max/default.yaml;
validateSopsFiles = false;
secrets = {
"ssh_keys/max" = {
path = "/home/max/.ssh/id_maxkey";
};
"waka_config" = {
path = "/home/max/.wakatime.cfg";
};
};
};
}

45
host/max/home/ssh.nix Normal file
View File

@@ -0,0 +1,45 @@
{ ... }:
{
programs.ssh = {
enable = true;
extraConfig = ''
Host m1
HostName m1
User admin
Host surface
HostName surface
User admin
Host ark
HostName ark
User admin
Host pi
HostName 192.168.0.143
User admin
Host ssh.koon.us
HostName ssh.koon.us
ProxyCommand cloudflared access ssh --hostname %h
User git
AddKeysToAgent yes
'';
matchBlocks = {
"git" = {
host = "github.com";
user = "git";
identityFile = [
"~/.ssh/id_maxkey"
];
};
};
};
home.file = {
".ssh/id_maxkey.pub".source = ../keys/id_maxkey.pub;
};
}

View File

@@ -0,0 +1,69 @@
{ pkgs, ... }: {
programs.alacritty = {
enable = true;
theme = "one_light";
settings = {
font = {
normal.family = "Monocraft";
size = 10;
};
};
};
programs.lf = { enable = true; };
programs.tmux = {
enable = true;
mouse = true;
keyMode = "vi";
shell = "${pkgs.zsh}/bin/zsh";
extraConfig = ''
set -g status-style bg=white
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
'';
};
programs.zsh = {
enable = true;
enableCompletion = true;
autosuggestion = {
enable = true;
highlight = "fg=#bbbbbb";
};
syntaxHighlighting.enable = true;
dotDir = ".config/zsh";
autocd = true;
# initExtra = builtins.readFile ./zsh-nix-shell.zsh;
shellAliases = {
ll = "ls -la --color";
v = "nvim";
vi = "nvim";
vim = "nvim";
k = "kubectl";
tt = "tt --theme one-light -n 10";
bible = "nvim ~/bible.txt -R";
notes = "nvim ~/notes";
home = "sudo nvim /etc/nixos/home.nix";
wttr = "curl wttr.in/Clemson";
docx-to-pdf = "libreoffice --headless --convert-to pdf";
};
plugins = [{
name = "vi-mode";
src = pkgs.zsh-vi-mode;
file = "share/zsh-vi-mode/zsh-vi-mode.plugin.zsh";
}];
};
programs.starship = { enable = true; };
}

View File

@@ -0,0 +1 @@
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIMywmwW37vjQSd9lqYh9IhGYce9Bi24sTyG3zffpdaJrAAAABHNzaDo= max@koon

25
host/max/sops.nix Normal file
View File

@@ -0,0 +1,25 @@
{ config, lib, ... }:
{
sops = {
age.keyFile = if builtins.pathExists /var/lib/sops-nix/key.txt then
"/var/lib/sops-nix/key.txt"
else
"/home/max/.config/sops/age/keys.txt" # temp decrypt key
;
defaultSopsFile = ../../secrets/sops/host/max/default.yaml;
validateSopsFiles = false;
secrets = {
"host_age_key" = {
path = "/var/lib/sops-nix/key.txt";
};
"yubico/u2f_keys" = {
owner = config.users.users.max.name;
inherit (config.users.users.max) group;
path = "/home/max/.config/Yubico/u2f_keys";
};
};
};
}

13
host/max/user.nix Normal file
View File

@@ -0,0 +1,13 @@
{ pkgs, config, ... }: {
sops.secrets.max-password.neededForUsers = true;
users.mutableUsers = false;
users.users.max = {
isNormalUser = true;
hashedPasswordFile = config.sops.secrets.max-password.path;
extraGroups = [ "wheel" "networkmanager" "video" "wireshark" "kvm" ];
packages = with pkgs; [ tree ];
shell = pkgs.zsh;
};
}

31
host/max/work.nix Normal file
View File

@@ -0,0 +1,31 @@
{ config, secrets, ... }: {
services.openvpn.servers = {
ris = {
config = "config /etc/openvpn/ris/config.ovpn ";
updateResolvConf = true;
autoStart = false;
};
};
sops.secrets = {
"ris-vpn/key" = {
sopsFile = ../../secrets/sops/host/max/work.yaml;
owner = config.users.users.root.name;
inherit (config.users.users.root) group;
path = "/etc/openvpn/ris/vpnclient.rismedia.com.key";
};
};
environment.etc."openvpn/ris/config.ovpn" = {
text = secrets.work.ris.vpn.config;
};
environment.etc."openvpn/ris/vpnclient.rismedia.com.crt" = {
text = secrets.work.ris.vpn.crt;
};
networking.extraHosts = ''
${secrets.work.ris.extraHosts}
'';
}

84
host/max/zero-cache.nix Normal file
View File

@@ -0,0 +1,84 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.zero-cache;
inherit (lib)
mkEnableOption
mkIf
;
litestream = pkgs.buildGoModule rec {
pname = "litestream-zero";
version = "0.3.13+z0.0.6";
src = pkgs.fetchFromGitHub {
owner = "rocicorp";
repo = "litestream";
rev = "zero@v0.0.6";
sha256 = "sha256-sBKmz2fBoYzYi1kUVeiugLBLPdqHc+fXCBkI8Cttakg=";
};
vendorHash = "sha256-PlfDJbhzbH/ZgtQ35KcB6HtPEDTDgss7Lv8BcKT/Dgg=";
ldflags = [
"-s"
"-w"
"-X main.Version=${version}"
# nix does not like to build with this
# "-extldflags '-static'"
];
doCheck = false;
tags = [
"osusergo"
"netgo"
"sqlite_omit_load_extension"
];
subPackages = [ "cmd/litestream" ];
};
zero-cache = pkgs.buildNpmPackage rec {
name = "zero-cache";
src = pkgs.fetchFromGitHub {
owner = "rocicorp";
repo = "mono";
rev = "zero/v0.23.2025081401";
hash = "sha256-NQcG/vnfUmle/6eNXXmnMqzNvniK8R/mO5RYdMX9pnE=";
};
npmDepsHash = "sha256-9vX9eODN8AfcLcMSjm6KzAAUmPIHfe2BILt0juya5us=";
makeCacheWritable = true;
npmFlags = [ "--legacy-peer-deps" ];
};
in
{
options = {
services.zero-cache = {
enable = mkEnableOption "Zero-cache, the server component of the Zero sync engine.";
};
};
config = mkIf cfg.enable {
systemd.services.zero-cache = {
description = "Zero Cache";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${zero-cache}/bin/zero-cache";
RemainAfterExit = true;
};
};
};
}