zet.home.arpa: document all services and SSL/nginx setup

- Server overview (README.md) with services, storage, and network summary
- Storage layout with disk/fstab/mount details (storage.md)
- Service docs: Samba, NFS, Squid, Pi-hole (with DHCP/split-DNS notes)
- Let's Encrypt cert via acme.sh + GoDaddy DNS-01 (ssl/)
- nginx SSL reverse proxy config and virtual host guide (nginx/)
- Pi-hole moved to port 8081; split DNS overrides documented for both
  Pi-hole and pfSense Unbound to avoid hairpin NAT issues

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:37:04 +00:00
parent 060219d161
commit 7c4c786e7b
10 changed files with 948 additions and 0 deletions

83
zet.home.arpa/README.md Normal file
View File

@@ -0,0 +1,83 @@
# zet.home.arpa
Home lab server providing file sharing, DNS filtering, web proxy, and git hosting.
## Server Overview
| Field | Value |
|-------|-------|
| **Hostname** | zet / zet.home.arpa / zet.kenjim.com |
| **Primary IP** | 172.27.0.35 |
| **OS** | Ubuntu 24.04.4 LTS (Noble) |
| **Kernel** | 6.8.0-124-generic |
| **Network** | 172.27.0.0/24 |
## Services
| Service | Port(s) | How It Runs | Docs |
|---------|---------|-------------|------|
| nginx (SSL reverse proxy) | 80, 443/tcp | systemd (`nginx`) | [nginx/](nginx/) |
| Pi-hole (DNS + ad blocking) | 53/tcp+udp, 8081/tcp, 67/udp | Docker container | [pihole/](pihole/) |
| Samba (SMB file sharing) | 445, 139 | systemd (`smbd`, `nmbd`) | [samba/](samba/) |
| NFS | 2049/tcp+udp | systemd | [nfs/](nfs/) |
| Squid (web proxy) | 3128/tcp | systemd (`squid`) | [squid/](squid/) |
| Gitea (git server) | 3000/tcp | systemd (`gitea`) | [git-server/](git-server/) |
| SSH | 22/tcp | systemd (`ssh`) | — |
| Docker | — | systemd (`docker`) | — |
## Public Hostnames (HTTPS via nginx)
| Hostname | Target | Notes |
|----------|--------|-------|
| `git.kenjim.com` | Gitea (:3000) | Public |
| `www.kenjim.com` | Docker container | Public |
| `kenji.kenjim.com` | Docker container | Public |
| `gt.kenjim.com` | CNAME elsewhere | Cert covers it, nginx drops it |
| `zet.kenjim.com` | SSH only | No web — dynamic DNS entry |
All HTTPS subdomains share one Let's Encrypt cert. See [ssl/](ssl/) and [nginx/](nginx/).
## Storage
See [storage.md](storage.md) for full disk layout. Summary:
| Mount | Device | Size | Use |
|-------|--------|------|-----|
| `/` | nvme0n1p3 (LVM) | 950 GB | OS + apps |
| `/data/ssd-photos` | sda (LVM, Crucial MX500) | 916 GB | Photos SSD |
| `/data/hsgt10a` | sdb1 (HGST 10 TB) | 9.1 TB | Primary bulk storage |
| `/data/hsgt10b` | sdc1 (HGST 10 TB) | 9.1 TB | Secondary bulk storage |
## Network
The server holds four IPs on a single USB NIC (`enx00242788c03a`):
- `172.27.0.35` — primary (DHCP, used for most services)
- `172.27.0.36`, `172.27.0.37`, `172.27.0.38` — secondary aliases
The built-in NIC (`enp1s0`) and WiFi (`wlp2s0`) are both **DOWN**.
## Quick Service Commands
```bash
# nginx (SSL reverse proxy)
sudo systemctl restart nginx
sudo nginx -t # test config before reload
# Pi-hole (admin UI now on :8081)
cd ~/docker-pi-hole && docker compose up -d # start
cd ~/docker-pi-hole && docker compose down # stop
docker exec pihole pihole version # version check
# Samba
sudo systemctl restart smbd nmbd
# NFS
sudo systemctl restart nfs-server
# Squid
sudo systemctl restart squid
# Gitea
sudo systemctl restart gitea
```

