112 lines
4.9 KiB
Markdown
112 lines
4.9 KiB
Markdown
# Homeserver — Dell OptiPlex 3000
|
||
|
||
The OptiPlex (`192.168.30.20`, Servers VLAN) is the homeserver. It runs the
|
||
Omada controller, Pi-hole, Nginx Proxy Manager and Home Assistant in Docker;
|
||
all web UIs are served over HTTPS under `*.home.staffenberger.at`. Set up on
|
||
2026-10-04.
|
||
|
||
| Service | Runs on | Internal address | Name (via NPM, HTTPS) |
|
||
|---|---|---|---|
|
||
| Omada controller | OptiPlex (Docker, host network) | https://192.168.30.20:8043 | omada.home.staffenberger.at |
|
||
| Pi-hole | OptiPlex (Docker) | http://192.168.30.20:8081/admin | pihole.home.staffenberger.at |
|
||
| Nginx Proxy Manager | OptiPlex (Docker) | http://192.168.30.20:81 | (not proxied yet) |
|
||
| Home Assistant | OptiPlex (Docker, host network) | http://192.168.30.20:8123 | ha.home.staffenberger.at |
|
||
| OctoPrint | Raspberry Pi | Pi IP, port 80 | octoprint.home.staffenberger.at |
|
||
| Old Pi-hole | Synology NAS | 192.168.30.10 | to be switched off |
|
||
|
||
Compose files live in `~/omada`, `~/pihole`, `~/npm` and `~/homeassistant` on
|
||
the OptiPlex; copies with notes are in [`../docker/`](../docker/). SSH from the
|
||
PC: `ssh optiplex`.
|
||
|
||
## Hardware check
|
||
|
||
Dell OptiPlex 3000: Core i3-12300T (12th gen, 35 W "T" part), 16 GB DDR4, 512 GB NVMe SSD, genuine Dell 65 W power supply — matched the listing.
|
||
|
||
| Check | Result |
|
||
|---|---|
|
||
| Memtest86+ | 2 passes, 0 errors (needs Secure Boot off to boot) |
|
||
| CPU stress test (stress-ng, 10 min) | Max 88 °C, no throttling |
|
||
| Dell ePSA diagnostics | Passed |
|
||
| Network link | 1000 Mb/s |
|
||
| USB ports | All working |
|
||
| SSD SMART | ~15,400 power-on hours, 0 media errors, extended self-test passed twice |
|
||
|
||
The Windows key was read with ShowKeyPlus before wiping. An OEM key in the
|
||
firmware stays there after installing Linux and only reactivates Windows on
|
||
this machine.
|
||
|
||
## SSD problem and fix
|
||
|
||
The system froze under disk load because the NVMe link threw fatal PCIe
|
||
errors. Stable since adding a thermal pad and the kernel option `pcie_aspm=off`.
|
||
|
||
**The drive:** Toshiba XG4 THNSN5512GPUK (512 GB NVMe), an HP OEM part (HP P/N
|
||
902944-002, made 2017), fitted by a refurbisher — not the original Dell drive.
|
||
|
||
**Symptoms:** load average around 37 with idle CPU, commands hanging, kernel
|
||
log entries `PCIe Bus Error: severity=Uncorrectable (Fatal)` followed by
|
||
controller resets.
|
||
|
||
**Findings:**
|
||
|
||
- The board's "M.2 SSD THERMAL PAD AREA" under the SSD was bare. The drive
|
||
reached 81 °C (warning 78 °C, critical 82 °C). With a thermal pad (two
|
||
stacked), idle dropped from 68 °C to ~46 °C, ~70 °C under sustained writes.
|
||
- The errors persisted at low temperature, so heat was not the root cause. The
|
||
SSD's AER registers show an FCP error (flow-control protocol, classified
|
||
fatal), most likely triggered by the L1.2 link power state the BIOS enables.
|
||
- The BIOS declares ASPM unsupported (FADT), so the kernel never controls ASPM.
|
||
`pcie_aspm=off` makes the kernel leave AER and LTR to the BIOS, which
|
||
tolerates the error. With kernel control (`pcie_aspm.policy=performance`) the
|
||
fatal errors returned every 30–60 seconds.
|
||
- The link trains at full speed (8 GT/s, x4). fio: ~1,380 MB/s read, ~500 MB/s write.
|
||
|
||
**Current setting:** `GRUB_CMDLINE_LINUX_DEFAULT="pcie_aspm=off"` in
|
||
`/etc/default/grub`. The APST option (`nvme_core.default_ps_max_latency_us=0`)
|
||
was removed again — it only made the drive run hotter.
|
||
|
||
**Health checks:**
|
||
|
||
```bash
|
||
sensors | grep -A1 Composite
|
||
sudo smartctl -a /dev/nvme0n1 | grep -iE "temp|media"
|
||
sudo lspci -vv -s 01:00.0 | grep -E "UESta|CESta"
|
||
```
|
||
|
||
Baseline: Warning Comp. Temperature Time = 5 minutes. A new 500 GB NVMe
|
||
(~€30–40) would remove the workaround entirely.
|
||
|
||
## Ubuntu Server and SSH
|
||
|
||
Ubuntu Server 26.04 LTS, headless, no disk encryption, SSH key logins only.
|
||
|
||
- **Install choices:** full disk via LVM, OpenSSH server, no featured snaps, no
|
||
encryption (so it boots unattended after power cuts).
|
||
- **BIOS:** Secure Boot on, AC Recovery set to Power On.
|
||
- **SSH key:** `~/.ssh/id_ed25519_homelab` (same per-client key as for the Pi),
|
||
copied with `ssh-copy-id`. Entry in `~/.ssh/config` on the PC:
|
||
|
||
```
|
||
Host optiplex
|
||
HostName 192.168.30.20
|
||
User david
|
||
IdentityFile ~/.ssh/id_ed25519_homelab
|
||
IdentitiesOnly yes
|
||
```
|
||
|
||
- **Password login disabled** in `/etc/ssh/sshd_config.d/00-no-password.conf`
|
||
(`PasswordAuthentication no`, `KbdInteractiveAuthentication no`). The `00-`
|
||
prefix makes it win over Ubuntu's `50-cloud-init.conf`.
|
||
- **Port 53 freed for Pi-hole:** `DNSStubListener=no` in
|
||
`/etc/systemd/resolved.conf.d/no-stub.conf`, and `/etc/resolv.conf` linked to
|
||
`/run/systemd/resolve/resolv.conf`.
|
||
|
||
## Docker
|
||
|
||
Installed from Docker's official apt repository (`docker-ce`,
|
||
`docker-compose-plugin`); user `david` is in the `docker` group. Service
|
||
details: [omada](../docker/omada/README.md), [pihole](../docker/pihole/README.md),
|
||
[npm](../docker/npm/README.md), [homeassistant](../docker/homeassistant/README.md).
|
||
|
||
All of the above was done by hand. Turning it into an Ansible playbook is
|
||
tracked in [todo.md](todo.md).
|