Skip to content

Commit 69e6c33

Browse files
committed
feat: https over tailscale
1 parent cdee3a1 commit 69e6c33

File tree

4 files changed

+133
-37
lines changed

4 files changed

+133
-37
lines changed

custom_modules/core_services.nix

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,41 @@ in
6464
# package = nixpkgs-stable.legacyPackages.${system}.tailscale;
6565
enable = true;
6666
};
67+
68+
systemd.services.tailscale-optimization = {
69+
description = "Optimize ethtool settings for Tailscale";
70+
after = [ "network.target" ];
71+
wantedBy = [ "multi-user.target" ];
72+
serviceConfig = {
73+
Type = "oneshot";
74+
ExecStart = "${lib.getExe pkgs.ethtool} -K enp6s0 rx-udp-gro-forwarding on rx-gro-list off";
75+
};
76+
};
77+
services.caddy = {
78+
enable = true;
79+
80+
globalConfig = ''
81+
https_port 8443
82+
'';
83+
84+
virtualHosts."office-desktop.tail5ca7.ts.net" = {
85+
extraConfig = ''
86+
bind 127.0.0.1
87+
88+
route /navidrome* {
89+
reverse_proxy 127.0.0.1:4533
90+
}
91+
handle_path /netdata* {
92+
reverse_proxy 127.0.0.1:19999
93+
}
94+
handle_path /open-webui* {
95+
reverse_proxy 127.0.0.1:8085
96+
}
97+
'';
98+
};
99+
};
100+
services.tailscale.permitCertUid = "caddy";
101+
67102
# create a oneshot job to authenticate to Tailscale
68103
# systemd.services.tailscale-autoconnect = {
69104
# description = "Automatic authentication to Tailscale";
@@ -93,6 +128,29 @@ in
93128
# serviceConfig.SupplementaryGroups = [ config.users.groups.keys.name ];
94129
# };
95130

131+
services.sslh = {
132+
enable = true;
133+
# "listenAddresses" replaces the old "port" setting
134+
listenAddresses = [ "0.0.0.0" ];
135+
136+
settings = {
137+
transparent = false;
138+
protocols = [
139+
{
140+
name = "ssh";
141+
service = "ssh";
142+
host = "127.0.0.1";
143+
port = "22";
144+
}
145+
{
146+
name = "tls";
147+
host = "127.0.0.1";
148+
port = "8443";
149+
}
150+
];
151+
};
152+
};
153+
96154
services.openssh = {
97155
enable = true;
98156
settings.PasswordAuthentication = false;
@@ -104,7 +162,6 @@ in
104162
200
105163
201
106164
202
107-
443
108165
2001
109166
2002
110167
];
@@ -179,6 +236,7 @@ in
179236
3389
180237
80
181238
443
239+
8443
182240
444
183241
9993
184242
8080

custom_modules/jellyfin.nix

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ in
3838
services.navidrome.user = "jellyfin";
3939
services.navidrome.group = "jellyfin";
4040
services.navidrome.openFirewall = true;
41-
services.navidrome.settings.Address = "0.0.0.0";
41+
services.navidrome.settings.Address = "127.0.0.1";
4242
services.navidrome.settings."Scanner.FollowSymlinks" = true;
43+
services.navidrome.settings.Port = 4533;
4344
services.navidrome.settings.MusicFolder = "/jellyfin/MUSIC";
44-
services.navidrome.package = nixpkgs-master.legacyPackages.${system}.navidrome;
45+
services.navidrome.package = pkgs.navidrome;
46+
services.navidrome.settings.BaseUrl = "/navidrome";
4547
systemd.services.navidrome.serviceConfig.BindReadOnlyPaths = [ "/var/lib/musiclibrary" ];
4648

4749
services.jellyfin.enable = false;