View File

@@ -0,0 +1,61 @@
# NFS — zet.home.arpa
NFSv4 file server exporting bulk storage to LAN clients.
## Overview
| Field | Value |
|-------|-------|
| **Package** | `nfs-kernel-server` (Ubuntu) |
| **Config** | `/etc/exports` |
| **Services** | `nfs-server`, `nfs-mountd`, `nfs-idmapd`, `rpcbind`, `rpc-statd` |
| **Port** | 2049/tcp+udp |
## Exports
| Path | Clients | Options |
|------|---------|---------|
| `/data/hsgt10a` | `172.27.0.0/24` | `rw,sync,no_subtree_check` |
### `/etc/exports`
```
/data/hsgt10a 172.27.0.0/24(rw,sync,no_subtree_check)
```
> **Warning**: The current `/etc/exports` on the server has a space between `172.27.0.0/24` and `(rw,sync,...)`.
> A space causes the options to apply to `*` (world) rather than the specified subnet — this is a security misconfiguration.
> The correct syntax has **no space** before the parenthesis:
> ```
> /data/hsgt10a 172.27.0.0/24(rw,sync,no_subtree_check)
> ```
> Fix and reload: `sudo exportfs -ra`
## Service Management
```bash
sudo systemctl status nfs-server
sudo systemctl restart nfs-server
sudo exportfs -v # show active exports
sudo exportfs -ra # reload /etc/exports without restarting
showmount -e 172.27.0.35 # list exports (run from client)
```
## Mounting from a Client
```bash
# Temporary mount
sudo mount -t nfs 172.27.0.35:/data/hsgt10a /mnt/hsgt10a
# Permanent — add to client's /etc/fstab:
172.27.0.35:/data/hsgt10a /mnt/hsgt10a nfs defaults,_netdev 0 0
```
## Migration Notes
To move NFS to a new server:
1. Install: `sudo apt install nfs-kernel-server`
2. Copy `/etc/exports` (fix the space issue above before copying)
3. Ensure `/data/hsgt10a` is mounted on the new host
4. Enable and start: `sudo systemctl enable --now nfs-server`
5. Update any client `/etc/fstab` entries to point to the new server IP

View File

