Compare commits

...

21 Commits

Author SHA1 Message Date
0f90778b53 refactor!: deploy headscale 2026-02-15 16:06:54 -08:00
dec32b9766 fix: pin sonarr version 2026-02-14 14:18:47 -08:00
64c13da521 fix: add no chat reports to minecraft-main 2026-02-13 20:26:17 -08:00
13f8c64f29 feat: add axiom to minecraft creative 2026-02-12 11:14:50 -08:00
27681c3ff5 fix: update pearce udm router endpoint 2026-02-06 13:40:34 -08:00
f83dca42ea feat: add pearce udm router 2026-02-05 18:27:16 -08:00
94e550787e fix!: only create mesh to routers 2026-02-04 21:48:00 -08:00
508d5a3525 fix: re add firewall configuration 2026-02-04 21:29:19 -08:00
a42e02514e feat: add tux to mesh 2026-02-04 21:21:22 -08:00
413f16fb6f fix: remove firewall configuration 2026-02-04 21:14:41 -08:00
c85cf06186 feat(wg): add mesh tunneling to devices & routers 2026-02-04 20:57:09 -08:00
63f9d3418c fix(safety): add fallback dns servers and fallback terminal 2026-02-03 22:58:30 -08:00
46460039af fix: jj sign commits 2026-02-03 21:43:05 -08:00
b9709dd655 feat: add jj 2026-02-03 21:29:33 -08:00
165eee9dd7 fix(homelab): add more resources to creative world 2026-02-01 16:13:09 -08:00
fd28865071 feat(homelab): add more optimization to servers 2026-01-31 15:22:56 -08:00
51afe1240d feat(homelab): add elytra trims 2026-01-30 19:54:02 -08:00
74909b9cd4 feat(homelab): add carpet & monitor keybinds 2026-01-30 14:35:50 -08:00
bd4dd7ba23 feat(homelab): migrate server to fabric 2026-01-29 17:20:25 -08:00
ae407c99c1 fix(homelab): use new fqdn for creative world 2026-01-25 14:29:25 -08:00
d086bb61ed feat(homelab): add old server 2026-01-25 00:13:23 -08:00
25 changed files with 438 additions and 39 deletions

View File