custom_modules/network_monitor.nix

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,21 @@ let
2525
2626
def get_data(hours):
2727
try:
28-
df = pd.read_csv(LOG_FILE, parse_dates=['timestamp'])
28+
# Read CSV. We don't rely on automatic parsing in read_csv
29+
# to ensure we can control the UTC conversion explicitly below.
30+
df = pd.read_csv(LOG_FILE)
2931
except FileNotFoundError:
3032
print(f"Error: Log file {LOG_FILE} not found. Wait for the hourly timer to run.")
3133
sys.exit(1)
3234
33-
# Filter by time window
34-
start_time = datetime.now() - timedelta(hours=hours)
35+
# Convert timestamp column to timezone-aware UTC
36+
# This handles the mixed offsets (e.g. -05:00) provided by `date -Iseconds`
37+
df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True)
38+
39+
# Generate the start time as timezone-aware UTC
40+
start_time = pd.Timestamp.now(tz='UTC') - pd.Timedelta(hours=hours)
41+
42+
# Now both sides are TZ-aware (UTC), enabling valid comparison
3543
df = df[df['timestamp'] >= start_time].copy()
3644
3745
if df.empty:
@@ -45,7 +53,6 @@ let
4553
df = df.sort_values(['unit', 'timestamp'])
4654
4755
# Calculate the difference between rows (Usage = Current - Previous)
48-
# We group by 'unit' so we don't subtract Service A from Service B
4956
df['down_mb'] = df.groupby('unit')['ingress_bytes'].diff().fillna(0) / 1024 / 1024
5057
df['up_mb'] = df.groupby('unit')['egress_bytes'].diff().fillna(0) / 1024 / 1024
5158
@@ -85,8 +92,12 @@ let
8592
print(f"No history found for unit: {unit}")
8693
return
8794
88-
# Resample to hourly chunks to smooth out the table
95+
# Resample to hourly chunks.
96+
# We set the index to our UTC timestamp for resampling.
8997
timeline.set_index('timestamp', inplace=True)
98+
99+
# Convert index to local time for display purposes if desired,
100+
# or keep as UTC. Here we keep it simple.
90101
hourly = timeline[['down_mb', 'up_mb']].resample('1h').sum()
91102
92103
print(f"\n=== Hourly Timeline for {unit} ===")
@@ -109,7 +120,6 @@ let
109120
else:
110121
print_summary(time_window)
111122
'';
112-
113123
in
114124
{
115125
options.custom_modules.network_monitor.enable = lib.mkOption {
@@ -126,6 +136,14 @@ in
126136
systemd.services.systemd-net-logger = {
127137
description = "Log Systemd IP Counters to CSV";
128138
serviceConfig.Type = "oneshot";
139+
140+
# 1. Provide necessary tools
141+
path = with pkgs; [
142+
gawk
143+
findutils
144+
coreutils
145+
];
146+
129147
script = ''
130148
LOG_FILE="/var/log/network/systemd.csv"
131149
TIMESTAMP=$(date -Iseconds)
@@ -138,9 +156,27 @@ in
138156
| awk '{print $1}' \
139157
| xargs ${pkgs.systemd}/bin/systemctl show -p Id -p IPIngressBytes -p IPEgressBytes \
140158
| awk -v date="$TIMESTAMP" -F= '
141-
/^Id=/ { id=$2 }
142-
/^IPIngressBytes=/ { input=$2 }
143-
/^IPEgressBytes=/ { output=$2; if (input > 0 || output > 0) printf "%s,%s,%s,%s\n", date, id, input, output }
159+
# 2. Reset variables for every new Unit ID to prevent leaking
160+
/^Id=/ {
161+
id=$2;
162+
input=0;
163+
output=0;
164+
has_input=0;
165+
has_output=0;
166+
}
167+
168+
# 3. Filter out "unset" values (UINT64_MAX) and non-numbers
169+
/^IPIngressBytes=/ {
170+
if ($2 ~ /^[0-9]+$/ && $2 != "18446744073709551615") { input=$2; has_input=1; }
171+
}
172+
/^IPEgressBytes=/ {
173+
if ($2 ~ /^[0-9]+$/ && $2 != "18446744073709551615") { output=$2; has_output=1; }
174+
175+
# 4. Only log if we actually found valid traffic data
176+
if ((has_input || has_output) && (input > 0 || output > 0)) {
177+
printf "%s,%s,%s,%s\n", date, id, input, output
178+
}
179+
}
144180
' >> "$LOG_FILE"
145181
'';
146182
};

custom_modules/workstation_services.nix

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -386,31 +386,31 @@ in
386386
# # ];
387387
# };
388388

389-
# services.ollama = {
390-
# # package = tmpnixpkgs.ollama;
391-
# #package = (import nixpkgs-stable { system = "x86_64-linux"; config.allowUnfree = true; }).ollama;
392-
# loadModels = [
393-
# "deepseek-r1:32b"
394-
# "deepseek-r1:14b"
395-
# "SIGJNF/deepseek-r1-671b-1.58bit"
396-
# ];
397-
# enable = true;
398-
# package = pkgs.ollama-cuda;
399-
# # acceleration = "cuda";
400-
# host = "0.0.0.0";
401-
# # environmentVariables = {"OLLAMA_KV_CACHE_TYPE" = "q4_0"; };
402-
# };
403-
# services.open-webui = {
404-
# # package = tmpnixpkgs.open-webui;
405-
# openFirewall = true;
406-
# enable = true;
407-
# host = "0.0.0.0";
408-
# environment = {
409-
# OLLAMA_API_BASE_URL = "http://127.0.0.1:11434";
410-
# # Disable authentication
411-
# WEBUI_AUTH = "False";
412-
# };
413-
# };
389+
services.ollama = {
390+
# package = tmpnixpkgs.ollama;
391+
#package = (import nixpkgs-stable { system = "x86_64-linux"; config.allowUnfree = true; }).ollama;
392+
# loadModels = [
393+
# "deepseek-r1:32b"
394+
# "deepseek-r1:14b"
395+
# "SIGJNF/deepseek-r1-671b-1.58bit"
396+
# ];
397+
enable = true;
398+
# package = pkgs.ollama-cuda;
399+
# acceleration = "cuda";
400+
host = "0.0.0.0";
401+
# environmentVariables = {"OLLAMA_KV_CACHE_TYPE" = "q4_0"; };
402+
};
403+
services.open-webui = {
404+
# package = tmpnixpkgs.open-webui;
405+
openFirewall = true;
406+
enable = true;
407+
host = "0.0.0.0";
408+
environment = {
409+
OLLAMA_API_BASE_URL = "http://127.0.0.1:11434";
410+
# Disable authentication
411+
WEBUI_AUTH = "False";
412+
};
413+
};
414414

415415
# programs.kdeconnect.enable = true;
416416

0 commit comments

Comments
 (0)