@@ -0,0 +1,114 @@
# nginx — zet.home.arpa
SSL-terminating reverse proxy. Handles all inbound HTTPS traffic and routes to backend services by hostname.
## Overview
| Field | Value |
|-------|-------|
| **Package** | `nginx` (Ubuntu apt) |
| **Config** | `/etc/nginx/sites-available/kenjim.conf` |
| **SSL cert** | `/etc/nginx/ssl/kenjim.com/` (managed by acme.sh) |
| **Ports** | 80/tcp (HTTP→HTTPS redirect), 443/tcp (HTTPS) |
| **Service** | `nginx.service` (systemd, enabled) |
## Architecture
```
Internet → pfSense NAT (80,443) → nginx on 172.27.0.35
┌────────┴─────────┐
git.kenjim.com (future)
Gitea :3000
```
LAN clients resolve `*.kenjim.com` subdomains directly to `172.27.0.35` via split DNS (Pi-hole + pfSense Unbound host overrides), avoiding hairpin NAT through pfSense's WAN interface.
## Virtual Hosts
| Hostname | Backend | Notes |
|----------|---------|-------|
| `git.kenjim.com` | `http://127.0.0.1:3000` | Gitea (systemd service) |
| `www.kenjim.com` | `http://127.0.0.1:8080` | Update port when container is running |
| `kenji.kenjim.com` | `http://127.0.0.1:8082` | Update port when container is running |
| `gt.kenjim.com` | — | Returns 444 (CNAME points elsewhere) |
| default (unknown host) | — | Returns 444 (drops connection) |
## Config File
**Location**: `/etc/nginx/sites-available/kenjim.conf`
**Repo copy**: [`kenjim.conf`](kenjim.conf)
To add a new Docker container backend, add a new `server {}` block following the existing pattern and update the `proxy_pass` port to match the container's host port mapping.
## SSL Certificate
Certificate is managed by acme.sh — see [../ssl/](../ssl/).
| File | Path |
|------|------|
| Full chain | `/etc/nginx/ssl/kenjim.com/fullchain.pem` |
| Private key | `/etc/nginx/ssl/kenjim.com/key.pem` |
Directory: owned by `kenjim:www-data`, mode `750`.
Sudoers rule at `/etc/sudoers.d/acme-nginx-reload` allows acme.sh to reload nginx without a password on cert renewal.
## Service Management
```bash
sudo systemctl status nginx
sudo systemctl reload nginx # reload config (no downtime)
sudo systemctl restart nginx # full restart
sudo nginx -t # test config syntax before applying
```
## pfSense NAT Rules
| WAN Port | Redirect to | Port | Description |
|----------|-------------|------|-------------|
| 80/tcp | 172.27.0.35 | 80 | HTTP → nginx (redirects to HTTPS) |
| 443/tcp | 172.27.0.35 | 443 | HTTPS → nginx |
## Adding a New Docker Container
1. Start the container with a host port mapping, e.g. `-p 8083:80`
2. Add a server block to `/etc/nginx/sites-available/kenjim.conf`:
```nginx
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name newservice.kenjim.com;
ssl_certificate /etc/nginx/ssl/kenjim.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/kenjim.com/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8083;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
3. Add the domain to the cert's SAN list if not already covered (see [../ssl/](../ssl/))
4. Add a CNAME in GoDaddy: `newservice``lair.kenjim.com`
5. Add split DNS overrides in Pi-hole and pfSense Unbound
6. Test and reload: `sudo nginx -t && sudo systemctl reload nginx`
## Migration Notes
To move nginx to a new server:
1. `sudo apt install nginx`
2. Copy `/etc/nginx/sites-available/kenjim.conf`
3. Copy `/etc/nginx/ssl/kenjim.com/` (cert files)
4. Copy `/etc/sudoers.d/acme-nginx-reload`
5. Re-run `acme.sh --install-cert` to wire up the renewal hook to the new host
6. Update pfSense NAT rules to point to the new host IP
7. Update split DNS overrides to the new host IP

View File

@@ -0,0 +1,99 @@
# /etc/nginx/sites-available/kenjim.conf
#
# SSL reverse proxy for kenjim.com subdomains.
# Certificate managed by acme.sh (DNS-01 via GoDaddy).
# Cert path: /etc/nginx/ssl/kenjim.com/
# Redirect all HTTP to HTTPS
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}
# Drop requests for unknown hostnames at SSL level (no response)
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/ssl/kenjim.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/kenjim.com/key.pem;
return 444;
}
# Gitea — git.kenjim.com
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name git.kenjim.com;
ssl_certificate /etc/nginx/ssl/kenjim.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/kenjim.com/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Gitea runs directly on the host (systemd), not in Docker
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# www.kenjim.com — update proxy_pass when container is running
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.kenjim.com;
ssl_certificate /etc/nginx/ssl/kenjim.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/kenjim.com/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8080; # update port to match container
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# kenji.kenjim.com — update proxy_pass when container is running
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name kenji.kenjim.com;
ssl_certificate /etc/nginx/ssl/kenjim.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/kenjim.com/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8082; # update port to match container
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# gt.kenjim.com — CNAME pointing elsewhere; reject cleanly if it lands here
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name gt.kenjim.com;
ssl_certificate /etc/nginx/ssl/kenjim.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/kenjim.com/key.pem;
return 444;
}

View File

@@ -0,0 +1,156 @@
# Pi-hole — zet.home.arpa
Network-wide DNS ad blocker and DHCP server. Runs as a Docker container.
## Overview
| Field | Value |
|-------|-------|
| **Image** | `pihole/pihole:latest` |
| **Container name** | `pihole` |
| **Compose file** | `/home/kenjim/docker-pi-hole/docker-compose.yml` |
| **Config directory** | `/home/kenjim/docker-pi-hole/` |
| **Restart policy** | `always` |
| **Timezone** | `America/Chicago` |
## Versions (as of 2026-06-19)
| Component | Running | Latest |
|-----------|---------|--------|
| Core | v6.1.4 | v6.4.2 |
| Web | v6.2.1 | v6.5.1 |
| FTL | v6.2.3 | v6.6.2 |
**Updates are available** — see [Upgrading](#upgrading) below.
## Ports
| Port | Protocol | Purpose | Accessible from |
|------|----------|---------|-----------------|
| 53 | TCP + UDP | DNS | LAN (pfSense points clients here) |
| 67 | UDP | DHCP | LAN only (broadcast, not routable to WAN) |
| 8081 | TCP | Web admin UI | LAN only (pfSense does not forward this port) |
**Admin UI**: `http://172.27.0.35:8081/admin`
## Role: DHCP Server for Untrusted Devices
Pi-hole acts as the DHCP server for untrusted LAN devices — Alexa/Echo devices, IoT, and children's machines. By serving DHCP, Pi-hole automatically assigns itself as the DNS server for those clients, ensuring DNS-level ad/content blocking applies without any per-device configuration.
pfSense should have its own DHCP server **disabled** (or scoped to a different subnet/VLAN) for any segment where Pi-hole is authoritative for DHCP, to avoid conflicts.
### DHCP + Docker caveat
Pi-hole's own docs recommend `network_mode: host` for reliable DHCP from Docker (broadcast packets don't traverse Docker NAT cleanly). The current setup uses port mappings + `NET_ADMIN` capability instead, which works in practice. If DHCP stops responding after a container restart or image upgrade, switching to host networking is the fix:
```yaml
# Alternative compose config if DHCP becomes unreliable:
services:
pihole:
network_mode: host # replaces all port: mappings
# remove the ports: section entirely
# admin UI returns to port 80, but WAN can't reach it
# since pfSense won't forward port 80 to this host
```
## Volume Mounts
| Host path | Container path | Contents |
|-----------|----------------|----------|
| `./etc-pihole` | `/etc/pihole` | Pi-hole config, gravity DB, DHCP leases |
| `./etc-dnsmasq.d` | `/etc/dnsmasq.d` | Custom DNS/DHCP overrides |
Both paths are relative to `/home/kenjim/docker-pi-hole/`.
## docker-compose.yml
```yaml
version: "3"
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
ports:
- "53:53/tcp"
- "53:53/udp"
- "67:67/udp"
- "8081:80/tcp"
environment:
TZ: 'America/Chicago'
FTLCONF_MAXCONCURRENTQUERIES: 300
volumes:
- './etc-pihole:/etc/pihole'
- './etc-dnsmasq.d:/etc/dnsmasq.d'
cap_add:
- NET_ADMIN
restart: always
```
## Service Management
```bash
cd ~/docker-pi-hole
docker compose up -d # start
docker compose down # stop
docker compose pull && docker compose up -d # update image
docker compose logs -f pihole # follow logs
# Run pihole commands inside container
docker exec pihole pihole status
docker exec pihole pihole -g # update gravity (blocklists)
docker exec pihole pihole version
```
## Upgrading
Pi-hole updates are released as new Docker image versions:
```bash
cd ~/docker-pi-hole
docker compose pull # pull latest image
docker compose up -d # recreate container
docker exec pihole pihole version # verify new version
```
The volumes (`etc-pihole/`, `etc-dnsmasq.d/`) persist config across upgrades.
## Migration Notes
To move Pi-hole to a new server:
1. Stop the container: `docker compose down`
2. Copy the entire `/home/kenjim/docker-pi-hole/` directory to the new host
3. Install Docker on the new host
4. Run `docker compose up -d` from the copied directory
5. Update pfSense DNS server setting to point to the new host IP
Key data to preserve:
- `etc-pihole/gravity.db` — blocklists
- `etc-pihole/dhcp.leases` — DHCP lease table
- `etc-pihole/pihole.toml` — main config (v6+ format)
- `etc-pihole/local.list` — local DNS overrides
- `etc-dnsmasq.d/` — custom dnsmasq config
## Network Integration
Pi-hole is one of two DNS resolvers on the LAN — some devices use Pi-hole (`172.27.0.35:53`), others use pfSense's built-in Unbound resolver directly.
## Split DNS — Local Overrides
To avoid hairpin NAT issues (LAN clients connecting to the public WAN IP for local services), DNS overrides are configured in **both** resolvers so that `kenjim.com` subdomains resolve directly to `172.27.0.35` from inside the LAN.
### Pi-hole (Local DNS → DNS Records)
| Domain | IP |
|--------|----|
| `git.kenjim.com` | `172.27.0.35` |
| `www.kenjim.com` | `172.27.0.35` |
| `kenji.kenjim.com` | `172.27.0.35` |
### pfSense DNS Resolver (Services → DNS Resolver → Host Overrides)
Same three entries as above — covers clients that use pfSense Unbound instead of Pi-hole.
Without these overrides, LAN clients resolving `git.kenjim.com` get the public WAN IP and connect to pfSense's own HTTPS interface rather than nginx on zet.

