Added custom page

This commit is contained in:
Nik Afiq 2025-11-20 23:32:59 +09:00
parent 96c864e1d2
commit edb60952c7
6 changed files with 343 additions and 1 deletions

28
default.conf Normal file
View File

@ -0,0 +1,28 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
# === custom error pages ===
error_page 404 /errors/404.html;
error_page 500 502 503 504 /errors/50x.html;
location = /errors/404.html {
root /var/www;
internal;
}
location = /errors/50x.html {
root /var/www;
internal;
}
location / {
try_files $uri $uri/ =404;
}
}

95
http/404.html Normal file
View File

@ -0,0 +1,95 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>404 | Page Lost in the Void</title>
<style>
body {
margin: 0;
padding: 0;
background: #050814;
color: #e5e5e5;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.card {
text-align: center;
padding: 2.5rem 3rem;
border-radius: 1rem;
background: radial-gradient(circle at top, #1e293b, #020617);
box-shadow: 0 0 40px rgba(15, 23, 42, 0.9);
}
.code {
font-size: 4rem;
letter-spacing: 0.2em;
margin-bottom: 0.25rem;
}
.glitch {
position: relative;
display: inline-block;
font-size: 1.4rem;
text-transform: uppercase;
letter-spacing: 0.25em;
}
.glitch::before,
.glitch::after {
content: attr(data-text);
position: absolute;
left: 0;
top: 0;
overflow: hidden;
clip-path: inset(0 0 50% 0);
opacity: 0.7;
animation: glitch 1.6s infinite linear alternate-reverse;
}
.glitch::before {
transform: translate(-2px, -1px);
}
.glitch::after {
transform: translate(2px, 1px);
clip-path: inset(50% 0 0 0);
}
@keyframes glitch {
0% { transform: translate(0, 0); }
20% { transform: translate(-3px, 2px); }
40% { transform: translate(2px, -2px); }
60% { transform: translate(-2px, 1px); }
80% { transform: translate(1px, -1px); }
100% { transform: translate(0, 0); }
}
p {
margin-top: 1rem;
font-size: 0.95rem;
opacity: 0.8;
}
a {
display: inline-block;
margin-top: 1.5rem;
padding: 0.6rem 1.4rem;
border-radius: 999px;
border: 1px solid rgba(148, 163, 184, 0.6);
text-decoration: none;
color: #e5e5e5;
font-size: 0.9rem;
backdrop-filter: blur(4px);
}
a:hover {
background: rgba(148, 163, 184, 0.15);
}
</style>
</head>
<body>
<div class="card">
<div class="code">404</div>
<div class="glitch" data-text="NOT FOUND">NOT FOUND</div>
<p>
The page youre looking for has drifted out of this universe.<br />
Check the URL or head back to the safe zone.
</p>
<a href="/">Return to Home</a>
</div>
</body>
</html>

178
http/50x.html Normal file
View File

@ -0,0 +1,178 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>5xx | Server is on Fire</title>
<style>
:root {
color-scheme: dark;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
background: radial-gradient(circle at top, #111827 0%, #020617 55%, #000 100%);
color: #f9fafb;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.card {
position: relative;
text-align: center;
padding: 2.8rem 3.2rem;
border-radius: 1.25rem;
background: linear-gradient(145deg, rgba(15,23,42,0.95), rgba(30,64,175,0.9));
box-shadow:
0 0 30px rgba(0,0,0,0.8),
0 0 80px rgba(248,113,113,0.5);
max-width: 480px;
width: 90%;
backdrop-filter: blur(10px);
}
.code {
font-size: 3.6rem;
font-weight: 700;
letter-spacing: 0.2em;
text-transform: uppercase;
margin-bottom: 0.25rem;
}
.subtitle {
font-size: 1rem;
letter-spacing: 0.16em;
text-transform: uppercase;
opacity: 0.85;
}
.flames {
position: absolute;
inset: auto -10%;
bottom: -2.5rem;
height: 80px;
pointer-events: none;
opacity: 0.95;
mix-blend-mode: screen;
}
.flame {
position: absolute;
bottom: 0;
width: 26px;
height: 80px;
background: radial-gradient(circle at 20% 0%, #fef3c7 0, #f97316 40%, #b91c1c 70%, transparent 80%);
border-radius: 50% 50% 0 0;
filter: blur(1px);
animation: rise 1.4s infinite ease-in-out alternate;
opacity: 0.9;
}
.flame:nth-child(1) { left: 10%; animation-delay: -0.1s; transform-origin: 50% 100%; }
.flame:nth-child(2) { left: 25%; animation-delay: -0.4s; transform-origin: 50% 100%; }
.flame:nth-child(3) { left: 50%; animation-delay: -0.2s; transform-origin: 50% 100%; }
.flame:nth-child(4) { left: 70%; animation-delay: -0.6s; transform-origin: 50% 100%; }
.flame:nth-child(5) { left: 86%; animation-delay: -0.3s; transform-origin: 50% 100%; }
@keyframes rise {
0% { transform: scaleY(0.7) translateY(10px); opacity: 0.6; }
50% { transform: scaleY(1.05) translateY(-6px); opacity: 1; }
100% { transform: scaleY(0.85) translateY(4px); opacity: 0.7; }
}
.text {
margin-top: 1.4rem;
font-size: 0.96rem;
line-height: 1.6;
opacity: 0.9;
}
.hint {
margin-top: 0.75rem;
font-size: 0.8rem;
opacity: 0.6;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.btn-row {
margin-top: 1.8rem;
display: flex;
justify-content: center;
gap: 0.75rem;
flex-wrap: wrap;
}
a.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
padding: 0.55rem 1.35rem;
border-radius: 999px;
border: 1px solid rgba(148,163,184,0.7);
text-decoration: none;
color: inherit;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.12em;
background: rgba(15,23,42,0.8);
backdrop-filter: blur(6px);
white-space: nowrap;
}
a.btn:hover {
background: rgba(248,113,113,0.15);
border-color: rgba(248,113,113,0.7);
}
.emoji {
font-size: 1.1rem;
}
@media (max-width: 480px) {
.card {
padding: 2.1rem 1.7rem;
}
.code {
font-size: 3rem;
}
.subtitle {
font-size: 0.9rem;
}
.text {
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="card">
<div class="code">5XX</div>
<div class="subtitle">SERVER IS ON FIRE</div>
<div class="text">
Something on the backend just went very wrong.<br />
Your request didnt make it through, but the logs definitely did.
</div>
<div class="hint">
Tip: If youre the admin, check your upstreams, containers, and error logs.<br />
If youre not, maybe just pretend this never happened.
</div>
<div class="btn-row">
<a href="/" class="btn">
<span class="emoji">🏠</span>
<span>Back to Safety</span>
</a>
<a href="https://x.com/nik4nao" class="btn">
<span class="emoji">🧯</span>
<span>Alert Admin</span>
</a>
</div>
<div class="flames">
<div class="flame"></div>
<div class="flame"></div>
<div class="flame"></div>
<div class="flame"></div>
<div class="flame"></div>
</div>
</div>
</body>
</html>

View File

@ -35,6 +35,24 @@ server {
# proxy_redirect off;
}
# ---- Jellyfin at /anime/ ----
location = /anime { return 302 /anime/; } # enforce trailing slash
location /anime/ {
proxy_pass http://anime_upstream/; # uses upstream (or use the raw URL)
proxy_next_upstream error timeout invalid_header http_502 http_503 http_504;
include snippets/proxy-common.conf;
# Jellyfin behind subpath specifics
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /anime;
# (Optional) if you see odd redirects, uncomment:
# proxy_redirect off;
}
# ---- Pi-hole admin at /admin/ ----
# Pi-holes UI lives under /admin/, so keep the trailing slash in proxy_pass.
location /admin/ {

View File

@ -57,6 +57,11 @@ server {
add_header X-Frame-Options "DENY" always;
add_header X-Robots-Tag "noindex, nofollow, noimageindex, nosnippet, noarchive" always;
# Custom error pages for public site
proxy_intercept_errors on;
error_page 404 /errors/404.html;
error_page 500 502 503 504 /errors/50x.html;
# (Optional) Block noncompliant AI bots (requires $block_ai map in nginx.conf)
if ($block_ai) { return 403; }
@ -109,6 +114,18 @@ server {
proxy_read_timeout 60s;
}
# Deny anything unexpected
# Pretty error pages (served from disk, not directly reachable)
location = /errors/404.html {
root /var/www;
internal;
}
location = /errors/50x.html {
root /var/www;
internal;
}
# Deny anything unexpected
location / {
return 404;

View File

@ -12,4 +12,10 @@ upstream pihole_upstream {
upstream watchparty_upstream {
server 192.168.7.96:3000;
keepalive 16;
}
}
upstream anime_upstream {
server 192.168.7.78:8096 max_fails=2 fail_timeout=3s;
server 192.168.7.7:8096 backup;
keepalive 16;
}