wow
This commit is contained in:
commit
5a58e0e55b
8 changed files with 84 additions and 1235 deletions
|
|
@ -6,6 +6,34 @@
|
|||
let
|
||||
nr = import "${inputs.self}/modules/mizukios/features/packages/nr.nix" { inherit pkgs; };
|
||||
nrr = import "${inputs.self}/modules/mizukios/features/packages/nrr.nix" { inherit pkgs; };
|
||||
concord = pkgs.writeShellScriptBin "concord" ''
|
||||
set -eu
|
||||
|
||||
runtime_dir="''${XDG_RUNTIME_DIR:-/tmp}"
|
||||
session_dir="$(mktemp -d "$runtime_dir/concord-session.XXXXXX")"
|
||||
|
||||
cleanup() {
|
||||
rm -rf -- "$session_dir"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
trap 'exit 129' HUP
|
||||
trap 'exit 130' INT
|
||||
trap 'exit 143' TERM
|
||||
|
||||
config_home="$session_dir/config"
|
||||
state_home="$session_dir/state"
|
||||
mkdir -p "$config_home" "$state_home"
|
||||
|
||||
cat > "$config_home/config.toml" <<'EOF'
|
||||
[credentials]
|
||||
store = "plain"
|
||||
EOF
|
||||
|
||||
XDG_CONFIG_HOME="$config_home" \
|
||||
XDG_STATE_HOME="$state_home" \
|
||||
"${inputs.concord.packages.${pkgs.system}.default}/bin/concord" "$@"
|
||||
'';
|
||||
in
|
||||
{
|
||||
home.stateVersion = "26.05";
|
||||
|
|
@ -13,6 +41,7 @@ in
|
|||
home.homeDirectory = "/home/imnyang";
|
||||
|
||||
home.packages = [
|
||||
concord
|
||||
nr
|
||||
nrr
|
||||
];
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ let
|
|||
'';
|
||||
};
|
||||
|
||||
# These were previously served by *.imnya.ng. Listing them explicitly lets
|
||||
# stock Caddy obtain an individual certificate without a DNS challenge.
|
||||
# Keep these explicit hosts for their existing per-host content. The
|
||||
# wildcard host below handles any other one-level subdomain.
|
||||
staticHosts = [
|
||||
"26layer7beginner.imnya.ng"
|
||||
"alt.imnya.ng"
|
||||
|
|
@ -149,7 +149,20 @@ in
|
|||
enable = true;
|
||||
email = "imnyang@pm.me";
|
||||
openFirewall = true;
|
||||
package = pkgs.caddy;
|
||||
package = pkgs.caddy.withPlugins {
|
||||
plugins = [
|
||||
"github.com/caddy-dns/cloudflare@v0.2.4"
|
||||
"github.com/aksdb/caddy-cgi/v2@v2.2.6"
|
||||
"github.com/shift72/caddy-geo-ip@v0.6.0"
|
||||
"github.com/lolPants/caddy-requestid@v1.1.2"
|
||||
"github.com/WeidiDeng/caddy-cloudflare-ip@v0.0.0-20231130002422-f53b62aa13cb"
|
||||
"github.com/caddyserver/ntlm-transport@v0.1.2"
|
||||
"github.com/ueffel/caddy-brotli@v1.6.0"
|
||||
"github.com/RussellLuo/caddy-ext/ratelimit@v0.3.0"
|
||||
"github.com/neodyme-labs/user_agent_parse@v0.0.1"
|
||||
];
|
||||
hash = "sha256-r4MgRk8HpKYx7f8FmA3PKgD/5ZNTIHpQvlE+zRbP0lw=";
|
||||
};
|
||||
|
||||
globalConfig = ''
|
||||
admin unix//run/caddy/admin.socket
|
||||
|
|
@ -170,6 +183,15 @@ in
|
|||
}) staticHosts
|
||||
)
|
||||
// {
|
||||
"*.imnya.ng".extraConfig = withErrors ''
|
||||
tls {
|
||||
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
|
||||
}
|
||||
|
||||
root * /var/static/{host}
|
||||
file_server
|
||||
'';
|
||||
|
||||
"api.imnya.ng".extraConfig = reverseProxyWithHeaders "127.0.0.1:10118";
|
||||
"docs.imnya.ng".extraConfig = reverseProxy "100.70.1.1:3939";
|
||||
"panel.imnya.ng".extraConfig = reverseProxy "127.0.0.1:32981";
|
||||
|
|
@ -372,6 +394,9 @@ in
|
|||
requires = [ "mnt-static.mount" ];
|
||||
after = [ "mnt-static.mount" "systemd-tmpfiles-setup.service" ];
|
||||
serviceConfig = {
|
||||
# Keep the manually provisioned token outside NixOS-managed /etc.
|
||||
# /var/lib/caddy is persistent across system generations.
|
||||
EnvironmentFile = "/var/lib/caddy/cloudflare.env";
|
||||
RuntimeDirectory = "caddy";
|
||||
RuntimeDirectoryMode = "0755";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@
|
|||
DISABLE_REGISTRATION = false;
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
|
||||
ENABLE_CAPTCHA = false;
|
||||
REQUIRE_SIGNIN_VIEW = false;
|
||||
REQUIRE_SIGNIN_VIEW = lib.mkForce false;
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false;
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true;
|
||||
DEFAULT_ENABLE_TIMETRACKING = true;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
let
|
||||
inherit (config.virtualisation.quadlet) containers networks;
|
||||
authentikVersion = "2026.5.6";
|
||||
authentikEnv = config.sops.secrets."containers/authentik.env".path;
|
||||
outpostEnv = config.sops.secrets."containers/authentik-outpost.env".path;
|
||||
in
|
||||
|
|
@ -53,7 +54,7 @@ in
|
|||
|
||||
authentik-server = {
|
||||
containerConfig = {
|
||||
image = "ghcr.io/goauthentik/server:2026.5.0";
|
||||
image = "ghcr.io/goauthentik/server:${authentikVersion}";
|
||||
exec = "server";
|
||||
networks = [ networks.authentik.ref ];
|
||||
publishPorts = [
|
||||
|
|
@ -65,6 +66,11 @@ in
|
|||
"/home/imnyang/Docker/authentik/custom-templates:/templates:Z"
|
||||
];
|
||||
environmentFiles = [ authentikEnv ];
|
||||
environments = {
|
||||
# Authentik 2026.5 defaults to [::], but hako is reached over IPv4.
|
||||
AUTHENTIK_LISTEN__HTTP = "0.0.0.0:9000";
|
||||
AUTHENTIK_LISTEN__HTTPS = "0.0.0.0:9443";
|
||||
};
|
||||
};
|
||||
|
||||
unitConfig = {
|
||||
|
|
@ -77,7 +83,7 @@ in
|
|||
|
||||
authentik-worker = {
|
||||
containerConfig = {
|
||||
image = "ghcr.io/goauthentik/server:2026.5.0";
|
||||
image = "ghcr.io/goauthentik/server:${authentikVersion}";
|
||||
exec = "worker";
|
||||
user = "root";
|
||||
networks = [ networks.authentik.ref ];
|
||||
|
|
@ -85,9 +91,11 @@ in
|
|||
"/home/imnyang/Docker/authentik/certs:/certs:Z"
|
||||
"/home/imnyang/Docker/authentik/media:/media:Z"
|
||||
"/home/imnyang/Docker/authentik/custom-templates:/templates:Z"
|
||||
"/var/run/docker.sock:/var/run/docker.sock"
|
||||
];
|
||||
environmentFiles = [ authentikEnv ];
|
||||
environments = {
|
||||
AUTHENTIK_LISTEN__HTTP = "0.0.0.0:9000";
|
||||
};
|
||||
};
|
||||
|
||||
unitConfig = {
|
||||
|
|
@ -100,7 +108,7 @@ in
|
|||
|
||||
authentik-outpost-ldap = {
|
||||
containerConfig = {
|
||||
image = "ghcr.io/goauthentik/ldap:2026.5.0";
|
||||
image = "ghcr.io/goauthentik/ldap:${authentikVersion}";
|
||||
entrypoint = [ "/ldap" ];
|
||||
user = "1000";
|
||||
networks = [ networks.authentik.ref ];
|
||||
|
|
@ -109,6 +117,15 @@ in
|
|||
"636:6636"
|
||||
];
|
||||
environmentFiles = [ outpostEnv ];
|
||||
environments = {
|
||||
# Keep the outpost-to-core API traffic on the private Podman network.
|
||||
# The public hostname resolves through Cloudflare and hairpins back
|
||||
# through the reverse proxy, which currently returns 502 from hako.
|
||||
AUTHENTIK_HOST = "http://authentik-server:9000";
|
||||
AUTHENTIK_INSECURE = "true";
|
||||
AUTHENTIK_LISTEN__LDAP = "0.0.0.0:3389";
|
||||
AUTHENTIK_LISTEN__LDAPS = "0.0.0.0:6636";
|
||||
};
|
||||
};
|
||||
|
||||
unitConfig = {
|
||||
|
|
|
|||
|
|
@ -1,95 +1,4 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
streamPlayer = pkgs.writeTextDir "index.html" ''
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Mizuki Stream</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100%;
|
||||
background: #0d0f12;
|
||||
color: #f5f3ee;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
main {
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr auto;
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 72px);
|
||||
aspect-ratio: 16 / 9;
|
||||
align-self: center;
|
||||
background: #000;
|
||||
border: 1px solid #2f343c;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
color: #a9acb3;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
code {
|
||||
color: #f5f3ee;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<video id="video" controls autoplay playsinline></video>
|
||||
<footer>
|
||||
<span id="stream"></span>
|
||||
<code>rtmp://stream.mizuki.guru:1935/live</code>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
|
||||
<script>
|
||||
var video = document.getElementById("video");
|
||||
var label = document.getElementById("stream");
|
||||
var match = window.location.pathname.match(/^\/play\/([^/]+)\/?$/);
|
||||
var name = match ? decodeURIComponent(match[1]) : "stream";
|
||||
var source = "https://stream.mizuki.guru/live/" + name + "/" + name + ".m3u8";
|
||||
|
||||
label.textContent = source;
|
||||
|
||||
if (video.canPlayType("application/vnd.apple.mpegurl")) {
|
||||
video.src = source;
|
||||
video.play();
|
||||
} else if (Hls.isSupported()) {
|
||||
var hls = new Hls();
|
||||
hls.loadSource(source);
|
||||
hls.attachMedia(video);
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
video.play();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'';
|
||||
in
|
||||
{
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
|
|
@ -182,25 +91,8 @@ in
|
|||
reverse_proxy 127.0.0.1:31774
|
||||
'';
|
||||
|
||||
virtualHosts."stream.mizuki.guru".extraConfig = ''
|
||||
handle /live/* {
|
||||
reverse_proxy 127.0.0.1:10023
|
||||
}
|
||||
|
||||
handle /play/* {
|
||||
root * ${streamPlayer}
|
||||
rewrite * /index.html
|
||||
file_server
|
||||
}
|
||||
|
||||
handle / {
|
||||
root * ${streamPlayer}
|
||||
file_server
|
||||
}
|
||||
|
||||
handle {
|
||||
respond "Not Found" 404
|
||||
}
|
||||
virtualHosts."pass.imnya.ng".extraConfig = ''
|
||||
reverse_proxy 127.0.0.1:10302
|
||||
'';
|
||||
|
||||
virtualHosts."netbird.mizuki.guru".extraConfig = ''
|
||||
|
|
|
|||
Loading…
Reference in a new issue