View File

@@ -0,0 +1,27 @@
version: "3"
# https://github.com/pi-hole/docker-pi-hole/blob/master/README.md
# Source: /home/kenjim/docker-pi-hole/docker-compose.yml on zet.home.arpa
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
# For DHCP it is recommended to remove these ports and instead add: network_mode: "host"
ports:
- "53:53/tcp"
- "53:53/udp"
- "67:67/udp"
- "8081:80/tcp"
environment:
TZ: 'America/Chicago'
FTLCONF_MAXCONCURRENTQUERIES: 300
# WEBPASSWORD: 'set a secure password here or it will be random'
# Volumes store your data between container upgrades
volumes:
- './etc-pihole:/etc/pihole'
- './etc-dnsmasq.d:/etc/dnsmasq.d'
# https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
cap_add:
- NET_ADMIN
restart: always

View File

@@ -0,0 +1,86 @@
# Samba — zet.home.arpa
SMB file sharing for the home network.
## Overview
| Field | Value |
|-------|-------|
| **Package** | `samba` (Ubuntu package) |
| **Version** | Samba 4.19.5-Ubuntu |
| **Config** | `/etc/samba/smb.conf` |
| **Logs** | `/var/log/samba/log.%m` |
| **Services** | `smbd.service`, `nmbd.service` |
## Shares
| Share name | Path | Read-only | Notes |
|------------|------|-----------|-------|
| `photos` | `/data/ssd-photos` | No | Crucial MX500 SSD — photos library |
| `hsgt10a` | `/data/hsgt10a` | No | HGST 10 TB primary bulk drive |
| `printers` | `/var/tmp` | Yes | Default printer share (unused) |
| `print$` | `/var/lib/samba/printers` | Yes | Printer drivers (unused) |
### Access paths (from Windows/macOS)
```
\\172.27.0.35\photos
\\172.27.0.35\hsgt10a
```
## Configuration (`/etc/samba/smb.conf` — relevant sections)
```ini
[global]
workgroup = WORKGROUP
server role = standalone server
map to guest = bad user
usershare allow guests = yes
log file = /var/log/samba/log.%m
max log size = 1000
[photos]
comment = Photos SSD on Zet
path = /data/ssd-photos
read only = no
browsable = yes
[hsgt10a]
comment = HSGT10 Data Drive
path = /data/hsgt10a
read only = no
browsable = yes
```
## Service Management
```bash
sudo systemctl status smbd nmbd
sudo systemctl restart smbd nmbd
sudo systemctl enable smbd nmbd # already enabled
```
## User Management
```bash
sudo smbpasswd -a <username> # add Samba user
sudo smbpasswd -e <username> # enable user
sudo pdbedit -L # list Samba users
```
## Testing
```bash
testparm # validate smb.conf syntax
smbclient -L 172.27.0.35 -N # list shares anonymously
sudo tail -f /var/log/samba/log.smbd # watch connections
```
## Migration Notes
To migrate to a new server:
1. Install: `sudo apt install samba`
2. Copy `/etc/samba/smb.conf`
3. Recreate Samba users: `sudo smbpasswd -a <username>`
4. Ensure `/data/ssd-photos` and `/data/hsgt10a` are mounted at the same paths
5. Restart: `sudo systemctl enable --now smbd nmbd`