@@ -48,7 +48,7 @@ pub async fn backup_world(state: State, world: &str) -> Result<()> {
let reporter = Reporter::new();
let job_name = format!("minecraft-{}-backup", world);
reporter.status(format!("Scaling deployment minecraft-{world}"));
reporter.log(format!("Scaling deployment minecraft-{world}"));
scale_deployment(&state.client, NAMESPACE, &format!("minecraft-{world}"), 0).await?;
reporter.status("Creating backup job...");
@@ -71,7 +71,7 @@ pub async fn backup_world(state: State, world: &str) -> Result<()> {
let succeeded = status.and_then(|s| s.succeeded).unwrap_or(0);
let failed = status.and_then(|s| s.failed).unwrap_or(0);
reporter.status(format!("Scaling deployment minecraft-{world}, replicas: 1"));
reporter.log(format!("Scaling deployment minecraft-{world}, replicas: 1"));
scale_deployment(&state.client, NAMESPACE, &format!("minecraft-{world}"), 1).await?;
if succeeded > 0 {
reporter.success("Backup complete");
@@ -137,7 +137,7 @@ async fn stream_pod_logs(pods: &Api<Pod>, pod_name: &str, reporter: &Reporter) -
let mut lines = stream.lines();
while let Some(line) = lines.try_next().await? {
reporter.log(&line);
reporter.log_event(&line);
}
Ok(())

View File

@@ -1,16 +1,22 @@
use std::fmt::Display;
use indicatif::{ProgressBar, ProgressStyle};
pub struct Reporter {
spinner: ProgressBar,
}
pub const TICK_CHARS: &str = "⣷⣯⣟⡿⢿⣻⣽⣾";
impl Reporter {
pub fn new() -> Self {
let spinner = ProgressBar::new_spinner();
spinner.set_style(
ProgressStyle::default_spinner()
.template("{spinner:.cyan} {msg}")
.unwrap(),
ProgressStyle::with_template(
"{prefix:.dim}{msg:>8.214/yellow} {spinner} [{elapsed_precise}]",
)
.unwrap()
.tick_chars(TICK_CHARS),
);
spinner.enable_steady_tick(std::time::Duration::from_millis(100));
Self { spinner }
@@ -20,12 +26,16 @@ impl Reporter {
self.spinner.set_message(msg.into());
}
pub fn log(&self, line: &str) {
pub fn log_event(&self, line: &str) {
self.spinner.suspend(|| {
println!("{}", line);
});
}
pub fn log<T: Display>(&self, text: T) {
self.spinner.suspend(|| println!("{}", text))
}
pub fn success(&self, msg: &str) {
self.spinner.finish_with_message(format!("{}", msg));
}

View File

@@ -0,0 +1 @@
apiVersion: batch/v1

View File

@@ -101,6 +101,13 @@ routes = [
service = "prometheus-stack-grafana",
port = 80,
private = true
},
{
name = "mesh",
namespace = "networking",
service = "headscale",
port = 8080,
private = false
}
]

View File

@@ -45,6 +45,13 @@ releases:
values:
- values/gitea.yaml
- name: gitea-runners
namespace: git
chart: gitea-charts/actions
version: 0.0.2
values:
- values/gitea-runners.yaml
# Storage
- name: longhorn
namespace: longhorn-system
@@ -95,6 +102,13 @@ releases:
values:
- values/minecraft/creative.yaml
- name: minecraft-old
namespace: minecraft
chart: minecraft-charts/minecraft
version: 5.0.0
values:
- values/minecraft/old.yaml
- name: home-assistant
namespace: home
chart: home-assistant/home-assistant

View File

@@ -0,0 +1,5 @@
enabled: true
statefulset:
nodeSelector:
kubernetes.io/hostname: rufus
giteaRootURL: https://git.lucalise.ca

View File

@@ -3,23 +3,37 @@ resources:
cpu: 1
memory: 500Mi
limits:
memory: 4Gi
memory: 5Gi
cpu: 2000m
minecraftServer:
eula: "TRUE"
type: "PAPER"
type: "FABRIC"
version: "1.21.11"
difficulty: hard
motd: "A Minecraft Server."
gameMode: creative
memory: 4G
memory: 5G
rcon:
enabled: true
withGeneratedPassword: false
port: 25575
existingSecret: rcon-credentials
secretKey: rcon-password
modrinth:
projects:
- fabric-api
- tree-vein-miner
- lithium
- servux
- ferrite-core
- carpet
- elytra-trims
- fabric-language-kotlin
- c2me-fabric
- scalablelux
- axiom
nodeSelector:
kubernetes.io/hostname: kube

View File

@@ -8,7 +8,7 @@ resources:
minecraftServer:
eula: "TRUE"
type: "PAPER"
type: "FABRIC"
version: "1.21.11"
difficulty: hard
motd: "A Minecraft Server."
@@ -21,8 +21,17 @@ minecraftServer:
secretKey: rcon-password
modrinth:
projects:
- treeminer
- fast-leaf-decay
- fabric-api
- tree-vein-miner
- lithium
- servux
- ferrite-core
- carpet
- elytra-trims
- fabric-language-kotlin
- c2me-fabric
- scalablelux
- no-chat-reports
nodeSelector:
kubernetes.io/hostname: kube

View File

@@ -0,0 +1,29 @@
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
memory: 2Gi
cpu: 1
minecraftServer:
eula: "TRUE"
type: "VANILLA"
version: "1.7.10"
difficulty: hard
motd: "A Minecraft Server."
memory: 4G
rcon:
enabled: true
withGeneratedPassword: false
port: 25575
existingSecret: rcon-credentials
secretKey: rcon-password
nodeSelector:
kubernetes.io/hostname: rufus
persistence:
dataDir:
enabled: true
Size: 2Gi

View File

@@ -11,6 +11,9 @@ minecraftRouter:
- externalHostname: "mc-rocket.privatedns.org"
host: "minecraft-main"
port: 25565
- externalHostname: "mc-rocket-creative.duckdns.org"
- externalHostname: "mc-rocket-creative.privatedns.org"
host: "minecraft-creative"
port: 25565
- externalHostname: "mc-rocket-old.privatedns.org"
host: "minecraft-old"
port: 25565

View File

@@ -0,0 +1,18 @@
apiVersion: v1
kind: Pod
metadata:
name: headscale-migrate
namespace: networking
spec:
restartPolicy: Never
containers:
- name: migrate
image: nouchka/sqlite3
command: ["sleep", "infinity"]
volumeMounts:
- name: data
mountPath: /var/lib/headscale
volumes:
- name: data
persistentVolumeClaim:
claimName: headscale-data

View File

@@ -15,3 +15,6 @@ resources:
- ./media/radarr.yaml
- ./media/qbittorrent.yaml
- ./media/flaresolverr.yaml
- ./networking/headscale/config.yaml
- ./networking/headscale/headscale.yaml

View File

@@ -34,7 +34,7 @@ spec:
spec:
containers:
- name: sonarr
image: lscr.io/linuxserver/sonarr
image: lscr.io/linuxserver/sonarr:4.0.16
securityContext:
runAsUser: 0
runAsGroup: 0

View File

@@ -0,0 +1,50 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: headscale-config
namespace: networking
data:
acl.json: |
{
"tagOwners": {
"tag:personal": ["lucalise@"],
},
"acls": [
{"action": "accept", "src": ["tag:personal"], "dst": ["tag:personal:*"]},
{"action": "accept", "src": ["tag:personal"], "dst": ["autogroup:internet:*"]},
{"action": "accept", "src": ["tag:personal"], "dst": ["192.168.15.0/27:*", "192.168.27.0/24:*", "192.168.20.0/26:*"]}
]
}
config.yaml: |
server_url: https://mesh.lucalise.ca
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 10.100.0.0/24
v6: fd7a:115c:a1e0::/48
database:
type: sqlite3
sqlite:
path: /var/lib/headscale/db.sqlite
policy:
path: /etc/headscale/acl.json
dns:
override_local_dns: false
base_domain: m.net
derp:
server:
enabled: false
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: true
update_frequency: 24h
log:
level: info

View File

@@ -0,0 +1,88 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: headscale-data
namespace: networking
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: headscale
namespace: networking
labels:
app: headscale
spec:
replicas: 1
selector:
matchLabels:
app: headscale
template:
metadata:
labels:
app: headscale
spec:
containers:
- name: headscale
image: docker.io/headscale/headscale
command: ["headscale", "serve"]
ports:
- containerPort: 8080
name: http
- containerPort: 9090
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 512m
memory: 1Gi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: headscale-data
mountPath: /var/lib/headscale
- name: headscale-config
mountPath: /etc/headscale/config.yaml
subPath: config.yaml
- name: headscale-config
mountPath: /etc/headscale/acl.json
subPath: acl.json
volumes:
- name: headscale-data
persistentVolumeClaim:
claimName: headscale-data
- name: headscale-config
configMap:
name: headscale-config
---
apiVersion: v1
kind: Service
metadata:
name: headscale
namespace: networking
labels:
app: headscale
spec:
selector:
app: headscale
ports:
- port: 8080
targetPort: http
protocol: TCP
name: http

View File

@@ -277,4 +277,20 @@ spec:
extensionRef:
group: traefik.io
kind: Middleware
name: private-networks
name: private-networks
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: mesh
namespace: networking
spec:
parentRefs:
- name: traefik-gateway
namespace: kube-system
hostnames:
- mesh.lucalise.ca
rules:
- backendRefs:
- name: headscale
port: 8080

View File

@@ -78,6 +78,7 @@
jless
fd
dig
just
];
programs.nix-ld.enable = lib.mkDefault true;
programs.zsh.enable = lib.mkDefault true;

View File

@@ -22,5 +22,6 @@
./mounts.nix
./nfs-mesh.nix
./rust.nix
# ./networking/wireguard-mesh.nix
];
}

View File

@@ -14,6 +14,15 @@
};
config = lib.mkIf config.desktop.enable {
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5.addons = with pkgs; [
fcitx5-mozc
fcitx5-gtk
];
};
environment.systemPackages = with pkgs; [
vscode-fhs
pavucontrol
@@ -53,6 +62,7 @@
fanctl
waypipe
inputs.quickshell.packages.${meta.architecture}.default
alacritty
];
boot.kernelModules = [
"iptables"
@@ -111,6 +121,14 @@
};
xdg.configFile = {
"hypr/hyprlock.conf".source = ../../custom/hyprlock/hyprlock.conf;
"fcitx5/config".text = ''
[Hotkey]
TriggerKeys=
EnumerateWithTriggerKeys=True
EnumerateForwardKeys=
EnumerateBackwardKeys=
EnumerateSkipFirst=False
'';
};
services.dunst = {
enable = true;
@@ -210,6 +228,10 @@
"$mod SHIFT, v, exec, bash -c ~/dotfiles/scripts/copy.sh"
"$mod SHIFT, s, exec, bash -c ~/dotfiles/scripts/screenshot.sh"
"$mod, p, exec, bash -c ~/dotfiles/scripts/project.sh"
"$mod SHIFT, k, exec, bash -c ~/dotfiles/scripts/layout.sh"
"$mod SHIFT, j, exec, fcitx5-remote -t"
"$mod CTRL, h, focusmonitor, l"
"$mod CTRL, l, focusmonitor, r"
"$mod, 0, workspace, 10"
"$mod SHIFT, 0, movetoworkspacesilent, 10"
@@ -257,17 +279,21 @@
"XCURSOR_SIZE,24"
"LIBVA_DRIVER_NAME,nvidia"
"__GLX_VENDOR_LIBRARY_NAME,nvidia"
# "GTK_IM_MODULE,fcitx"
# "QT_IM_MODULE,fcitx"
"XMODIFIERS,@im=fcitx"
];
exec-once = [
# "status-bar"
"qs"
"wl-clip-persist --clipboard regular"
"fcitx5 -d"
];
monitor = [
"eDP-1, 1920x1080, 0x0, 1"
];
input = {
kb_layout = "us";
kb_layout = "us,jp";
touchpad = {
natural_scroll = true;
};

View File

@@ -29,7 +29,7 @@
];
extraConfig = ''
[Resolve]
DNS=192.168.27.13:53
DNS=192.168.27.13:53 1.1.1.1 1.0.0.1
ResolveUnicastSingleLabel=yes
'';
};

