servo: nginx: split uninsane.org out of main config file
This commit is contained in:
@@ -1,18 +1,10 @@
|
|||||||
# docs: <https://nixos.wiki/wiki/Nginx>
|
# docs: <https://nixos.wiki/wiki/Nginx>
|
||||||
# docs: <https://nginx.org/en/docs/>
|
# docs: <https://nginx.org/en/docs/>
|
||||||
{ config, lib, pkgs, ... }:
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
# make the logs for this host "public" so that they show up in e.g. metrics
|
|
||||||
publog = vhost: lib.attrsets.unionOfDisjoint vhost {
|
|
||||||
extraConfig = (vhost.extraConfig or "") + ''
|
|
||||||
access_log /var/log/nginx/public.log vcombined;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# kTLS = true; # in-kernel TLS for better perf
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
./uninsane.org.nix
|
||||||
|
];
|
||||||
|
|
||||||
sane.ports.ports."80" = {
|
sane.ports.ports."80" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
@@ -61,141 +53,8 @@ in
|
|||||||
# enables sendfile, tcp_nopush, tcp_nodelay, keepalive_timeout 65
|
# enables sendfile, tcp_nopush, tcp_nodelay, keepalive_timeout 65
|
||||||
services.nginx.recommendedOptimisation = true;
|
services.nginx.recommendedOptimisation = true;
|
||||||
|
|
||||||
# web blog/personal site
|
|
||||||
# alternative way to link stuff into the share:
|
|
||||||
# sane.fs."/var/www/sites/uninsane.org/share/Ubunchu".mount.bind = "/var/media/Books/Visual/HiroshiSeo/Ubunchu";
|
|
||||||
# sane.fs."/var/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
|
||||||
services.nginx.virtualHosts."uninsane.org" = publog {
|
|
||||||
# a lot of places hardcode https://uninsane.org,
|
|
||||||
# and then when we mix http + non-https, we get CORS violations
|
|
||||||
# and things don't look right. so force SSL.
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
# for OCSP stapling
|
|
||||||
sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
|
||||||
|
|
||||||
locations."/" = {
|
# serve any site not otherwise declared, if it's static.
|
||||||
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
|
|
||||||
tryFiles = "$uri $uri/ @fallback";
|
|
||||||
};
|
|
||||||
|
|
||||||
# unversioned files
|
|
||||||
locations."@fallback" = {
|
|
||||||
root = "/var/www/sites/uninsane.org";
|
|
||||||
extraConfig = ''
|
|
||||||
# instruct Google to not index these pages.
|
|
||||||
# see: <https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#xrobotstag>
|
|
||||||
add_header X-Robots-Tag 'none, noindex, nofollow';
|
|
||||||
|
|
||||||
# best-effort attempt to block archive.org from archiving these pages.
|
|
||||||
# reply with 403: Forbidden
|
|
||||||
# User Agent is *probably* "archive.org_bot"; maybe used to be "ia_archiver"
|
|
||||||
# source: <https://archive.org/details/archive.org_bot>
|
|
||||||
# additional UAs: <https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker>
|
|
||||||
#
|
|
||||||
# validate with: `curl -H 'User-Agent: "bot;archive.org_bot;like: something else"' -v https://uninsane.org/dne`
|
|
||||||
if ($http_user_agent ~* "(?:\b)archive.org_bot(?:\b)") {
|
|
||||||
return 403;
|
|
||||||
}
|
|
||||||
if ($http_user_agent ~* "(?:\b)archive.org(?:\b)") {
|
|
||||||
return 403;
|
|
||||||
}
|
|
||||||
if ($http_user_agent ~* "(?:\b)ia_archiver(?:\b)") {
|
|
||||||
return 403;
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# uninsane.org/share/foo => /var/www/sites/uninsane.org/share/foo.
|
|
||||||
# special-cased to enable directory listings
|
|
||||||
locations."/share" = {
|
|
||||||
root = "/var/www/sites/uninsane.org";
|
|
||||||
extraConfig = ''
|
|
||||||
# autoindex => render directory listings
|
|
||||||
autoindex on;
|
|
||||||
# don't follow any symlinks when serving files
|
|
||||||
# otherwise it allows a directory escape
|
|
||||||
disable_symlinks on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
locations."/share/Milkbags/" = {
|
|
||||||
alias = "/var/media/Videos/Milkbags/";
|
|
||||||
extraConfig = ''
|
|
||||||
# autoindex => render directory listings
|
|
||||||
autoindex on;
|
|
||||||
# don't follow any symlinks when serving files
|
|
||||||
# otherwise it allows a directory escape
|
|
||||||
disable_symlinks on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
locations."/share/Ubunchu/" = {
|
|
||||||
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
|
||||||
extraConfig = ''
|
|
||||||
# autoindex => render directory listings
|
|
||||||
autoindex on;
|
|
||||||
# don't follow any symlinks when serving files
|
|
||||||
# otherwise it allows a directory escape
|
|
||||||
disable_symlinks on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
|
||||||
locations."= /.well-known/matrix/server".extraConfig =
|
|
||||||
let
|
|
||||||
# use 443 instead of the default 8448 port to unite
|
|
||||||
# the client-server and server-server port for simplicity
|
|
||||||
server = { "m.server" = "matrix.uninsane.org:443"; };
|
|
||||||
in ''
|
|
||||||
add_header Content-Type application/json;
|
|
||||||
return 200 '${builtins.toJSON server}';
|
|
||||||
'';
|
|
||||||
locations."= /.well-known/matrix/client".extraConfig =
|
|
||||||
let
|
|
||||||
client = {
|
|
||||||
"m.homeserver" = { "base_url" = "https://matrix.uninsane.org"; };
|
|
||||||
"m.identity_server" = { "base_url" = "https://vector.im"; };
|
|
||||||
};
|
|
||||||
# ACAO required to allow element-web on any URL to request this json file
|
|
||||||
in ''
|
|
||||||
add_header Content-Type application/json;
|
|
||||||
add_header Access-Control-Allow-Origin *;
|
|
||||||
return 200 '${builtins.toJSON client}';
|
|
||||||
'';
|
|
||||||
|
|
||||||
# static URLs might not be aware of .well-known (e.g. registration confirmation URLs),
|
|
||||||
# so hack around that.
|
|
||||||
locations."/_matrix" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8008";
|
|
||||||
};
|
|
||||||
locations."/_synapse" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8008";
|
|
||||||
};
|
|
||||||
|
|
||||||
# allow ActivityPub clients to discover how to reach @user@uninsane.org
|
|
||||||
# see: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
|
||||||
# not sure this makes sense while i run multiple AP services (pleroma, lemmy)
|
|
||||||
# locations."/.well-known/nodeinfo" = {
|
|
||||||
# proxyPass = "http://127.0.0.1:4000";
|
|
||||||
# extraConfig = pleromaExtraConfig;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# redirect common feed URIs to the canonical feed
|
|
||||||
locations."= /atom".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /feed".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /feed.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /rss".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /rss.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/atom".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/atom.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/feed".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/feed.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/rss".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/rss.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
# serve any site not listed above, if it's static.
|
|
||||||
# because we define it dynamically, SSL isn't trivial. support only http
|
# because we define it dynamically, SSL isn't trivial. support only http
|
||||||
# documented <https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name>
|
# documented <https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name>
|
||||||
services.nginx.virtualHosts."~^(?<domain>.+)$" = {
|
services.nginx.virtualHosts."~^(?<domain>.+)$" = {
|
||||||
@@ -230,28 +89,6 @@ in
|
|||||||
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
# let's encrypt default chain looks like:
|
|
||||||
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
|
||||||
# - <https://community.letsencrypt.org/t/production-chain-changes/150739>
|
|
||||||
# DST Root CA X3 expired in 2021 (?)
|
|
||||||
# the alternative chain is:
|
|
||||||
# - End-entity certificate ← R3 ← ISRG Root X1 (self-signed)
|
|
||||||
# using this alternative chain grants more compatibility for services like ejabberd
|
|
||||||
# but might decrease compatibility with very old clients that don't get updates (e.g. old android, iphone <= 4).
|
|
||||||
# security.acme.defaults.extraLegoFlags = [
|
|
||||||
security.acme.certs."uninsane.org" = rec {
|
|
||||||
# ISRG Root X1 results in lets encrypt sending the same chain as default,
|
|
||||||
# just without the final ISRG Root X1 ← DST Root CA X3 link.
|
|
||||||
# i.e. we could alternative clip the last item and achieve the exact same thing.
|
|
||||||
extraLegoRunFlags = [
|
|
||||||
"--preferred-chain" "ISRG Root X1"
|
|
||||||
];
|
|
||||||
extraLegoRenewFlags = extraLegoRunFlags;
|
|
||||||
};
|
|
||||||
# TODO: alternatively, we could clip the last cert IF it's expired,
|
|
||||||
# optionally outputting that to a new cert file.
|
|
||||||
# security.acme.defaults.postRun = "";
|
|
||||||
|
|
||||||
# create a self-signed SSL certificate for use with literally any domain.
|
# create a self-signed SSL certificate for use with literally any domain.
|
||||||
# browsers will reject this, but proxies and local testing tools can be configured
|
# browsers will reject this, but proxies and local testing tools can be configured
|
||||||
# to accept it.
|
# to accept it.
|
||||||
|
165
hosts/by-name/servo/services/nginx/uninsane.org.nix
Normal file
165
hosts/by-name/servo/services/nginx/uninsane.org.nix
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
# "public" log so requests show up in metrics
|
||||||
|
logfile = "/var/log/nginx/public.log";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# web blog/personal site
|
||||||
|
# alternative way to link stuff into the share:
|
||||||
|
# sane.fs."/var/www/sites/uninsane.org/share/Ubunchu".mount.bind = "/var/media/Books/Visual/HiroshiSeo/Ubunchu";
|
||||||
|
# sane.fs."/var/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
||||||
|
services.nginx.virtualHosts."uninsane.org" = {
|
||||||
|
# a lot of places hardcode https://uninsane.org,
|
||||||
|
# and then when we mix http + non-https, we get CORS violations
|
||||||
|
# and things don't look right. so force SSL.
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
# for OCSP stapling
|
||||||
|
sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||||
|
|
||||||
|
extraConfig = ''
|
||||||
|
access_log ${logfile} vcombined;
|
||||||
|
'';
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
|
||||||
|
tryFiles = "$uri $uri/ @fallback";
|
||||||
|
};
|
||||||
|
|
||||||
|
# unversioned files
|
||||||
|
locations."@fallback" = {
|
||||||
|
root = "/var/www/sites/uninsane.org";
|
||||||
|
extraConfig = ''
|
||||||
|
# instruct Google to not index these pages.
|
||||||
|
# see: <https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#xrobotstag>
|
||||||
|
add_header X-Robots-Tag 'none, noindex, nofollow';
|
||||||
|
|
||||||
|
# best-effort attempt to block archive.org from archiving these pages.
|
||||||
|
# reply with 403: Forbidden
|
||||||
|
# User Agent is *probably* "archive.org_bot"; maybe used to be "ia_archiver"
|
||||||
|
# source: <https://archive.org/details/archive.org_bot>
|
||||||
|
# additional UAs: <https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker>
|
||||||
|
#
|
||||||
|
# validate with: `curl -H 'User-Agent: "bot;archive.org_bot;like: something else"' -v https://uninsane.org/dne`
|
||||||
|
if ($http_user_agent ~* "(?:\b)archive.org_bot(?:\b)") {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
if ($http_user_agent ~* "(?:\b)archive.org(?:\b)") {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
if ($http_user_agent ~* "(?:\b)ia_archiver(?:\b)") {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# uninsane.org/share/foo => /var/www/sites/uninsane.org/share/foo.
|
||||||
|
# special-cased to enable directory listings
|
||||||
|
locations."/share" = {
|
||||||
|
root = "/var/www/sites/uninsane.org";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
locations."/share/Milkbags/" = {
|
||||||
|
alias = "/var/media/Videos/Milkbags/";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
locations."/share/Ubunchu/" = {
|
||||||
|
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
||||||
|
locations."= /.well-known/matrix/server".extraConfig =
|
||||||
|
let
|
||||||
|
# use 443 instead of the default 8448 port to unite
|
||||||
|
# the client-server and server-server port for simplicity
|
||||||
|
server = { "m.server" = "matrix.uninsane.org:443"; };
|
||||||
|
in ''
|
||||||
|
add_header Content-Type application/json;
|
||||||
|
return 200 '${builtins.toJSON server}';
|
||||||
|
'';
|
||||||
|
locations."= /.well-known/matrix/client".extraConfig =
|
||||||
|
let
|
||||||
|
client = {
|
||||||
|
"m.homeserver" = { "base_url" = "https://matrix.uninsane.org"; };
|
||||||
|
"m.identity_server" = { "base_url" = "https://vector.im"; };
|
||||||
|
};
|
||||||
|
# ACAO required to allow element-web on any URL to request this json file
|
||||||
|
in ''
|
||||||
|
add_header Content-Type application/json;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
return 200 '${builtins.toJSON client}';
|
||||||
|
'';
|
||||||
|
|
||||||
|
# static URLs might not be aware of .well-known (e.g. registration confirmation URLs),
|
||||||
|
# so hack around that.
|
||||||
|
locations."/_matrix" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8008";
|
||||||
|
};
|
||||||
|
locations."/_synapse" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8008";
|
||||||
|
};
|
||||||
|
|
||||||
|
# allow ActivityPub clients to discover how to reach @user@uninsane.org
|
||||||
|
# see: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
||||||
|
# not sure this makes sense while i run multiple AP services (pleroma, lemmy)
|
||||||
|
# locations."/.well-known/nodeinfo" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:4000";
|
||||||
|
# extraConfig = pleromaExtraConfig;
|
||||||
|
# };
|
||||||
|
|
||||||
|
# redirect common feed URIs to the canonical feed
|
||||||
|
locations."= /atom".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /feed".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /rss".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/atom".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/atom.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/feed".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/rss".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
};
|
||||||
|
|
||||||
|
# let's encrypt default chain looks like:
|
||||||
|
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
||||||
|
# - <https://community.letsencrypt.org/t/production-chain-changes/150739>
|
||||||
|
# DST Root CA X3 expired in 2021 (?)
|
||||||
|
# the alternative chain is:
|
||||||
|
# - End-entity certificate ← R3 ← ISRG Root X1 (self-signed)
|
||||||
|
# using this alternative chain grants more compatibility for services like ejabberd
|
||||||
|
# but might decrease compatibility with very old clients that don't get updates (e.g. old android, iphone <= 4).
|
||||||
|
# security.acme.defaults.extraLegoFlags = [
|
||||||
|
security.acme.certs."uninsane.org" = rec {
|
||||||
|
# ISRG Root X1 results in lets encrypt sending the same chain as default,
|
||||||
|
# just without the final ISRG Root X1 ← DST Root CA X3 link.
|
||||||
|
# i.e. we could alternatively clip the last item and achieve the exact same thing.
|
||||||
|
extraLegoRunFlags = [
|
||||||
|
"--preferred-chain" "ISRG Root X1"
|
||||||
|
];
|
||||||
|
extraLegoRenewFlags = extraLegoRunFlags;
|
||||||
|
};
|
||||||
|
# TODO: alternatively, we could clip the last cert IF it's expired,
|
||||||
|
# optionally outputting that to a new cert file.
|
||||||
|
# security.acme.defaults.postRun = "";
|
||||||
|
}
|
Reference in New Issue
Block a user