Kieran's opinionated (and probably slightly dumb) nix config

feat: add 404 page

dunkirk.sh 9ac7236a 0ff93cd1

verified
Changed files
+119 -25
modules
nixos
+97
modules/nixos/services/bore/404.html
···
+
<!DOCTYPE html>
+
<html lang="en">
+
+
<head>
+
<meta charset="UTF-8">
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
<title>404 - bore</title>
+
<link rel="icon"
+
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🚇</text></svg>">
+
<style>
+
* {
+
margin: 0;
+
padding: 0;
+
box-sizing: border-box;
+
}
+
+
body {
+
font-family: 'SF Mono', 'Monaco', monospace;
+
background: #0d1117;
+
color: #e6edf3;
+
min-height: 100vh;
+
display: flex;
+
align-items: center;
+
justify-content: center;
+
padding: 2rem;
+
}
+
+
.container {
+
text-align: center;
+
max-width: 600px;
+
}
+
+
.error-code {
+
font-size: 8rem;
+
font-weight: 700;
+
color: #8b949e;
+
line-height: 1;
+
margin-bottom: 1rem;
+
}
+
+
.emoji {
+
font-size: 4rem;
+
margin-bottom: 2rem;
+
opacity: 0.5;
+
}
+
+
h1 {
+
font-size: 2rem;
+
margin-bottom: 1rem;
+
color: #e6edf3;
+
}
+
+
p {
+
color: #8b949e;
+
font-size: 1rem;
+
margin-bottom: 2rem;
+
line-height: 1.6;
+
}
+
+
.countdown {
+
color: #14b8a6;
+
font-size: 1.2rem;
+
font-weight: 600;
+
font-variant-numeric: tabular-nums;
+
}
+
</style>
+
</head>
+
+
<body>
+
<div class="container">
+
<div class="emoji">🚇</div>
+
<div class="error-code">404</div>
+
<h1>wrong stop!</h1>
+
<p>this tunnel doesn't go anywhere. maybe it was never built, or perhaps it collapsed?</p>
+
<p>redirecting in <span class="countdown" id="countdown">5.000</span>s</p>
+
</div>
+
+
<script>
+
let timeLeft = 5000; // 5 seconds in milliseconds
+
const countdownEl = document.getElementById('countdown');
+
const startTime = Date.now();
+
+
const interval = setInterval(() => {
+
const elapsed = Date.now() - startTime;
+
timeLeft = Math.max(0, 5000 - elapsed);
+
+
countdownEl.textContent = (timeLeft / 1000).toFixed(3);
+
+
if (timeLeft <= 0) {
+
clearInterval(interval);
+
window.location.href = 'https://bore.dunkirk.sh';
+
}
+
}, 10); // Update every 10ms for smooth countdown
+
</script>
+
</body>
+
+
</html>
+11 -25
modules/nixos/services/bore/dashboard.html
···
flex-direction: column;
}
+
body.loading .container {
+
opacity: 0;
+
}
+
.container {
max-width: 1200px;
margin: 0 auto;
flex: 1;
width: 100%;
+
opacity: 1;
+
transition: opacity 0.3s ease-in-out;
}
header {
···
.tunnel-url a {
color: #14b8a6;
text-decoration: none;
-
cursor: pointer;
-
user-select: all;
}
.tunnel-url a:hover {
text-decoration: underline;
}
-
.tunnel-url a:active {
-
color: #fb923c;
-
}
-
.tunnel-status {
padding: 0.25rem 0.75rem;
border-radius: 0;
···
</style>
</head>
-
<body>
+
<body class="loading">
<main class="container">
<header>
<h1>🚇 bore</h1>
···
<div class="tunnel-info">
<div class="tunnel-name">${proxy.name || 'unnamed'}</div>
<div class="tunnel-url">
-
<a href="${url}" target="_blank" ondblclick="copyToClipboard(event, '${url}')">${url}</a>
+
<a href="${url}" target="_blank">${url}</a>
</div>
<div style="color: #8b949e; font-size: 0.75rem; margin-top: 0.25rem;">
started: <span data-start-time="${proxy.lastStartTime || ''}"></span> • traffic in: <span data-traffic-in="${proxy.name}">0 B</span> • out: <span data-traffic-out="${proxy.name}">0 B</span>
···
});
}
-
function copyToClipboard(event, url) {
-
event.preventDefault();
-
event.stopPropagation();
-
-
navigator.clipboard.writeText(url).then(() => {
-
// Visual feedback
-
const link = event.target;
-
const originalColor = link.style.color;
-
link.style.color = '#fb923c';
-
setTimeout(() => {
-
link.style.color = originalColor;
-
}, 200);
-
}).catch(err => {
-
console.error('Failed to copy:', err);
-
});
-
}
-
// Fetch immediately and then every 5 seconds
fetchStats();
setInterval(fetchStats, 5000);
// Update relative times every 10 seconds
setInterval(updateRelativeTimes, 10000);
+
+
// Remove loading class after initial fetch
+
document.body.classList.remove('loading');
</script>
</body>
+11
modules/nixos/services/bore/frps.nix
···
# Subdomain support for *.${cfg.domain}
subDomainHost = "${cfg.domain}"
+
# Custom 404 page
+
custom404Page = "${./404.html}"
+
# Logging
log.to = "console"
log.level = "info"
···
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote}
header_up Host {host}
+
}
+
handle_errors {
+
@404 expression {http.error.status_code} == 404
+
handle @404 {
+
root * ${./.}
+
rewrite * /404.html
+
file_server
+
}
}
'';
};