View File

@@ -0,0 +1,90 @@
{
pkgs,
lib,
config,
...
}:
let
meshHosts = {
kumatani = {
address = "kumatani";
publicKey = "pKkl30tba29FG86wuaC0KrpSHMr1tSOujikHFbx75BM=";
isRouter = false;
ip = "10.100.0.1";
};
usahara = {
address = "usahara";
publicKey = "4v7GyAIsKfwWjLMVB4eoosJDvLkIDHW0KsEYoQqSnh4=";
isRouter = false;
ip = "10.100.0.2";
};
tux = {
address = "tux";
publicKey = "Z17ci3Flk1eDAhJ8QZSUgtmlw6BVu4XqvpqLKLWTYWw=";
isRouter = false;
ip = "10.100.0.3";
};
oakbay-pfsense = {
endpoint = "oakbay.lucalise.ca:51822";
publicKey = "xOTPZBIC9m1BkkiLCOUTty3b7/NOvslteVQHzEFxqWQ=";
isRouter = true;
ip = "10.100.0.250";
routes = [
"10.100.0.0/24"
"192.168.15.0/27"
"192.168.20.0/26"
"192.168.27.0/24"
];
};
pearce-udm = {
endpoint = "pearce.kisame.ca:51823";
publicKey = "hDb2DzI+isaqXLdxwAF1hc5Nid8TK/M1SQ+zDpf9QxY=";
isRouter = true;
ip = "10.100.0.251";
routes = [
"192.168.18.0/27"
];
};
};
getEndpoint =
name: host:
if host.isRouter or false then "${host.endpoint}" else "${host.address}:${toString 51820}";
mkPeer = name: host: {
publicKey = host.publicKey;
allowedIPs = [ "${host.ip}/32" ] ++ (host.routes or [ ]);
endpoint = getEndpoint name host;
persistentKeepalive = 25;
dynamicEndpointRefreshSeconds = 300;
};
mkPeersFor =
selfName:
lib.mapAttrsToList mkPeer (
lib.filterAttrs (name: host: name != selfName && (host.isRouter or false)) meshHosts
);
selfConfig = meshHosts.${config.networking.hostName} or null;
in
{
config = lib.mkIf (selfConfig != null) {
networking.wireguard.interfaces = {
wg0 = {
privateKeyFile = "/etc/wireguard/private.key";
ips = [ "${selfConfig.ip}/32" ];
listenPort = 51820;
peers = mkPeersFor config.networking.hostName;
};
};
networking.firewall = {
allowedUDPPorts = [ 51820 ];
trustedInterfaces = [ "wg0" ];
};
systemd.tmpfiles.rules = [
"d /etc/wireguard 0700 root root -"
];
};
}

