cmc/dotfiles

Using GNU Stow to manage my dotfiles. config dotfiles macos stow

Commit 263f281b30

263f281b30ac0f7daaf654e2e9abee71f9d80709

parent: 3d0c165f49

Verified · cmc

cmc <hello@cleberg.net> · 2026-08-03 17:03 UTC

fix security headers for new vhosts

Layout: unified · split

linux/nginx/etc/nginx/conf.d/i.conf +13
@@ -1,9 +1,22 @@
1server { 1server {
2 listen 127.0.0.1:10048; 2 listen 127.0.0.1:10048;
3 server_name i.krz.sh; 3 server_name i.krz.sh;
4 add_header Onion-Location "http://j42zbkbxrdx4mvkyutt7jiwpucgcmrdvaelwcwmgwn3mzus2v6x3toad.onion$request_uri" always;
4 include custom.d/basic.conf; 5 include custom.d/basic.conf;
5 include custom.d/security/content-security-policy.conf; 6 include custom.d/security/content-security-policy.conf;
6 root /var/www/i/; 7 root /var/www/i/;
7 autoindex on; 8 autoindex on;
8 location / { try_files $uri $uri/ =404; } 9 location / { try_files $uri $uri/ =404; }
9} 10}
11
12# Onion counterpart of i.krz.sh. Reached via tor -> 127.0.0.1:10049, so it
13# never transits Cloudflare; nginx is the only thing setting headers here.
14server {
15 listen 127.0.0.1:10049;
16 server_name j42zbkbxrdx4mvkyutt7jiwpucgcmrdvaelwcwmgwn3mzus2v6x3toad.onion;
17 include custom.d/basic.conf;
18 include custom.d/security/content-security-policy.conf;
19 root /var/www/i/;
20 autoindex on;
21 location / { try_files $uri $uri/ =404; }
22}
linux/nginx/etc/nginx/conf.d/i.conf.bak-i-onion added +9
@@ -0,0 +1,9 @@
1server {
2 listen 127.0.0.1:10048;
3 server_name i.krz.sh;
4 include custom.d/basic.conf;
5 include custom.d/security/content-security-policy.conf;
6 root /var/www/i/;
7 autoindex on;
8 location / { try_files $uri $uri/ =404; }
9}
linux/nginx/etc/nginx/conf.d/krz.sh.conf +1
@@ -4,5 +4,6 @@ server {
4 root /var/www/krz.sh/; 4 root /var/www/krz.sh/;
5 absolute_redirect off; 5 absolute_redirect off;
6 include custom.d/basic.conf; 6 include custom.d/basic.conf;
7 include custom.d/security/content-security-policy-krz.conf;
7 location / { try_files $uri $uri/ =404; } 8 location / { try_files $uri $uri/ =404; }
8} 9}
linux/nginx/etc/nginx/custom.d/http/content_type_maps.conf +19 −2
@@ -50,7 +50,7 @@ map $sent_http_content_type $x_frame_options {
50# literal newlines, which nginx emitted verbatim -- a folded, malformed header 50# literal newlines, which nginx emitted verbatim -- a folded, malformed header
51# that clients saw as empty. Policies must be ONE line. 51# that clients saw as empty. Policies must be ONE line.
52map $sent_http_content_type $content_security_policy { 52map $sent_http_content_type $content_security_policy {
53 ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' data:; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; upgrade-insecure-requests"; 53 ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' data:; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'";
54} 54}
55 55
56# cleberg.* only. Mirrors what the site actually loads, verified by grepping 56# cleberg.* only. Mirrors what the site actually loads, verified by grepping
@@ -69,6 +69,23 @@ map $sent_http_content_type $content_security_policy_cmc {
69 ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' https://img.cleberg.net data:; script-src 'self' https://bubbles.town; connect-src 'self' https://bubbles.town; style-src 'self' https://cleberg.net; font-src 'self' https://cleberg.net; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'"; 69 ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' https://img.cleberg.net data:; script-src 'self' https://bubbles.town; connect-src 'self' https://bubbles.town; style-src 'self' https://cleberg.net; font-src 'self' https://cleberg.net; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'";
70} 70}
71 71
72# krz.sh only. Derived from the served HTML after the img.cleberg.net removal
73# (2026-08-03), counted with an HTML parser:
74# 14 <img src> -> https://i.krz.sh (the new krz-side image host)
75# 12 <link rel=stylesheet> -> https://krz.sh (ABSOLUTE, not relative)
76# 12 <link rel=icon> -> https://krz.sh (covered by img-src)
77# 0 scripts, inline or external; 0 inline styles.
78#
79# `https://krz.sh` is listed explicitly because those URLs are absolute: on a
80# future krz.sh onion they would be cross-origin and 'self' would block them.
81# Same reasoning as the cmc policy above.
82#
83# script-src stays 'self' rather than 'none': the site ships no scripts today,
84# but 'none' would break the first one added, in a way that is easy to misread.
85map $sent_http_content_type $content_security_policy_krz {
86 ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' https://krz.sh https://i.krz.sh data:; style-src 'self' https://krz.sh; font-src 'self' https://krz.sh; script-src 'self'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'";
87}
88
72# For apps that ship inline <script>/<style>/style="" and cannot use the strict 89# For apps that ship inline <script>/<style>/style="" and cannot use the strict
73# policy. Currently only office.zerolabs.sh (5 files with inline <script>, 90# policy. Currently only office.zerolabs.sh (5 files with inline <script>,
74# 3 with <style>, 2 with style attributes). Identity-neutral -- no host is 91# 3 with <style>, 2 with style attributes). Identity-neutral -- no host is
@@ -79,7 +96,7 @@ map $sent_http_content_type $content_security_policy_cmc {
79# strictly worse. The upgrade path is per-file hashes or nonces; that needs 96# strictly worse. The upgrade path is per-file hashes or nonces; that needs
80# changes to the app, not to nginx. 97# changes to the app, not to nginx.
81map $sent_http_content_type $content_security_policy_inline { 98map $sent_http_content_type $content_security_policy_inline {
82 ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; upgrade-insecure-requests"; 99 ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'";
83} 100}
84 101
85# --- Proxied third-party apps ------------------------------------------- 102# --- Proxied third-party apps -------------------------------------------
linux/nginx/etc/nginx/custom.d/security/content-security-policy-krz.conf added +10
@@ -0,0 +1,10 @@
1# Content-Security-Policy for krz.sh itself.
2#
3# Uses $content_security_policy_krz, which names https://i.krz.sh (the krz-side
4# image host) and https://krz.sh (its own absolute asset URLs). Both are `krz`
5# surfaces, so this stays identity-clean -- it names no `cleberg` host.
6#
7# Other krz vhosts should use custom.d/security/content-security-policy.conf
8# (the strict neutral one); this variant exists only because krz.sh loads
9# cross-origin images and uses absolute self-URLs.
10add_header Content-Security-Policy $content_security_policy_krz always;