authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-01-09 00:28:36-08:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-01-09 02:52:13-08:00
log839f6e614995faa9c948343f23bb23831af3117c
tree93623916fecc52b8c26002b646dc499f54e72532
parent6818a04ce885276880fac95a779f3a5a6c849727
signaturelock-open Commit is signed but in an unrecognized format.

feat: internal services on SSO


5 files changed, 162 insertions(+), 143 deletions(-)

compose.yaml+57-51
...@@ -17,6 +17,12 @@ services:...@@ -17,6 +17,12 @@ services:
17 watch:17 watch:
18 - path: ./config/Caddyfile18 - path: ./config/Caddyfile
19 action: restart19 action: restart
20 healthcheck:
21 test: ["CMD", "caddy", "healthcheck", "--address", ":2019"]
22 interval: 10s
23 timeout: 5s
24 retries: 3
25 start_period: 5s
20 # SSO26 # SSO
21 keycloak: # port 80, 44327 keycloak: # port 80, 443
22 container_name: keycloak28 container_name: keycloak
...@@ -255,6 +261,7 @@ services:...@@ -255,6 +261,7 @@ services:
255 ND_SCANNER_GROUPALBUMRELEASES: "1"261 ND_SCANNER_GROUPALBUMRELEASES: "1"
256 ND_BASEURL: "https://music.${HOME_DOMAIN}/"262 ND_BASEURL: "https://music.${HOME_DOMAIN}/"
257 ND_PID_ALBUM: "folder"263 ND_PID_ALBUM: "folder"
264 ND_EXTAUTH_USERHEADER: "Remote-User"
258 ND_EXTAUTH_TRUSTEDSOURCES: "0.0.0.0/0" # troll265 ND_EXTAUTH_TRUSTEDSOURCES: "0.0.0.0/0" # troll
259 ND_PORT: "80"266 ND_PORT: "80"
260 labels:267 labels:
...@@ -306,55 +313,55 @@ services:...@@ -306,55 +313,55 @@ services:
306 net.paperclover.list.domain: qbt313 net.paperclover.list.domain: qbt
307 net.paperclover.list.priority: 52314 net.paperclover.list.priority: 52
308 net.paperclover.list.access: media-manage315 net.paperclover.list.access: media-manage
309 # jackett: # port 9117316 jackett: # port 9117
310 # container_name: jackett317 container_name: jackett
311 # environment:318 environment:
312 # - "PUID=$USER_ID"319 - "PUID=$USER_ID"
313 # - "PGID=$GROUP_ID"320 - "PGID=$GROUP_ID"
314 # - "TZ=America/Los_Angelas"321 - "TZ=America/Los_Angelas"
315 # image: lscr.io/linuxserver/jackett:latest322 image: lscr.io/linuxserver/jackett:latest
316 # restart: unless-stopped323 restart: unless-stopped
317 # volumes:324 volumes:
318 # - "${APP_ROOT}/jackett:/config/Jackett"325 - "${APP_ROOT}/jackett:/config/Jackett"
319 # labels:326 labels:
320 # net.paperclover.list.name: Jackett API Adapter327 net.paperclover.list.name: Jackett API Adapter
321 # net.paperclover.list.domain: jkt328 net.paperclover.list.domain: jkt
322 # net.paperclover.list.priority: 40329 net.paperclover.list.priority: 40
323 # net.paperclover.list.access: media-manage330 net.paperclover.list.access: media-manage
324 # sonarr: # port 8989331 sonarr: # port 8989
325 # container_name: sonarr332 container_name: sonarr
326 # environment:333 environment:
327 # - "PUID=$USER_ID"334 - "PUID=$USER_ID"
328 # - "PGID=$GROUP_ID"335 - "PGID=$GROUP_ID"
329 # - "TZ=America/Los_Angelas"336 - "TZ=America/Los_Angelas"
330 # image: lscr.io/linuxserver/sonarr:latest337 image: lscr.io/linuxserver/sonarr:latest
331 # volumes:338 volumes:
332 # - "${APP_ROOT}/sonarr:/config"339 - "${APP_ROOT}/sonarr:/config"
333 # - "${TORRENT_TEMP:-${APP_ROOT}/qbittorrent/tmp}:/data/tmp"340 - "${TORRENT_TEMP:-${APP_ROOT}/qbittorrent/tmp}:/data/tmp"
334 # - "${MEDIA_ROOT}:/data/media"341 - "${MEDIA_ROOT}:/data/media"
335 # restart: unless-stopped342 restart: unless-stopped
336 # labels:343 labels:
337 # net.paperclover.list.name: Sonarr TV PVR344 net.paperclover.list.name: Sonarr TV PVR
338 # net.paperclover.list.domain: jkt345 net.paperclover.list.domain: jkt
339 # net.paperclover.list.priority: 51346 net.paperclover.list.priority: 51
340 # net.paperclover.list.access: media-manage347 net.paperclover.list.access: media-manage
341 # radarr: # port 7878348 radarr: # port 7878
342 # container_name: radarr349 container_name: radarr
343 # environment:350 environment:
344 # - "PUID=$USER_ID"351 - "PUID=$USER_ID"
345 # - "PGID=$GROUP_ID"352 - "PGID=$GROUP_ID"
346 # - "TZ=America/Los_Angelas"353 - "TZ=America/Los_Angelas"
347 # image: lscr.io/linuxserver/radarr:latest354 image: lscr.io/linuxserver/radarr:latest
348 # volumes:355 volumes:
349 # - "${APP_ROOT}/radarr:/config"356 - "${APP_ROOT}/radarr:/config"
350 # - "${TORRENT_TEMP:-${APP_ROOT}/qbittorrent/tmp}:/data/tmp"357 - "${TORRENT_TEMP:-${APP_ROOT}/qbittorrent/tmp}:/data/tmp"
351 # - "${MEDIA_ROOT}:/data/media"358 - "${MEDIA_ROOT}:/data/media"
352 # restart: unless-stopped359 restart: unless-stopped
353 # labels:360 labels:
354 # net.paperclover.list.name: Radarr Movie Organizer361 net.paperclover.list.name: Radarr Movie Organizer
355 # net.paperclover.list.domain: jkt362 net.paperclover.list.domain: rdr
356 # net.paperclover.list.priority: 50363 net.paperclover.list.priority: 50
357 # net.paperclover.list.access: media-manage364 net.paperclover.list.access: media-manage
358 # language models365 # language models
359 opencode: # port 4096366 opencode: # port 4096
360 container_name: opencode367 container_name: opencode
...@@ -554,7 +561,7 @@ services:...@@ -554,7 +561,7 @@ services:
554 net.paperclover.list.name: Open Speed Test561 net.paperclover.list.name: Open Speed Test
555 net.paperclover.list.domain: speedtest562 net.paperclover.list.domain: speedtest
556 net.paperclover.list.priority: 10563 net.paperclover.list.priority: 10
557 technitium-dns:564 technitium-dns: # port 5380
558 image: technitium/dns-server565 image: technitium/dns-server
559 container_name: technitium-dns566 container_name: technitium-dns
560 user: "$USER_ID:$GROUP_ID"567 user: "$USER_ID:$GROUP_ID"
...@@ -563,7 +570,6 @@ services:...@@ -563,7 +570,6 @@ services:
563 - 53:53/tcp570 - 53:53/tcp
564 - 67:67/udp571 - 67:67/udp
565 - 68:68/udp572 - 68:68/udp
566 - 5380:5380/tcp # Web console
567 - 8053:8053/tcp # dns over http573 - 8053:8053/tcp # dns over http
568 volumes:574 volumes:
569 - "${APP_ROOT}/technitium/config:/app/config"575 - "${APP_ROOT}/technitium/config:/app/config"
config/403.html created+5
...@@ -0,0 +1,5 @@
1no permission &lt;/3 ... <br>
2<a href="/snow.oauth2/sign_out">retry</a>
3<br>
4<br>
5contact clover for assistance...
config/Caddyfile+96-89
...@@ -1,62 +1,45 @@...@@ -1,62 +1,45 @@
1# (auth_require) {1{
2# @not_websocket not header Connection Upgrade2 admin
3# handle /snow.oauth2/* {3}
4# reverse_proxy "http://forward-auth" {4
5# header_up X-Real-IP {remote_host}5(reverse_proxy_auth) {
6# header_up X-Forwarded-Uri {uri}6 handle /snow.oauth2/* {
7# }
8# }
9#
10# handle {
11# forward_auth @not_websocket "http://forward-auth" {
12# uri /snow.oauth2/auth
13# header_up X-Real-IP {remote_host}
14# copy_headers X-Forwarded-User X-Forwarded-Groups X-Forwarded-Email
15# @error status 401
16# handle_response @error {
17# redir * /snow.oauth2/sign_in?rd={scheme}://{host}{uri}
18# }
19# }
20#
21# reverse_proxy {args[:]}
22# }
23# }
24(auth-optional) {
25 handle /snow.oauth2/* {
26 reverse_proxy "http://forward-auth" {7 reverse_proxy "http://forward-auth" {
27 header_up X-Real-IP {remote_host}8 header_up X-Real-IP {remote_host}
28 header_up X-Forwarded-Uri {uri}9 header_up X-Forwarded-Uri {uri}
29 }10 }
30 }11 }
3112 handle {
32 @not_websocket not header Connection Upgrade13 reverse_proxy "http://forward-auth" {
33 reverse_proxy @not_websocket "http://forward-auth" {14 method GET
34 method GET15 header_up X-Forwarded-Method {method}
35 rewrite /snow.oauth2/auth16 header_up X-Forwarded-Uri {uri}
3617 rewrite /snow.oauth2/auth
37 header_up X-Forwarded-Method {method}18 header_up X-Real-IP {remote_host}
38 header_up X-Forwarded-Uri {uri}19 @error status 401
3920 handle_response @error {
40 @good status 2xx21 redir * /snow.oauth2/sign_in?rd={scheme}://{host}{uri}
41 handle_response @good {22 }
42 request_header User-Id {rp.header.X-Auth-Request-User}23 @valid_group header X-Auth-Request-Groups *role:{args[1]}*
43 request_header User-Groups {rp.header.X-Auth-Request-Groups}24 handle_response @valid_group {
44 request_header User-Email {rp.header.X-Auth-Request-Email}25 method {method}
45 request_header User-Name {rp.header.X-Auth-Request-Preferred-Username}26 rewrite {uri}
46 }27 reverse_proxy {args[0]} {
47 @bad status 4xx 28 header_up Cookie ([^;]*?)\s*_oauth2_proxy_\d=[^;]*(;?.*) "$1$2"
48 handle_response @bad {29 {block}
49 request_header User-Id ""30 }
50 request_header User-Groups ""31 }
51 request_header User-Email ""32 handle_response {
52 request_header User-Name ""33 rewrite /403.html
34 file_server {
35 status 403
36 root /etc/caddy
37 }
38 }
53 }39 }
54 }40 }
55
56 reverse_proxy {args[:]}
57}41}
5842
59
60# services are sorted alphabetically43# services are sorted alphabetically
61auth.{$HOME_DOMAIN} {44auth.{$HOME_DOMAIN} {
62 handle / {45 handle / {
...@@ -70,6 +53,9 @@ dawarich.{$HOME_DOMAIN} {...@@ -70,6 +53,9 @@ dawarich.{$HOME_DOMAIN} {
70db.{$HOME_DOMAIN} {53db.{$HOME_DOMAIN} {
71 reverse_proxy "http://clover-source-of-truth"54 reverse_proxy "http://clover-source-of-truth"
72}55}
56dns.{$HOME_DOMAIN} {
57 import reverse_proxy_auth "http://technitium-dns:5380" admin
58}
73file.{$HOME_DOMAIN} {59file.{$HOME_DOMAIN} {
74 handle "/.static/*" {60 handle "/.static/*" {
75 uri strip_prefix /.static61 uri strip_prefix /.static
...@@ -82,7 +68,36 @@ file.{$HOME_DOMAIN} {...@@ -82,7 +68,36 @@ file.{$HOME_DOMAIN} {
82 root /etc/caddy/static68 root /etc/caddy/static
83 file_server69 file_server
84 }70 }
85 import auth-optional "http://copyparty"71 handle /snow.oauth2/* {
72 reverse_proxy "http://forward-auth" {
73 header_up X-Real-IP {remote_host}
74 header_up X-Forwarded-Uri {uri}
75 }
76 }
77 @should_auth not path /shr/*
78 reverse_proxy @should_auth "http://forward-auth" {
79 method GET
80 rewrite /snow.oauth2/auth
81
82 header_up X-Forwarded-Method {method}
83 header_up X-Forwarded-Uri {uri}
84
85 @good status 2xx
86 handle_response @good {
87 request_header User-Id {rp.header.X-Auth-Request-User}
88 request_header User-Groups {rp.header.X-Auth-Request-Groups}
89 request_header User-Email {rp.header.X-Auth-Request-Email}
90 request_header User-Name {rp.header.X-Auth-Request-Preferred-Username}
91 }
92 @bad status 4xx
93 handle_response @bad {
94 request_header User-Id ""
95 request_header User-Groups ""
96 request_header User-Email ""
97 request_header User-Name ""
98 }
99 }
100 reverse_proxy "http://copyparty"
86}101}
87git.{$HOME_DOMAIN} {102git.{$HOME_DOMAIN} {
88 handle /user/login {103 handle /user/login {
...@@ -94,12 +109,11 @@ git.{$HOME_DOMAIN} {...@@ -94,12 +109,11 @@ git.{$HOME_DOMAIN} {
94 }109 }
95}110}
96import ./jellyfin/Caddyfile111import ./jellyfin/Caddyfile
97# jkt.{$HOME_DOMAIN} {112jkt.{$HOME_DOMAIN} {
98# import auth113 import reverse_proxy_auth "http://jackett:9117" media-manage {
99# reverse_proxy "http://jackett:9117" {114 header_up Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
100# header_up Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="115 }
101# }116}
102# }
103music.{$HOME_DOMAIN} {117music.{$HOME_DOMAIN} {
104 handle_path /app/sw.js {118 handle_path /app/sw.js {
105 header Content-Type "application/javascript"119 header Content-Type "application/javascript"
...@@ -147,41 +161,34 @@ music.{$HOME_DOMAIN} {...@@ -147,41 +161,34 @@ music.{$HOME_DOMAIN} {
147 reverse_proxy "http://navidrome"161 reverse_proxy "http://navidrome"
148 }162 }
149} 163}
150# opencode.{$HOME_DOMAIN} {164opencode.{$HOME_DOMAIN} {
151# import auth165 import reverse_proxy_auth "http://opencode" admin
152# reverse_proxy "http://opencode"166}
153# }167pg.{$HOME_DOMAIN} {
154# pg.{$HOME_DOMAIN} {168 import reverse_proxy_auth "http://pgadmin" admin
155# import auth169}
156# reverse_proxy "http://pgadmin"170qbt.{$HOME_DOMAIN} {
157# }171 import reverse_proxy_auth "http://qbittorrent:23938" media-manage
158# qbt.{$HOME_DOMAIN} {172}
159# import auth173redis.{$HOME_DOMAIN} {
160# reverse_proxy "qbittorrent:23938"174 import reverse_proxy_auth "http://redis-insight:5540" admin
161# }175}
162# redis.{$HOME_DOMAIN} {176rdr.{$HOME_DOMAIN} {
163# import auth177 import reverse_proxy_auth "http://radarr:7878" media-manage {
164# reverse_proxy "redis-insight:5540"178 header_up Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
165# }179 }
166# rdr.{$HOME_DOMAIN} {180}
167# import auth181snr.{$HOME_DOMAIN} {
168# reverse_proxy "radarr:7878" {182 import reverse_proxy_auth "http://sonarr:8989" media-manage {
169# header_up Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="183 header_up Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
170# }184 }
171# }185}
172# snr.{$HOME_DOMAIN} {
173# import auth
174# reverse_proxy "sonarr:8989" {
175# header_up Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
176# }
177# }
178speedtest.{$HOME_DOMAIN} {186speedtest.{$HOME_DOMAIN} {
179 reverse_proxy "openspeedtest:3000"187 reverse_proxy "openspeedtest:3000"
180}188}
181# sync.{$HOME_DOMAIN} {189sync.{$HOME_DOMAIN} {
182# import auth190 import reverse_proxy_auth "http://syncthing:8384" admin
183# reverse_proxy "syncthing:8384"191}
184# }
185192
186# redirections193# redirections
187paperclover.dev {194paperclover.dev {
config/jellyfin/Caddyfile+3-2
...@@ -49,8 +49,9 @@ jelly.{$HOME_DOMAIN} {...@@ -49,8 +49,9 @@ jelly.{$HOME_DOMAIN} {
49 }49 }
5050
51 /* theme fixes */51 /* theme fixes */
52 .playlistSectionButton, .noBackdropTransparency .detailPagePrimaryContainer {52 .material-icons.play_arrow { display: flex }
53 background: rgb(from var(--main-background) r g b / 50%;53 .detailPagePrimaryContainer {
54 background: rgb(from var(--main-background) r g b / 75%)!;
54 }55 }
55 .selectLabel {56 .selectLabel {
56 display: flex;57 display: flex;
config/keycloak/init.py+1-1
...@@ -19,7 +19,7 @@ def env(key: str):...@@ -19,7 +19,7 @@ def env(key: str):
19 return val19 return val
2020
2121
22groups_to_create = ["snow", "media", "media-manage", "git", "file"]22groups_to_create = ["snow", "media-manage"]
23realm_config = {23realm_config = {
24 "realm": "master",24 "realm": "master",
25 "displayName": "snow sign on",25 "displayName": "snow sign on",