Rebuilding My Personal Server Framework

Jun 16, 2026

1872 words

9 min read

Tech

Rebuilding My Personal Server Framework

While reorganizing my personal servers, the main thing I wanted to solve was not “how do I run a few more services?” It was how to put a growing pile of services back behind clear boundaries.

HomeLab services tend to pile up naturally: a blog, a start page, monitoring, admin panels, personal projects, bots, Minecraft servers, and all kinds of temporary experiments. At first, each one is just something I want to “get running.” After a while, entry points, domains, databases, ports, and backup strategies start tangling together. When something breaks, it becomes hard to tell which layer failed. When I want to migrate, it becomes hard to move only one part away.

Looking back, the April version was more like a migration draft: it mapped out the roles of HK Main, the Mac mini, proxy nodes, and each stack. This version is closer to the current scene: which domains are actually in use, which services have become long-lived, and which entry points exist for friends or for my own maintenance.

So the goal of this framework is straightforward: use one public entry path, split services by responsibility, keep sensitive components inside the private network, put static content on managed hosting whenever possible, and leave the Mac mini for services that need long-running processes, persistence, or private-network access.

Overall Idea

The current architecture follows a “Cloudflare as the DNS/access layer + HK Main as the public entry point + Mac mini for local core services” model.

flowchart LR
    User["Public users / friends"] --> CF["Cloudflare DNS / CDN"]
    CF --> Pages["Cloudflare Pages<br/>Astro Blog and static content"]
    CF --> HK["HK Main<br/>frps only"]
    HK --> FRPC["Mac mini<br/>frpc"]
    FRPC --> NPM["Nginx Proxy Manager"]

    NPM --> Monitor["monitor-stack<br/>Komari"]
    NPM --> Home["homepage-stack<br/>Homepage"]
    NPM --> Private["private-services-stack<br/>Nextcloud / Vault"]
    NPM --> VPN["vpn-stack<br/>VPN download and config entry"]

    Friends["Trusted friends"] --> GameAccess["Tailscale first<br/>frp / domain fallback"]
    GameAccess --> Games["game-stack<br/>Game Server"]

    VPN --> Nodes["Proxy / VPN nodes<br/>connected as needed"]

The key idea is to separate “entry” from “business services.”

HK Main is only the public entry server. It runs frps, but it does not host databases, personal files, long-running business services, or proxy exit traffic. The real services run locally on the Mac mini inside OrbStack. frpc connects them to HK Main, and Nginx Proxy Manager (NPM) handles domain-based routing and reverse proxying.

The static blog still belongs on a hosted platform such as Cloudflare Pages. But homepage.shishishi3.com is no longer just a static home page; it is the HomeLab navigation and status entry point, so it now lives on the Mac mini as a long-running service. This keeps the static publishing surface and the private service surface from dragging each other down.

Server Roles

The Mac mini is the core host of this system. It has no public IP. Its job is to run long-lived services, databases, personal projects, bots, and game servers. Containers are split into Docker Compose stacks, each with its own config directory, data directory, and network boundary.

HK Main is the only host exposed as the public entry layer. It only runs frps, receives HTTP/HTTPS traffic after Cloudflare, and forwards it through frp to the Mac mini. The less this node does, the better, because it sits on the public side and should have as small an attack surface as possible.

Proxy or VPN nodes only handle network exit and access duties. They are not involved in Nextcloud, Homepage, Komari, game services, or other main services, and they are not mixed with HK Main. Nodes can come and go without shaking the entry layer or the local service layer.

This split makes the boundaries easier to reason about: if the entry breaks, check HK Main; if a service breaks, check the Mac mini; if file sync breaks, check Nextcloud; if monitoring looks strange, check Komari; if game access breaks, check gs and the related ports. I no longer need to dig through a pile of unrelated containers on the same machine.

Domain Plan

Domains are also split by responsibility. I no longer want the domain table to describe everything I might run someday; it should describe the entry points that are actually in use right now.

shishishi3.com hosts normal web services for myself and trusted visitors:

SubdomainServiceLocation
komari.shishishi3.comKomari monitoring panelmonitor-stack
homepage.shishishi3.comHomepage navigation and service entryhomepage-stack
vpndl.shishishi3.comVPN download, config, or instruction entryvpn-stack
gs.shishishi3.comGame service entrygame-stack
nc.shishishi3.comNextcloud file and sync serviceprivate-services-stack
v.shishishi3.comVault / private tools entryprivate-services-stack

This version is more focused than the April plan: names like status, panel, bot, and demo are out of the current article instead of pretending to represent the live setup. They can come back later if needed, but a domain plan should reflect running services rather than reserving space for every possibility.

Infrastructure domains stay quiet and are only used for HK Main, frp, nodes, or internal management entries. Normal service entry points live under shishishi3.com; infrastructure entry points should not blend into business domains. This makes DNS, certificates, Cloudflare rules, and NPM proxy rules much easier to troubleshoot.

Public Entry

This setup does not use Cloudflare Tunnel as the main entry. Cloudflare handles DNS, CDN, WAF, and access control, while the real origin entry for local services is centralized on HK Main.

The web traffic path looks roughly like this:

User browser
  -> Cloudflare
  -> HK Main:80/443
  -> frps
  -> Mac mini frpc
  -> NPM
  -> Komari / Homepage / Nextcloud / Vault / VPN entry containers

TCP forwarding is configured like this:

HK Main:80  -> frps:8080 -> Mac mini frpc -> NPM:80
HK Main:443 -> frps:8443 -> Mac mini frpc -> NPM:443