View File

@@ -0,0 +1,116 @@
# Squid Web Proxy — zet.home.arpa
Caching web proxy with content filtering for children's devices on the LAN.
## Overview
| Field | Value |
|-------|-------|
| **Package** | `squid` (Ubuntu) |
| **Version** | Squid 6.14 |
| **Config** | `/etc/squid/squid.conf` |
| **Port** | 3128/tcp |
| **Cache directory** | `/var/spool/squid` (2 GB, UFS) |
| **Access log** | `/var/log/squid/access.log` |
## How It Works
Squid runs as a standard forward proxy. pfSense intercepts HTTP traffic from children's device IPs and redirects port 80 to `172.27.0.35:3128` via NAT port-forward (see [../PROXY-SETUP.md](../PROXY-SETUP.md) for pfSense setup).
```
Child device → pfSense NAT (port 80 → 172.27.0.35:3128) → Squid → Internet
```
## Configuration (`/etc/squid/squid.conf`)
```
http_port 3128
# ACLs
acl children src "/etc/squid/children.txt"
acl blocked_sites dstdomain "/etc/squid/blocked_sites.txt"
acl SSL_ports port 443
acl Safe_ports port 80
acl Safe_ports port 443
acl CONNECT method CONNECT
acl allowed_hosts src 172.27.0.0/24
# Access rules
http_access deny blocked_sites children
http_access deny !Safe_ports
http_access allow allowed_hosts
# Cache
cache_dir ufs /var/spool/squid 2048 16 256
cache_mem 512 MB
maximum_object_size_in_memory 1 MB
maximum_object_size 128 MB
minimum_object_size 0 KB
# Refresh patterns
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i \.(gif|png|jpg|jpeg|ico)$ 10080 90% 43200
refresh_pattern -i \.(css|js)$ 1440 90% 10080
refresh_pattern . 0 20% 4320
pipeline_prefetch 1
collapsed_forwarding on
```
## ACL Files
### `/etc/squid/children.txt` — devices subject to content filtering
Contains one IP per line for children's devices on the `172.27.0.0/24` network.
### `/etc/squid/blocked_sites.txt` — blocked domains
Domains blocked for children (partial list):
```
.facebook.com / .fb.com / .instagram.com / .snapchat.com / .tiktok.com
.x.com / .twitter.com / .reddit.com / .redditmedia.com / .redditstatic.com
.pinterest.com / .youtube.com / .youtu.be / .googlevideo.com
.twitch.tv / .vimeo.com / .dailymotion.com
.netflix.com / .hulu.com / .disneyplus.com
```
## Service Management
```bash
sudo systemctl status squid
sudo systemctl restart squid
sudo systemctl reload squid # reload config without dropping connections
sudo squid -k parse # validate squid.conf syntax
# Watch live traffic
sudo tail -f /var/log/squid/access.log
# Check cache stats
sudo squidclient -h 127.0.0.1 mgr:info
```
## Adding/Removing Children's IPs
Edit `/etc/squid/children.txt` — one IP per line, then reload:
```bash
sudo nano /etc/squid/children.txt
sudo systemctl reload squid
```
## Limitations
- Only intercepts plain **HTTP (port 80)**. HTTPS (port 443) is not filtered.
- To filter HTTPS would require SSL bump (TLS interception) with a custom CA installed on every client device — significantly more complex.
- See [../PROXY-SETUP.md](../PROXY-SETUP.md) for pfSense NAT configuration.
## Migration Notes
To move Squid to a new server:
1. Install: `sudo apt install squid`
2. Copy `/etc/squid/squid.conf`, `children.txt`, `blocked_sites.txt`
3. Initialize cache: `sudo squid -z`
4. Start: `sudo systemctl enable --now squid`
5. Update pfSense NAT rule redirect target to the new server IP

