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:
83
zet.home.arpa/README.md
Normal file
83
zet.home.arpa/README.md
Normal 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
|
||||
```
|
||||
61
zet.home.arpa/nfs/README.md
Normal file
61
zet.home.arpa/nfs/README.md
Normal 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
|
||||
114
zet.home.arpa/nginx/README.md
Normal file
114
zet.home.arpa/nginx/README.md
Normal 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
|
||||
99
zet.home.arpa/nginx/kenjim.conf
Normal file
99
zet.home.arpa/nginx/kenjim.conf
Normal 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;
|
||||
}
|
||||
156
zet.home.arpa/pihole/README.md
Normal file
156
zet.home.arpa/pihole/README.md
Normal 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.
|
||||
27
zet.home.arpa/pihole/docker-compose.yml
Normal file
27
zet.home.arpa/pihole/docker-compose.yml
Normal 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
|
||||
86
zet.home.arpa/samba/README.md
Normal file
86
zet.home.arpa/samba/README.md
Normal 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`
|
||||
116
zet.home.arpa/squid/README.md
Normal file
116
zet.home.arpa/squid/README.md
Normal 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
124
zet.home.arpa/ssl/README.md
Normal 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
82
zet.home.arpa/storage.md
Normal 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
|
||||
```
|
||||
Reference in New Issue
Block a user