frps only forwards traffic. It does not process business requests on HK Main. TLS transport is enabled between frpc and frps; NPM handles domain routing, reverse proxying, and certificate management. Backend services do not expose ports directly to the public internet. They only join Docker networks that NPM can reach.

Non-HTTP/HTTPS services are not forced through NPM. For example, gs.shishishi3.com is more like a friendly entry label for game services. The actual connection can depend on the game protocol, port, and audience: trusted friends use Tailscale first, and frp or restricted ports are only fallbacks when installing a client is not practical.

Stack Layout on the Mac mini

Services on the Mac mini are split into a few layers by responsibility. The names do not need to be pretty; the important thing is that the directory tells me what it owns.

edge-stack is the entry layer. It contains frpc and NPM. It brings public traffic into the local machine and forwards each domain to the right service. The NPM admin UI is only reachable from the LAN or Tailscale by default; it is not exposed directly to the public internet.

monitor-stack hosts Komari. Monitoring may look like just another panel, but it answers the question “do I need to get up and check something?” That deserves independent persistence and upgrades that are not tied to unrelated services.

homepage-stack hosts Homepage. It is an entry point for humans, not for machines: links, groups, service status, and common management addresses can live here. It can be exposed for my own use, but it should not accidentally expose every backend behind it.

private-services-stack hosts Nextcloud and private services such as v.shishishi3.com. The common thread is not the tech stack; it is data sensitivity. Files, sync data, vault data, and other private material need explicit volumes, backup plans, and access limits.

vpn-stack hosts the download, config, or instruction entry behind vpndl.shishishi3.com. It may not be complex, but it affects access, so it should stay separate from ordinary showcase projects. I do not want a casual page edit to affect someone else’s connection path.

game-stack hosts the game services behind gs.shishishi3.com. Game traffic is not mixed with the web reverse proxy. Access uses Tailscale first, with frp or restricted ports as fallbacks. Saves, mods, and config files are persisted separately and backed up regularly.

Temporary projects can still have a projects-stack, but they are no longer the center of this article. The core of the current architecture is keeping Komari, Homepage, the VPN entry, game services, Nextcloud, and private services stable.

After this split, every stack can be started, stopped, backed up, and migrated independently. When adding a new service, I first decide which layer it belongs to, then add it to that stack instead of throwing every container into the same flat space.

Security Strategy

The rule for HK Main is: entry only, no business services. It only opens 80, 443, the frps control port, and the necessary high forwarding ports. frps uses a strong token and disables the default admin port. SSH allows key login only and disables password login.

The rule for the Mac mini is: layered services, centralized data. OrbStack networks are split by stack. Database ports are not mapped to the public side. The NPM admin UI is not exposed directly. .env files, database passwords, tokens, and key files are never committed to Git. For services such as Nextcloud and Vault, “the page opens” is not enough; the data volumes, backups, and restore path also have to be verified.

The rule for Cloudflare is: route by domain, put access control in front. Normal web services can use CDN and WAF. Panel-like services should be protected with Cloudflare Access or IP restrictions. Certificates should use DNS validation or Cloudflare Origin Certificates where possible, avoiding HTTP validation problems caused by the frp forwarding chain.

Backups should cover Cloudflare Pages project configuration, the Astro Blog source repository, Homepage config, Komari data, Nextcloud data and database, Vault-style service volumes, the VPN config entry, game saves, and NPM configuration. A service is not really deployed until it can be restored.

Maintenance Order

This setup is no longer just a migration plan, so maintenance should not start by “launching all containers.” It should start by clarifying entry points and data boundaries.

The first step is to inventory existing containers, image versions, port mappings, volumes, databases, and config files, then complete one verifiable backup. The second step is to keep stack directories on the Mac mini, with each stack maintaining its own compose.yml, .env, and data/.

If the entry layer changes, check HK Main’s frps, firewall, and required ports first, then verify that the Mac mini’s frpc can connect reliably. Once the entry path works, check edge-stack and NPM, confirm that npm-http and npm-https forwarding are registered, and make sure each domain hits the right Proxy Host.

If a business service changes, verify it domain by domain: komari for continuous monitoring data, homepage for navigation and status cards, vpndl for usable downloads and config, gs for game protocol and port access, nc for file sync and database health, and v for login, unlock, and persistence.

Finally, review DNS, NPM reverse proxy rules, backup jobs, and old port mappings. Once the new entry is stable, shut down old containers or old domains instead of saving all the risk for the end.

What Comes Next

This framework has moved from April’s “preparing the rebuild” stage into ongoing maintenance around the current services. A few concrete templates still need to be filled in:

  • monitor-stack compose.yml and Komari backup notes.
  • homepage-stack config structure.
  • private-services-stack Nextcloud / Vault backup and restore procedures.
  • vpn-stack entry notes and access-control checklist.
  • game-stack compose.yml.
  • NPM reverse proxy rule list.
  • Scheduled backup scripts and restore rehearsal notes.

Once those templates are complete, this will become more than a one-time rebuild note. It will be a reusable way to run my personal servers: new services join by layer, old services migrate by layer, and problems can be traced through entry, service, data, and network boundaries one layer at a time.

Rebuilding My Personal Server Framework
https://blog.shishishi3.com/en/blog/server-frame/
Author
豕豕豕
Published on
Jun 16, 2026
License
CC BY-NC-SA 4.0

Open the RSS Feed

RSS is an XML feed meant for feed readers, so opening it in a browser usually shows raw XML. That is expected behavior.

To reduce accidental clicks and misleading redirects, the feed link is only enabled after a 5 second confirmation countdown.

Enter keywords to start searching