124
zet.home.arpa/ssl/README.md Normal file
View File

@@ -0,0 +1,124 @@
# SSL Certificate — zet.home.arpa
Let's Encrypt certificate for `kenjim.com` subdomains, issued and renewed via acme.sh using GoDaddy DNS-01 challenge.
## Overview
| Field | Value |
|-------|-------|
| **CA** | Let's Encrypt |
| **Tool** | acme.sh v3.1.4 |
| **Challenge** | DNS-01 via GoDaddy API |
| **Key type** | ECC (default in acme.sh v3) |
| **Validity** | 90 days (auto-renewed at ~60 days) |
| **Installed to** | `/etc/nginx/ssl/kenjim.com/` |
| **acme.sh data** | `~/.acme.sh/zet.kenjim.com_ecc/` |
## Covered Domains (SANs)
- `zet.kenjim.com` (primary)
- `git.kenjim.com`
- `www.kenjim.com`
- `kenji.kenjim.com`
- `gt.kenjim.com`
## GoDaddy API Credentials
Stored by acme.sh in `~/.acme.sh/account.conf` after first use. Only needs to be re-exported if rotating the API key.
The API key used is named **"Claude"** in GoDaddy's developer portal (developer.godaddy.com → API Keys).
To re-export credentials for a manual reissue:
```bash
export GD_Key='your-key'
export GD_Secret='your-secret'
```
**Never paste credentials into chat or commit them to this repo.**
## Installed Certificate Files
| File | Purpose |
|------|---------|
| `/etc/nginx/ssl/kenjim.com/fullchain.pem` | Certificate + intermediates (used by nginx) |
| `/etc/nginx/ssl/kenjim.com/key.pem` | Private key (used by nginx) |
Directory ownership: `kenjim:www-data`, mode `750`. Files readable by nginx (`www-data` group).
## Auto-Renewal
acme.sh installs a cron job at install time:
```bash
crontab -l | grep acme # verify cron entry exists
```
On renewal acme.sh:
1. Adds `_acme-challenge` TXT records to GoDaddy DNS via API
2. Requests new cert from Let's Encrypt
3. Copies cert files to `/etc/nginx/ssl/kenjim.com/`
4. Runs `sudo systemctl reload nginx`
5. Cleans up TXT records
The sudoers rule that allows passwordless nginx reload:
```
/etc/sudoers.d/acme-nginx-reload:
kenjim ALL=(ALL) NOPASSWD: /bin/systemctl reload nginx
```
## Manual Reissue
Only needed if the cert is lost or domains change:
```bash
export GD_Key='your-key'
export GD_Secret='your-secret'
~/.acme.sh/acme.sh --issue \
--server letsencrypt \
--dns dns_gd \
-d zet.kenjim.com \
-d git.kenjim.com \
-d www.kenjim.com \
-d kenji.kenjim.com \
-d gt.kenjim.com
~/.acme.sh/acme.sh --install-cert \
-d zet.kenjim.com \
--fullchain-file /etc/nginx/ssl/kenjim.com/fullchain.pem \
--key-file /etc/nginx/ssl/kenjim.com/key.pem \
--reloadcmd "sudo systemctl reload nginx"
```
Note: always pass `--server letsencrypt` — acme.sh v3 defaults to ZeroSSL which has a 24-hour retry delay incompatible with acme.sh's timeout.
## Verify Certificate
```bash
# Check cert served by nginx locally
curl -sv --resolve git.kenjim.com:443:172.27.0.35 https://git.kenjim.com 2>&1 \
| grep -E "subject|issuer|subjectAltName|SSL connection"
# Check expiry
~/.acme.sh/acme.sh --list
# Check from outside the LAN
curl -sv https://git.kenjim.com 2>&1 | grep -E "subject|issuer|< HTTP"
```
## DNS Setup
Public DNS uses CNAMEs to a DDNS-managed A record:
| Record | Type | Value |
|--------|------|-------|
| `lair.kenjim.com` | A | `<WAN IP>` — updated by pfSense DDNS |
| `zet.kenjim.com` | CNAME | `lair.kenjim.com` |
| `git.kenjim.com` | CNAME | `lair.kenjim.com` |
| `www.kenjim.com` | CNAME | `lair.kenjim.com` |
| `kenji.kenjim.com` | CNAME | `lair.kenjim.com` |
| `gt.kenjim.com` | CNAME | `lair.kenjim.com` |
pfSense Dynamic DNS keeps `lair.kenjim.com` updated whenever the ISP WAN IP changes. All subdomains follow automatically via their CNAMEs.
See [../nginx/](../nginx/) for how the cert is used.