View File

@@ -16,6 +16,8 @@
oh-my-posh = import ./omp.nix;
eza = import ./eza.nix;
mise = import ./mise.nix;
bacon.enable = true;
jujutsu = import ./jj.nix;
};
xdg.mimeApps = import ./mime.nix;
@@ -23,27 +25,6 @@
nodejs_22
pnpm
];
systemd.user.services.ssh-add-keys = {
Unit = {
Description = "Load SSH keys from YubiKey";
After = [ "ssh-agent.service" ];
Requires = [ "ssh-agent.service" ];
};
Service = {
Type = "oneshot";
Environment = [
"SSH_AUTH_SOCK=%t/ssh-agent"
"SSH_ASKPASS=${pkgs.lxqt.lxqt-openssh-askpass}/bin/lxqt-openssh-askpass"
"SSH_ASKPASS_REQUIRE=prefer"
"DISPLAY=:0"
];
ExecStart = "${pkgs.openssh}/bin/ssh-add -K";
RemainAfterExit = true;
};
Install = {
WantedBy = [ "default.target" ];
};
};
home.stateVersion = "24.11";

14
nix/users/luca/jj.nix Normal file
View File

@@ -0,0 +1,14 @@
{
enable = true;
settings = {
user = {
email = "luca_lise@icloud.com";
name = "lucalise";
};
signing = {
behavior = "own";
backend = "ssh";
key = "~/.ssh/id_ed25519.pub";
};
};
}

View File

@@ -33,6 +33,7 @@ in
"rust"
"kubectl"
"helm"
"jj"
];
};
plugins = [

18
scripts/layout.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Rofi-based keyboard layout switcher for Hyprland
layouts="🇨🇦 Canadian (CA)
🇯🇵 Japanese (JP)"
selected=$(echo "$layouts" | rofi -dmenu -p "Layout")
case "$selected" in
*"Canadian"*)
hyprctl switchxkblayout all 0
notify-send -h string:synchronous:keyboard "Keyboard" "🇨🇦 Canadian (CA)"
;;
*"Japanese"*)
hyprctl switchxkblayout all 1
notify-send -h string:synchronous:keyboard "Keyboard" "🇯🇵 Japanese (JP)"
;;
esac