[main]: Add server-notes
This commit is contained in:
18 files changed
+1406
-1
No files matched your search
@@ -0,0 +1,203 @@
|
||||
---
|
||||
schema_version: 1
|
||||
id: home-server.networking
|
||||
type: reference
|
||||
scope: [jupiter, mercury, dns, ingress, wireguard, cloudflare]
|
||||
sensitivity: private-infrastructure
|
||||
last_reviewed: "2026-10-06"
|
||||
sources:
|
||||
- kind: owner-report
|
||||
reference: "Network topology, Mercury nginx/iptables/fail2ban output, LAN DNS, 2026-10-06"
|
||||
- kind: owner-report
|
||||
reference: "Cloudflare ingress YAML and client SSH configurations, 2026-10-06"
|
||||
- kind: owner-report
|
||||
reference: "CGNAT rationale, Docker network and container inspection, 2026-10-06"
|
||||
- kind: repository
|
||||
repository: jupiter-stacks
|
||||
revision: 610e325ef6a98850511ce7a089b0b9a77bfecf15
|
||||
paths:
|
||||
- stacks/traefik/docker-compose.yml
|
||||
- stacks/cloudflared/docker-compose.yml
|
||||
- stacks/gitea/docker-compose.yml
|
||||
- stacks/jellyfin/docker-compose.yml
|
||||
- stacks/audiobookshelf/docker-compose.yml
|
||||
related: [home-server.reference, home-server.host, home-server.mercury, home-server.seedbox, home-server.authentication, home-server.operations]
|
||||
update_triggers: [dns-change, proxy-change, tunnel-change, firewall-change, certificate-change]
|
||||
unknowns:
|
||||
- public-dns-record-types-and-cloudflare-proxy-status
|
||||
- cloudflare-access-applications-and-login-policies
|
||||
- wireguard-allowedips-and-keepalive
|
||||
- jupiter-firewall-policy
|
||||
- traefik-forwarded-header-trust-configuration
|
||||
---
|
||||
|
||||
# Networking
|
||||
|
||||
## HTTPS ingress
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
themeCSS: |
|
||||
.node rect { rx: 8px; ry: 8px; stroke-width: 1.5px; }
|
||||
.cluster rect { fill: var(--infra-zone) !important; stroke: var(--infra-border) !important; stroke-dasharray: 5 5; rx: 12px; ry: 12px; }
|
||||
.label, .nodeLabel, .cluster-label { color: var(--infra-text) !important; }
|
||||
.edgeLabel, .edgeLabel p { background-color: var(--infra-zone) !important; color: var(--infra-text) !important; }
|
||||
.flowchart-link { stroke: var(--infra-line) !important; }
|
||||
marker path { fill: var(--infra-line) !important; stroke: var(--infra-line) !important; }
|
||||
.infraClient rect { fill: var(--infra-client-fill) !important; stroke: var(--infra-client-stroke) !important; }
|
||||
.infraEdge rect { fill: var(--infra-edge-fill) !important; stroke: var(--infra-edge-stroke) !important; }
|
||||
.infraService rect { fill: var(--infra-service-fill) !important; stroke: var(--infra-service-stroke) !important; }
|
||||
flowchart:
|
||||
curve: basis
|
||||
nodeSpacing: 35
|
||||
rankSpacing: 55
|
||||
---
|
||||
flowchart TB
|
||||
Internet["<b>Public clients</b>"]
|
||||
|
||||
subgraph VPS["MERCURY / PUBLIC EDGE"]
|
||||
Nginx["<b>nginx</b><br/>185.230.217.66<br/>WireGuard 10.0.0.1"]
|
||||
Uptime["<b>Uptime service</b><br/>127.0.0.1:3001"]
|
||||
Nginx -->|"uptime.umbra.mom / HTTP"| Uptime
|
||||
end
|
||||
|
||||
subgraph Home["JUPITER / HOME SERVER"]
|
||||
LAN["<b>LAN clients</b><br/>Jellyfin / Bookshelf local DNS"]
|
||||
Traefik["<b>Traefik</b><br/>192.168.1.56<br/>WireGuard 10.0.0.2"]
|
||||
Apps["<b>Application containers</b><br/>Docker network: traefik"]
|
||||
LAN -->|"HTTPS :443"| Traefik
|
||||
Traefik -->|"Application routing"| Apps
|
||||
end
|
||||
|
||||
Internet -->|"HTTPS :443"| Nginx
|
||||
Nginx -->|"HTTPS :443 over WireGuard"| Traefik
|
||||
|
||||
class Internet,LAN infraClient
|
||||
class Nginx,Traefik infraEdge
|
||||
class Apps,Uptime infraService
|
||||
```
|
||||
|
||||
## Cloudflare Tunnel
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
themeCSS: |
|
||||
.node rect { rx: 8px; ry: 8px; stroke-width: 1.5px; }
|
||||
.cluster rect { fill: var(--infra-zone) !important; stroke: var(--infra-border) !important; stroke-dasharray: 5 5; rx: 12px; ry: 12px; }
|
||||
.label, .nodeLabel, .cluster-label { color: var(--infra-text) !important; }
|
||||
.edgeLabel, .edgeLabel p { background-color: var(--infra-zone) !important; color: var(--infra-text) !important; }
|
||||
.flowchart-link { stroke: var(--infra-line) !important; }
|
||||
marker path { fill: var(--infra-line) !important; stroke: var(--infra-line) !important; }
|
||||
.infraClient rect { fill: var(--infra-client-fill) !important; stroke: var(--infra-client-stroke) !important; }
|
||||
.infraCloud rect { fill: var(--infra-cloud-fill) !important; stroke: var(--infra-cloud-stroke) !important; }
|
||||
.infraEdge rect { fill: var(--infra-edge-fill) !important; stroke: var(--infra-edge-stroke) !important; }
|
||||
.infraService rect { fill: var(--infra-service-fill) !important; stroke: var(--infra-service-stroke) !important; }
|
||||
flowchart:
|
||||
curve: basis
|
||||
nodeSpacing: 35
|
||||
rankSpacing: 45
|
||||
---
|
||||
flowchart TB
|
||||
Shell["<b>SSH client</b><br/>Host jupiter / user jay"]
|
||||
Git["<b>Git over SSH</b><br/>Host git.umbra.mom / user git"]
|
||||
Cloud["<b>Cloudflare Tunnel edge</b><br/>Access policy unconfirmed"]
|
||||
|
||||
subgraph Home["JUPITER / HOME SERVER"]
|
||||
Connector["<b>cloudflared</b><br/>Locally configured ingress"]
|
||||
SSH["<b>Host sshd</b><br/>192.168.1.56:22"]
|
||||
Gitea["<b>Gitea SSH</b><br/>192.168.1.56:2222"]
|
||||
Connector -->|"ssh.umbra.mom / SSH :22"| SSH
|
||||
Connector -->|"git.umbra.mom / SSH :2222"| Gitea
|
||||
end
|
||||
|
||||
Shell -->|"cloudflared access ssh / ssh.umbra.mom"| Cloud
|
||||
Git -->|"cloudflared access ssh / git.umbra.mom"| Cloud
|
||||
Cloud <-->|"Tunnel traffic / initiated outbound by Jupiter"| Connector
|
||||
|
||||
class Shell,Git infraClient
|
||||
class Cloud infraCloud
|
||||
class Connector infraEdge
|
||||
class SSH,Gitea infraService
|
||||
```
|
||||
|
||||
Client `cloudflared` transports SSH through Cloudflare; Jupiter's connector opens
|
||||
the outbound tunnel. Origins still perform SSH authentication. No Mercury,
|
||||
WireGuard, or Traefik hop on this path; no home-router port forwarding.
|
||||
|
||||
| Ingress hostname | Origin | Client SSH user |
|
||||
| --- | --- | --- |
|
||||
| `ssh.umbra.mom` | `ssh://192.168.1.56:22` | `jay` |
|
||||
| `git.umbra.mom` | `ssh://192.168.1.56:2222` | `git` |
|
||||
| Unmatched | `http_status:404` | N/A |
|
||||
|
||||
Both client configurations use `IdentityFile ~/.ssh/id_ed25519`.
|
||||
|
||||
```sshconfig
|
||||
Host jupiter
|
||||
User jay
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
ProxyCommand cloudflared access ssh --hostname ssh.umbra.mom
|
||||
|
||||
Host git.umbra.mom
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
ProxyCommand cloudflared access ssh --hostname %h
|
||||
```
|
||||
|
||||
Local tunnel configuration is separate from Cloudflare Access applications.
|
||||
Access login/provider/allow rules remain unconfirmed; `ProxyCommand` alone
|
||||
does not establish enforcement.
|
||||
|
||||
Ingress source: host `/data/cloudflared/config.yaml`, mounted at
|
||||
`/etc/cloudflared/config.yaml`.
|
||||
|
||||
## DNS / routes
|
||||
|
||||
| DNS / route | Destination |
|
||||
| --- | --- |
|
||||
| Public service ingress | Mercury `185.230.217.66` |
|
||||
| `jellyfin.local.umbra.mom` | Jupiter `192.168.1.56` |
|
||||
| `bookshelf.local.umbra.mom` | Jupiter `192.168.1.56` |
|
||||
| `ssh.umbra.mom`, `git.umbra.mom` | Cloudflare Tunnel |
|
||||
| `uptime.umbra.mom` | Mercury nginx -> `http://127.0.0.1:3001` |
|
||||
|
||||
## Mercury
|
||||
|
||||
[Mercury VPS](mercury.md): native nginx; WireGuard server `10.0.0.1/24`;
|
||||
Jupiter client `10.0.0.2/24`. Hosting, TLS, firewall and fail2ban details are
|
||||
maintained on that page.
|
||||
|
||||
Home ISP uses CGNAT. Mercury supplies a static public IPv4 and forwards over
|
||||
WireGuard; owner preference is to avoid public ingress via the residential IP.
|
||||
|
||||
## Observed Docker networks
|
||||
|
||||
Snapshot from supplied inspection, not fixed-address configuration. Container
|
||||
IPs may change; use Docker service names.
|
||||
|
||||
| Network | IPv4 subnet | Internal | Observed role |
|
||||
| --- | --- | --- | --- |
|
||||
| `traefik` | `172.18.0.0/16` | No | Reverse proxy and application ingress |
|
||||
| `gitea_network` | `172.23.0.0/16` | No | Gitea, runner, notes builder, Havox sync |
|
||||
| `cloudflared_cloudflare` | `172.26.0.0/16` | No | Tunnel connector |
|
||||
| `gitea_data` | `192.168.96.0/20` | Yes | Gitea and PostgreSQL |
|
||||
| `paperless_data` | `192.168.112.0/20` | Yes | Paperless, PostgreSQL, Redis |
|
||||
| `dozzle_dozzle` | `172.27.0.0/16` | Yes | Dozzle and socket proxy |
|
||||
|
||||
Cloudflared's observed `172.26.0.2` matches the supplied proxied SSH login source.
|
||||
An internal network alone does not isolate a multi-network container from
|
||||
egress through its other networks. Empty network entries do not establish
|
||||
whether they are obsolete or safe to remove.
|
||||
|
||||
## Jupiter: repository configuration
|
||||
|
||||
- Traefik publishes TCP `80,443`; HTTP redirects to HTTPS.
|
||||
- Docker provider: opt-in `traefik.enable=true`; external network `traefik`.
|
||||
- File provider: `/data/traefik/dynamic`.
|
||||
- ACME: Let's Encrypt; Cloudflare DNS-01; `/data/traefik/acme/acme.json`;
|
||||
apex + `*.umbra.mom` certificate requested.
|
||||
- HTTPS fallback: priority `1`; unmatched non-apex hosts redirect to `https://umbra.mom`.
|
||||
- `cloudflared`: `/data/cloudflared` -> `/etc/cloudflared`;
|
||||
stack-local bridge `cloudflare`; no published ports.
|
||||
Reference in new issue
Block a user