82
zet.home.arpa/storage.md Normal file
View File

@@ -0,0 +1,82 @@
# Storage — zet.home.arpa
## Disk Layout
```
NAME SIZE FSTYPE MOUNTPOINT LABEL
nvme0n1 953.9G
├─nvme0n1p1 1G vfat /boot/efi
├─nvme0n1p2 2G ext4 /boot
└─nvme0n1p3 950.8G LVM2_member
└─ubuntu--vg-ubuntu--lv 950.8G ext4 / (OS disk)
sda 931.5G
└─sda1 931.5G LVM2_member
└─crucial--mx500-backup 931.5G ext4 /data/ssd-photos (Crucial MX500 SSD)
sdb 9.1T
└─sdb1 9.1T ext4 /data/hsgt10a (HGST 10TB #1)
sdc 9.1T
└─sdc1 9.1T ext4 /data/hsgt10b (HGST 10TB #2)
sdd 3.6T (unmounted — ws4000a/ws4000b)
├─sdd1 1.8T ext4 ws4000a
└─sdd2 1.8T ext4 ws4000b
```
## Mount Points
| Mount | Device | Size | Used | Free | Use% |
|-------|--------|------|------|------|------|
| `/` | ubuntu--vg-ubuntu--lv | 935 GB | 302 GB | 586 GB | 34% |
| `/boot` | nvme0n1p2 | 2.0 GB | 201 MB | 1.6 GB | 11% |
| `/boot/efi` | nvme0n1p1 | 1.1 GB | 6.2 MB | 1.1 GB | 1% |
| `/data/ssd-photos` | crucial--mx500-backup | 916 GB | 426 GB | 445 GB | 49% |
| `/data/hsgt10a` | sdb1 | 9.1 TB | 7.4 TB | 1.3 TB | 86% |
| `/data/hsgt10b` | sdc1 | 9.1 TB | 7.4 TB | 1.3 TB | 86% |
## fstab (`/etc/fstab`)
```
# OS / boot / swap — installer-generated
/dev/disk/by-id/dm-uuid-LVM-pZkwCzArj53TehlUJeYjQyR5pMsex7qNIPGqddmwnOHy5Rw7eBJvFHdd5fPzVMtw / ext4 defaults 0 1
/dev/disk/by-uuid/a186b998-5a71-4ca5-a7f0-dc36055e5d49 /boot ext4 defaults 0 1
/dev/disk/by-uuid/8D7F-166E /boot/efi vfat defaults 0 1
/swap.img none swap sw 0 0
# Added by Kenji
/dev/disk/by-id/dm-name-crucial--mx500-backup /data/ssd-photos ext4 defaults 0 1
/swap.extra none swap sw 0 0
/dev/sdb1 /data/hsgt10a ext4 defaults 0 1
/dev/sdc1 /data/hsgt10b ext4 defaults 0 1
```
## Samba Shares
| Share | Path | Notes |
|-------|------|-------|
| `photos` | `/data/ssd-photos` | Crucial MX500 SSD, photos library |
| `hsgt10a` | `/data/hsgt10a` | HGST 10 TB primary bulk drive |
## NFS Exports
| Export | Clients | Options |
|--------|---------|---------|
| `/data/hsgt10a` | `172.27.0.0/24` | `rw,sync,no_subtree_check` |
## Notes
- **`sdd` (3.6 TB)** is connected but unmounted. Partitions labeled `ws4000a` and `ws4000b`, previously referenced in fstab as CIFS mounts from `172.27.0.2`. These appear to be historical drive copies — verify before mounting.
- **`/data/hsgt10a` and `/data/hsgt10b`** are at 86% capacity. Monitor closely.
- **SMART monitoring** (`smartmontools.service`) is active — check `smartctl -a /dev/sdX` for drive health.
## Checking Drive Health
```bash
sudo smartctl -a /dev/sda # Crucial MX500
sudo smartctl -a /dev/sdb # HGST 10TB #1
sudo smartctl -a /dev/sdc # HGST 10TB #2
sudo smartctl -a /dev/sdd # unmounted 3.6 TB
sudo smartctl -a /dev/nvme0n1 # OS NVMe
```