The front page of https://503mail.com is one static HTML file with a list of links: the tools I've built (Mail Reader, Phone Dictation, Nibbles) and the server dashboards (Uptime Kuma, DNS Updater, Analytics, Stirling PDF). Each link sits in an outlined box down the center of the page, which is always in dark mode. This post is the complete rebuild guide; every block has a Copy button.
How it works
- The browser asks for
https://503mail.com. DNS already points the domain at home. - CT 108 (Caddy reverse proxy) terminates TLS and serves files straight from its own folder
/var/www/503mail.com. There is no separate container for the home page. - Caddy's
file_serverservesindex.htmlfrom that folder for/. The page has no JavaScript and no external files: the styling is a small<style>block inside the HTML.
The same folder also holds the resume (/resume/, a Markdown file rendered through layout.html with Caddy templates) and resume.pdf. This guide only covers index.html; the resume files are left alone.
Containers involved
| Container | Role | LAN IP |
|---|---|---|
| CT 108 (Caddy reverse proxy) | Serves 503mail.com from /var/www/503mail.com |
x.x.0.122 |
The linked tools each run in their own container and have their own rebuild guides on this blog.
Where to run each command
- Proxmox host shell: in the Proxmox web UI click pve → Shell (or SSH to the host as root).
Rebuild, step by step
1. Make a working folder on the host
Proxmox host shell:
mkdir -p /root/homepage-503mail && cd /root/homepage-503mail
2. Create the page
Proxmox host shell. This writes /root/homepage-503mail/index.html.
index.html: the whole page, with its styling inline. To add or remove a link, copy or delete one <li> ... </li> box.
cat > /root/homepage-503mail/index.html <<'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Greetings from Dietrich!</title>
<style>
:root { color-scheme: dark; --bg: #121212; --txt: #e0e0e0; --muted: #b0b0b0; --accent: #4da6ff; --border: #6a6a6a; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
line-height: 1.6; color: var(--txt); background: var(--bg); margin: 0;
}
main { max-width: 800px; margin: 40px auto; padding: 0 16px; }
h1 { text-align: center; margin: 48px 0 8px; }
nav { text-align: center; margin-bottom: 40px; }
a { color: var(--accent); }
nav a { font-weight: bold; margin: 0 10px; text-decoration: none; }
h2 { border-bottom: 1px solid var(--border); padding-bottom: 6px; margin-top: 40px; }
ul.tools { list-style: none; padding: 0; }
ul.tools li { border: 1px solid var(--border); border-radius: 8px; padding: 14px 16px; margin-bottom: 14px; }
ul.tools h3 { margin: 0 0 4px; font-size: 1.15rem; }
ul.tools p { margin: 0 0 6px; color: var(--muted); }
</style>
</head>
<body>
<main>
<h1>Hello World!, Greetings from Dietrich</h1>
<nav aria-label="Site">
<a href="/resume/">Resume</a>
<a href="https://blog.503mail.com/">Blog</a>
</nav>
<h2>Tools I've built</h2>
<ul class="tools">
<li>
<h3><a href="https://ocr.503mail.com/">Mail Reader</a></h3>
<p>Take a photo of a piece of mail and have it read aloud and summarized. Self-hosted OCR, a local AI model, and text-to-speech.</p>
<a href="https://blog.503mail.com/blog/mail-reader-self-hosted-ocr-01oct2026">How it was built (Mail Reader)</a>
</li>
<li>
<h3><a href="https://stt.503mail.com/">Phone Dictation</a></h3>
<p>Speak into my phone and the text is typed into whichever computer I pick. Self-hosted Whisper speech-to-text.</p>
<a href="https://blog.503mail.com/blog/phone-dictation-self-hosted-whisper-03oct2026">How it was built (Phone Dictation)</a>
</li>
<li>
<h3><a href="https://games.503mail.com/">Nibbles</a></h3>
<p>A browser remake of the classic QBasic snake game, with all 10 original levels and two-player mode. Works with a keyboard or by swiping on a phone.</p>
<a href="https://blog.503mail.com/blog/nibbles-qbasic-snake-game-02oct2026">How it was built (Nibbles)</a>
</li>
</ul>
<h2>Server dashboards</h2>
<ul class="tools">
<li>
<h3><a href="https://status.503mail.com/">Uptime Kuma</a></h3>
<p>Status monitoring for all my sites and containers.</p>
</li>
<li>
<h3><a href="https://dns.503mail.com/">DNS Updater</a></h3>
<p>Keeps my domains pointed at my home IP address. Password protected.</p>
</li>
<li>
<h3><a href="https://analytics.503mail.com/">Analytics</a></h3>
<p>Self-hosted Umami visitor statistics.</p>
</li>
<li>
<h3><a href="https://pdf.503mail.com/">Stirling PDF</a></h3>
<p>Self-hosted PDF tools: merge, split, convert, OCR, and more.</p>
</li>
</ul>
</main>
</body>
</html>
EOF
3. Back up the current page
Proxmox host shell. Keeps the live page in the ARCHIVE folder next to it, named with today's date:
pct exec 108 -- cp -p /var/www/503mail.com/index.html /var/www/503mail.com/ARCHIVE/index.html.$(date +%Y-%m-%d).bak
If this says the file doesn't exist, you're rebuilding from nothing; skip it and make sure the folders exist instead:
pct exec 108 -- mkdir -p /var/www/503mail.com/ARCHIVE
4. Push the page into CT 108 (Caddy reverse proxy)
Proxmox host shell. No reload is needed; Caddy serves the new file on the next request.
pct push 108 /root/homepage-503mail/index.html /var/www/503mail.com/index.html --perms 644
5. Only if rebuilding CT 108 from nothing: the Caddy site block
The existing edge Caddyfile already has a 503mail.com block, so normally skip this. If CT 108 was rebuilt and has none, this is the minimum that serves the home page (the real block also adds Markdown templating for the resume). Add it to /etc/caddy/Caddyfile in CT 108:
503mail.com {
root * /var/www/503mail.com
file_server {
index index.html index.md
}
}
Then validate and reload from the Proxmox host shell:
pct exec 108 -- caddy validate --config /etc/caddy/Caddyfile
pct exec 108 -- systemctl reload caddy
6. Check it
Proxmox host shell. Should print 200:
curl -s -o /dev/null -w '%{http_code}\n' https://503mail.com/
Then open https://503mail.com and check every box's link works.
Updating the page later
Edit index.html (on the host, or on your PC and copy it over), then repeat steps 3 and 4. To undo a change, push the backup back:
pct exec 108 -- ls /var/www/503mail.com/ARCHIVE/
pct exec 108 -- cp -p /var/www/503mail.com/ARCHIVE/index.html.YYYY-MM-DD.bak /var/www/503mail.com/index.html
(Replace YYYY-MM-DD with a date from the list.)
Monitoring
No separate Uptime Kuma monitor: the page is served by CT 108, and if CT 108 is down every other site's monitor at https://status.503mail.com goes red too.
Troubleshooting: where the logs are
503mail.com access log on CT 108 (Caddy reverse proxy)
- Where:
/var/log/caddy/503mail.login CT 108 - Open: Proxmox host shell
pct exec 108 -- tail -n 50 /var/log/caddy/503mail.log
- Look for: requests for
/with status200are healthy.404for/meansindex.htmlis missing from/var/www/503mail.com. Requests for/wp-login.phpand similar with404are internet bots scanning, harmless.
Edge Caddy service log
- Where: systemd journal for
caddyin CT 108 - Open: Proxmox host shell
pct exec 108 -- journalctl -u caddy -n 100 --no-pager
- Look for: errors mentioning
503mail.comandcertificatemean TLS renewal trouble. A warning that the "Caddyfile input is not formatted" is harmless.
Page looks wrong or a box is missing
Check what's actually live, from the Proxmox host shell:
pct exec 108 -- cat /var/www/503mail.com/index.html
Notes
- Dark mode always: the colors are set once at the top of the
<style>block (--bg,--txt,--accent,--border) withcolor-scheme: dark, so the page is dark whatever the visitor's device setting is. - Box outlines: the first version used a dark gray outline (
#2d2d2d) that almost disappeared on the dark background.#6a6a6ais clearly visible; change--borderto taste. - Stopped services aren't listed: BentoPDF, Etherpad and Code Server still have Caddy routes but their containers are stopped (they return 502), so they're left off the page until they run again.
- Each box's heading is a real heading and every link has its own text, so a screen reader can jump box to box with the heading keys.