Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
361fbc7416 | ||
|
|
9e03da752c | ||
|
|
0817cf3b0b | ||
|
|
b487218a81 | ||
|
|
f4367950b5 | ||
|
|
10c37eafed | ||
|
|
7c78facff3 | ||
|
|
18ba36bfc6 | ||
|
|
c42f0879ee | ||
|
|
300df1b81a | ||
|
|
cc6e62f7be | ||
|
|
a92b6838be | ||
|
|
e95d16fc3e | ||
|
|
953dee0c7f | ||
|
|
42b94b1b09 | ||
|
|
db122119e6 | ||
|
|
460dae1005 | ||
|
|
ac32df2cc2 | ||
|
|
29cf3bef40 | ||
|
|
c567aae14d | ||
|
|
24cd30909d | ||
|
|
3149125b68 | ||
|
|
af16641b00 | ||
|
|
64ea55f09f | ||
|
|
323ab35aa6 | ||
|
|
c751968835 | ||
|
|
aaadb6129b | ||
|
|
2cb7ba4ded | ||
|
|
e8f6b04d04 | ||
|
|
769d81b122 | ||
|
|
c4f19b1601 | ||
|
|
6e8cfccf92 | ||
|
|
7168e3cdf3 | ||
|
|
3548055780 | ||
|
|
ffc073e4f9 | ||
|
|
0bb71afdb2 | ||
|
|
965607587c | ||
|
|
8c185ff083 | ||
|
|
63f2212ea7 | ||
|
|
3ea3b208dd | ||
|
|
24b381808a | ||
|
|
0d0a2fc115 | ||
|
|
2a12ca2c90 | ||
|
|
8c80ab77c0 | ||
|
|
182755693f | ||
|
|
13a8cb417c | ||
|
|
ab71227824 | ||
|
|
3138eac005 | ||
|
|
459b78b63e | ||
|
|
145bf39639 | ||
|
|
07e2f5c71c | ||
|
|
c2952c22bc | ||
|
|
dfff88763d | ||
|
|
8f521feaaf | ||
|
|
e100c53522 | ||
|
|
1fda69a887 | ||
|
|
462b99d365 | ||
|
|
aab8682175 | ||
|
|
4eb87f0f9d | ||
|
|
6e40e47de7 | ||
|
|
e3cc066073 | ||
|
|
bf6443fca4 | ||
|
|
b269bce196 | ||
|
|
87b5a9b795 | ||
|
|
5821d5f7ee | ||
|
|
fc9a4ee8f5 | ||
|
|
762b7d60e3 | ||
|
|
85194b90e9 | ||
|
|
239bb2d7f4 | ||
|
|
298d8ec9ee | ||
|
|
0ecd691e64 | ||
|
|
286bec018c | ||
|
|
6206411b7d | ||
|
|
571ca91403 | ||
|
|
3e9ea2fc71 | ||
|
|
0b67d3c2b5 | ||
|
|
e7be216a79 | ||
|
|
dea224e90c | ||
|
|
0db9df80d1 | ||
|
|
63f95ba65c | ||
|
|
2c42d6fe47 | ||
|
|
c8531eb33f | ||
|
|
7f898eb29b | ||
|
|
d790058e12 | ||
|
|
52bdf2e975 | ||
|
|
42b2e64c76 | ||
|
|
8519cf6368 | ||
|
|
367086f953 | ||
|
|
c5a597830e | ||
|
|
9ae0a0e80c | ||
|
|
abb37a030b | ||
|
|
a7d7688353 | ||
|
|
9da624e2e0 | ||
|
|
01e93025dd | ||
|
|
7cb5f2bbc5 | ||
|
|
5b73dbc3f3 | ||
|
|
034ddc2dc0 | ||
|
|
30c33d61f9 | ||
|
|
1031ade2b6 | ||
|
|
5d3291e8db | ||
|
|
a0163bb188 | ||
|
|
fcbe79327c | ||
|
|
a23ba3441e | ||
|
|
09858410eb | ||
|
|
7f5c44e3d9 | ||
|
|
e1fe951aa9 | ||
|
|
0f3dbd7ca3 | ||
|
|
51675d140c | ||
|
|
41b2151716 | ||
|
|
7e48f76aed | ||
|
|
55f195097c | ||
|
|
111c8e1701 | ||
|
|
2364adfba2 | ||
|
|
0ed26f88ac | ||
|
|
f9aea1b3d5 | ||
|
|
d2da8f477d | ||
|
|
53ad76813e | ||
|
|
ba6cb3b8e0 | ||
|
|
e236e02eee | ||
|
|
d3c463f983 | ||
|
|
f38c081d8e | ||
|
|
da875b6e96 | ||
|
|
35cc8b8dd3 | ||
|
|
261aeb3e9c | ||
|
|
12292fa985 | ||
|
|
48423e45f1 | ||
|
|
5128da09b0 | ||
|
|
d915e99884 | ||
|
|
7c68b720f2 | ||
|
|
3358341330 | ||
|
|
6712f6c8ed | ||
|
|
43a51fc19a | ||
|
|
e758a34852 | ||
|
|
25ddf9567f | ||
|
|
ba17723775 | ||
|
|
41bd1b12d4 | ||
|
|
66d20c374f | ||
|
|
d699ae32fb | ||
|
|
a8e63663d8 | ||
|
|
7910bdf2fd | ||
|
|
89cec8b18e | ||
|
|
ee5946d863 | ||
|
|
73f5295354 | ||
|
|
9ea685d3bd | ||
|
|
7bdafb9c56 | ||
|
|
2904d77d70 | ||
|
|
6e9b9340e7 | ||
|
|
b7e2bf426f | ||
|
|
d1171375b8 | ||
|
|
b9f011bfb8 | ||
|
|
cd9f6e1478 | ||
|
|
e3019d155f | ||
|
|
1f90f95f85 | ||
|
|
ea58ec4d99 | ||
|
|
53a1f0fff9 | ||
|
|
eefa06ce72 | ||
|
|
6907022126 | ||
|
|
408146f5d1 | ||
|
|
989a019d69 | ||
|
|
e781afe19d | ||
|
|
71f1948ee4 | ||
|
|
58de1ff16a | ||
|
|
05a41cd2dc | ||
|
|
08a1b2def5 | ||
|
|
6752589a98 | ||
|
|
8090158869 | ||
|
|
df4ebe465c | ||
|
|
dfafee6c66 | ||
|
|
210aec460b | ||
|
|
cd7f8d3d10 | ||
|
|
0346280185 | ||
|
|
076e4b85dc | ||
|
|
8adcb18fb4 | ||
|
|
40b7c2c269 | ||
|
|
eb26006dbe | ||
|
|
681568824e | ||
|
|
731011add6 | ||
|
|
76354d602f | ||
|
|
b3edf696f7 | ||
|
|
be9bd5e15d | ||
|
|
8ac0c77a9c | ||
|
|
4639b830de | ||
|
|
fb60fe0875 | ||
|
|
b5b6e14b8d | ||
|
|
6c898b0df6 | ||
|
|
dfac9e9e68 | ||
|
|
89dd4db659 | ||
|
|
42cb1a2158 | ||
|
|
aec09e46bd | ||
|
|
862b5d3d80 | ||
|
|
b2dd29c4fb | ||
|
|
7284541bbf | ||
|
|
3d08dd1940 | ||
|
|
bb69575045 | ||
|
|
9ce330be4f | ||
|
|
8ef194c3c9 | ||
|
|
052fab6ef1 | ||
|
|
8a15180759 | ||
|
|
499c5063ba | ||
|
|
e86f7b9df4 | ||
|
|
20701f7e8d | ||
|
|
7555871713 | ||
|
|
da1f640a9d | ||
|
|
3f9ae13bd5 | ||
|
|
8e4930a761 | ||
|
|
f34ccf4003 | ||
|
|
6377bd4841 | ||
|
|
f8a0539e11 | ||
|
|
0054284464 | ||
|
|
68462fda76 | ||
|
|
7dd2a19fca | ||
|
|
6ff7804ecb | ||
|
|
101abf28e2 | ||
|
|
e985961dfe | ||
|
|
238b3061a4 | ||
|
|
db7b229d1f | ||
|
|
2d9ab1608a | ||
|
|
24cf6fe31f | ||
|
|
dfcb9b17bc | ||
|
|
fc3a65b2e8 | ||
|
|
b9d0ef8638 | ||
|
|
1fd8ea1a7b | ||
|
|
886d8ec86a | ||
|
|
19d5fe6fd1 | ||
|
|
7ef95fdf39 | ||
|
|
059e13b3df | ||
|
|
90a9308cf2 | ||
|
|
523785dd41 | ||
|
|
a23179efd9 | ||
|
|
58ebe611be | ||
|
|
2f83407ea3 | ||
|
|
a4800fb385 | ||
|
|
e0b9370c32 | ||
|
|
0b1df40420 | ||
|
|
0731ac005d | ||
|
|
979ed53297 | ||
|
|
9677685704 | ||
|
|
e76093a40d | ||
|
|
147b2b3329 | ||
|
|
f944bf2290 | ||
|
|
b18ff2b04e | ||
|
|
e9341a4f7e | ||
|
|
f7b3e96035 | ||
|
|
37ea10b0ee | ||
|
|
8e68264894 | ||
|
|
0d07c5eea5 | ||
|
|
9677c6c30f | ||
|
|
ed63db2197 | ||
|
|
7185d72e5b | ||
|
|
3714c1f5af | ||
|
|
9f66c5e185 | ||
|
|
a8e8891fec | ||
|
|
e4c4552903 | ||
|
|
90d7ea750b | ||
|
|
15dabf72b6 | ||
|
|
16815d79ba | ||
|
|
d1a6766211 | ||
|
|
5e44c47275 | ||
|
|
6ccf121a80 | ||
|
|
4b4df4b5dc | ||
|
|
bbf54379c5 | ||
|
|
a255c7847a | ||
|
|
0480ff7467 | ||
|
|
1ed31b84e2 | ||
|
|
6002290702 | ||
|
|
1988c4639e | ||
|
|
281b3294d6 | ||
|
|
cee99b43fe | ||
|
|
c6f40983de | ||
|
|
d70587f1fa | ||
|
|
b04a710394 | ||
|
|
0a485a9888 | ||
|
|
1fc1034e47 | ||
|
|
7961f149f4 | ||
|
|
1473fda4de | ||
|
|
ff18e9a8a8 | ||
|
|
ca22613094 | ||
|
|
98a7b694fd | ||
|
|
b140d90abc | ||
|
|
654d65799c | ||
|
|
1eb91748c2 | ||
|
|
393fc31f02 | ||
|
|
f2ba966089 | ||
|
|
e885db4886 | ||
|
|
356d61308a | ||
|
|
d100d5cd97 | ||
|
|
a0ae730753 | ||
|
|
061d422baa | ||
|
|
e249b5a2ee | ||
|
|
3a0388a206 | ||
|
|
ff0a2f9c5c | ||
|
|
f60fed7f83 | ||
|
|
d74d1a7bf8 | ||
|
|
734e0d727e | ||
|
|
da848ab004 | ||
|
|
28f0021a61 | ||
|
|
b81ba4351f | ||
|
|
33f18f8bd5 | ||
|
|
5d31500772 | ||
|
|
514fa29c65 | ||
|
|
de8577c868 | ||
|
|
f15ec64dd8 | ||
|
|
824591e199 | ||
|
|
2b346dfcb7 | ||
|
|
93af46c9b6 | ||
|
|
c19f033ba7 | ||
|
|
55cc70bb3a | ||
|
|
4861ef3c17 | ||
|
|
c168950f5d | ||
|
|
77cd9e4276 | ||
|
|
1cd98cb351 | ||
|
|
92fd1fc679 | ||
|
|
7f523505a4 | ||
|
|
b577d69aa1 | ||
|
|
0aefb7c6e9 | ||
|
|
0f9ecd28cc | ||
|
|
5e8f0a032f | ||
|
|
aae8519ec7 | ||
|
|
f9588e9f13 | ||
|
|
09cf85896d | ||
|
|
4d8b6a48f1 | ||
|
|
40ddbdcd52 | ||
|
|
c2f8926ba9 | ||
|
|
9a13177fef | ||
|
|
88f5d97b16 | ||
|
|
cc7cab1fe1 | ||
|
|
83885c164a | ||
|
|
04e748beeb | ||
|
|
59d3395dd4 | ||
|
|
d8e3896ef2 | ||
|
|
68afecc99d | ||
|
|
b760001eba | ||
|
|
fa79e7a612 | ||
|
|
49c5f72698 | ||
|
|
79e884a7ad | ||
|
|
c142a7e935 | ||
|
|
f6c10ca88c | ||
|
|
cfaa9c9e27 | ||
|
|
bdf5fe1d5c | ||
|
|
86ef80d16d | ||
|
|
086262f7f7 | ||
|
|
950d4bd846 | ||
|
|
2238005774 | ||
|
|
c4350c8369 | ||
|
|
518fb78781 | ||
|
|
dccff393da | ||
|
|
51167db84b | ||
|
|
6b9b970464 | ||
|
|
663794061d | ||
|
|
0ba7e8a95b | ||
|
|
d4214b6dd8 | ||
|
|
4ce6fcec75 | ||
|
|
b36d7c5acc | ||
|
|
44a16bd862 | ||
|
|
bb6cf0db4f | ||
|
|
1094e77ec1 | ||
|
|
40705cb1bf | ||
|
|
16f2bac0fb | ||
|
|
5bb55994f7 | ||
|
|
7be9a3f7b2 | ||
|
|
bf4eb46335 | ||
|
|
93707196e7 | ||
|
|
6eb2f74118 | ||
|
|
bc8182aa3f | ||
|
|
c597890d06 | ||
|
|
39a8ef74fb | ||
|
|
ebfad8112c | ||
|
|
55a238b32c | ||
|
|
2bec8f92e6 | ||
|
|
16133b017f | ||
|
|
31ab20e352 | ||
|
|
0b29d4223b | ||
|
|
625337489e | ||
|
|
0413ec1c19 | ||
|
|
889fd5215c | ||
|
|
3b892a7d02 | ||
|
|
de464a62b8 | ||
|
|
b909022d66 | ||
|
|
f06ea0e95a | ||
|
|
c69c94ab57 | ||
|
|
1a9d299f10 | ||
|
|
d49a0d73a3 | ||
|
|
6420c21d6a | ||
|
|
68cd97803d | ||
|
|
95133ccbe8 | ||
|
|
1ab362a86e | ||
|
|
0d61e55557 | ||
|
|
cbdae40a08 | ||
|
|
9b489462eb | ||
|
|
3917c1bded | ||
|
|
c079f67c1c | ||
|
|
c85f0401b1 | ||
|
|
8053fb889a | ||
|
|
0a36f6f536 | ||
|
|
18a47b96f2 | ||
|
|
fed2b30f60 | ||
|
|
d6f3cd3b50 | ||
|
|
b5e097f0fb | ||
|
|
c7c1028462 | ||
|
|
1b734a756c | ||
|
|
ca391b2a9c | ||
|
|
f2306bcda0 | ||
|
|
d6de99ba90 | ||
|
|
d934f9bb47 | ||
|
|
385abd1b2d | ||
|
|
cee5f45252 | ||
|
|
e11463a0e4 | ||
|
|
f03f0cb7de | ||
|
|
0028475380 | ||
|
|
15de7b7f29 | ||
|
|
bb4e4c4b10 | ||
|
|
8926acb805 |
@@ -0,0 +1,122 @@
|
||||
# Hi, I'm Chase (Ced) Dumphord
|
||||
### Digital Systems Engineer | Infrastructure | Automation | RF Edge Systems
|
||||
|
||||
> **Live Portfolio:** https://chasedumphord.com
|
||||
> **Live NOC Dashboard:** https://noc.chasedumphord.com
|
||||
|
||||
---
|
||||
|
||||
## 🧠 About
|
||||
|
||||
Digital Systems Engineer with 10+ years of experience across industrial automation, manufacturing systems, and data-driven infrastructure. Currently at GE Aerospace Digital Team specializing in machine data integration, dashboard development, and system-level visibility. Hands-on homelab engineer bridging physical equipment with modern digital platforms. Increasingly integrating AI tooling for system documentation, automated diagnostics, and workflow acceleration.
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Live Sites
|
||||
|
||||
| Site | URL | Description |
|
||||
|------|-----|-------------|
|
||||
| Portfolio | https://chasedumphord.com | Personal portfolio — projects, stack, resume |
|
||||
| NOC Dashboard | https://noc.chasedumphord.com | Live infrastructure visibility — 28 systems |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Ced's NOC — Live Infrastructure Observability
|
||||
|
||||
Real-time network operations center dashboard monitoring 28 homelab systems across 6 infrastructure layers.
|
||||
|
||||
### How It Works
|
||||
|
||||
```
|
||||
Proxmox Biggie (Cron every 5min)
|
||||
→ noc_update.py pings 28 systems
|
||||
→ writes data/noc-status.json
|
||||
→ git push to ced-portfolio
|
||||
→ GitHub Pages deploys (~30s)
|
||||
→ Browser fetches every 30s
|
||||
→ Live dashboard updates
|
||||
```
|
||||
|
||||
### Systems Monitored
|
||||
|
||||
- **6-node Proxmox Cluster** — BigWorld, Biggie, Snoop, TooShort, Tupac, DrDre
|
||||
- **12-node K3s Cluster** — 3 control plane (django-1/2/3) + 9 workers (ingress, data, monitoring groups)
|
||||
- **TrueNAS** — Network attached storage
|
||||
- **Nginx Proxy Manager** — Reverse proxy layer
|
||||
- **Prometheus + Grafana + Uptime Kuma** — Full observability stack (Prometheus actively scraping)
|
||||
- **Dashy + Home Assistant + PrimeStation** — Services layer
|
||||
- **APRS iGate x2** — RF edge systems (home + mobile)
|
||||
|
||||
### Automation
|
||||
|
||||
- Script: `~/scripts/noc_update.py` running on Biggie (`10.10.30.192`)
|
||||
- Cron: `*/5 * * * *` — every 5 minutes
|
||||
- Log: `/var/log/noc_update.log`
|
||||
- Auth: GitHub Personal Access Token via baked remote URL
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Infrastructure Overview
|
||||
|
||||
| Layer | Systems | Count |
|
||||
|-------|---------|-------|
|
||||
| Compute | Proxmox VE cluster | 6 nodes |
|
||||
| Orchestration | K3s Kubernetes | 12 nodes |
|
||||
| Storage | TrueNAS | 1 |
|
||||
| Networking | Nginx Proxy Manager, Cloudflare Tunnels, UniFi VLANs | 4 VLANs |
|
||||
| Monitoring | Prometheus, Grafana, Uptime Kuma, Custom NOC | 4 services |
|
||||
| Edge | APRS iGate (home + mobile), Direwolf TNC | 2 nodes |
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Featured Projects
|
||||
|
||||
### 📊 Ced's NOC Dashboard
|
||||
|
||||
Real-time monitoring system with live system health, latency tracking, severity-based alerts, and layer filtering.
|
||||
|
||||
- **Live:** https://noc.chasedumphord.com
|
||||
- **Source:** https://github.com/ced4568/ceds-noc
|
||||
|
||||
### 🧱 Ced's HomeLab
|
||||
|
||||
Full enterprise-style homelab with Proxmox clustering, K3s orchestration, VLAN segmentation, and full observability stack including Prometheus scraping.
|
||||
|
||||
- **Source:** https://github.com/ced4568/ceds-homelab
|
||||
|
||||
### 📡 APRS iGate (RF Edge System)
|
||||
|
||||
Dual-node RF-to-internet gateway. Raspberry Pi + Direwolf TNC. Live on aprs.fi.
|
||||
|
||||
- **Source:** https://github.com/ced4568/ceds-aprs-igate
|
||||
|
||||
---
|
||||
|
||||
## 🧰 Tech Stack
|
||||
|
||||
**Infrastructure:** Proxmox VE • K3s • Docker • TrueNAS • Nginx Proxy Manager • Cloudflare Tunnels
|
||||
|
||||
**Monitoring:** Prometheus • Grafana • Uptime Kuma • Custom NOC Dashboard
|
||||
|
||||
**Networking:** UniFi • VLAN Segmentation • Cloudflare DNS
|
||||
|
||||
**Edge / RF:** Direwolf • APRS-IS • Raspberry Pi • RTL-SDR
|
||||
|
||||
**Development:** Python • Bash • JavaScript • HTML/CSS • Git
|
||||
|
||||
**AI & Automation:** Claude (Anthropic) • LLM-assisted Documentation • Prompt Engineering
|
||||
|
||||
---
|
||||
|
||||
## 👤 Connect
|
||||
|
||||
[](https://www.linkedin.com/in/toochase-dumphord/)
|
||||
[](https://github.com/ced4568)
|
||||
[](https://chasedumphord.com)
|
||||
[](https://noc.chasedumphord.com)
|
||||
|
||||
📧 chasedumphord@gmail.com | 📍 Oxford, MS
|
||||
|
||||
---
|
||||
|
||||
> This is not a static portfolio — it is a live representation of working systems.
|
||||
@@ -0,0 +1,93 @@
|
||||
%PDF-1.4
|
||||
%“Œ‹ž ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 8 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260502182436+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260502182436+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Count 2 /Kids [ 4 0 R 5 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2874
|
||||
>>
|
||||
stream
|
||||
Gb!SmgN)%.&q0LUoM\eYQ"42Il>79h:,K5HN29,5<qunG+UK*Ni..UD:$ou>2ZZfUXG^Abg+#m'YpC#r!/IIJ?YG(G5Bc]]9E79#iV^h&gO]/%Cp3<Dr#.3NB7HH)Au%NTHQES"Ibu7*'YMo(HtsE]h\oYkBE3J8*s;Z^eFG00)1`/Zc9[@Or2;S+IQ=_a><&9^cDm1OSh4ObE"dP_(XKA%$1nq$/=7lU]0=FP[,?I5*RYggL!F5JEXimsP-(O;hS]9K0`Qh8s+WaTj0l.NDqXd(VX9Nmg=qDlpK`FQXnP>:jc1>E#IkN4>_o4)=:DNY?LT4qbB,12c5#-h_]__&Kjo>$b-39+X*8e3.e1-d)<8#a#qL[&p"5=l0]l!i)%686%6LrUm;(:U1\@7''Ma(6+mt`C1%9h2nXr,=SWRRF3Uem#@-B:OIOl&40&4YNW\&>lU]1<L`9B:jf5hq`IWdLmZm,\H5F)ThEBf]0ZZ-9$WdLIDk95mK,hB:FYt2Y$8>OcYOe*@e<n;W*q88->ZtJ=qp=%n;,gWU&n(6@PER/LtKh_PsJ@Xkb('<]H[QPTm,G[[dCJ#*6g@;8%PNV*_qu,YhI.shXO4UIJ%q"7ScP]AK)HS"[.t1K=_=JWq7LUl4KW4XL[B76G]n>fu+3tpOWcZ%2"FS6;+g;!,mkj.m"dUuU"74D)]b0lWca@%`d&m<GF@HD\+)"C_RfgoImA0Wmn-Ktf;u[>Cc;Y9o!W5I-Q/HAtJVE<*3J`YjZGn9(OKc)s0QLE\/g8i4]>2i#,$(pSUr4KRCH+CbbLQJD.@&n,&[+L[JnPgWcu)5Y`JSSZ44N#WF-^nkcZk88&V&4C*1jAGBCT_:r*Jlh10]]>^3YlW,B0305Oqog$*LA=WqY>-krLqa>WdgE'^PV^R?A0MQpcb.O$^sQVWN=%KTl!K?J[j^N\\\U1/2J8aKZhDr6^5EDVf7(0io[9*RF@!`aA1HE-DIJ>4NS&\9F$=%n]5_ZBD?@\HicKr^SE;mH[9/aG?l2+p1XWZN;F&_$s/g:iVf]A;%HY"\juSbq;gT@_.4kbdnA-YU&fE61_lP5#]:`WQY_^RYUedeb;K`T+J#aa'<-25N4l@'D/DTS@@d1-PDX=Gk1[OI_:fnXLTRo%<QQfARhpr?pL"Pn7UWI*9S0YjucnF16tSLo4'ifCpSco=\uc)^B7`3_76qg!I'4;7f/s32oKLA*X[g,B/'%pC/Pnh1+>n\>>ui[*@$R]FcIBJ?>VMYAolQq%\)6rZ7V9PcLKn!NRGFEq35Z8&\FoESVuk-JrQS@K+$2B]d0rSCprNo>Vt).J-,+'qnijq=plfb["\-a5*9R%6i(K7Qo5*])94kh9(M*0%)*%*[8iYc,-GjW5_^,/iCd4-7/U30aPPr"Jr]jlM/_dRfYFM,mVF8CLCnX@f>QYQg_Qt0kDfiRnEmLhf-2e$0Jp$7,6ZeG5*ld.l+GsMrVJ3PaRD8m?+@j-n=p=;CW&2D9=d*>AJm(/L,>E1\Dct,YsI<L;ZV(e;c-'mqhIJD:'K?A`>3^\MCT"RoUs,>oK2Ss_riek)\^Fl0VQ5Z14]m)mlM1(r@OqJp[8V8':]Ds>@(-*49eJu.U9\nO)NDZF0S+t\jMNX=O^=j6/p\Fg&s^S;K4"oE$Z3J@W@@PR4cGWN=IZ45ESpQMRn#=Cn]njV@l4JPI]H@"DKPZ)+o5t'T6F\d*)V_h5]8re'7N42Aok\&O6(6F`q8*W_SkB7WOo;9&]Q6''"UTnkMWNQGO]]au^JAlXE;7quIh:$bru;2@Gek:t._SDm%D61F1I?;&J+M!.f2@if'd+Qq\[\+:KVrkXj"@L_FRP@\mT^66aSFohCKUWL-U:I'K4fO/Jl-_*Xu`,a2>A78mtB;M>.AMD^Uj"0"PA<EZTAQE>CQU7B#T*mDj&?/mnH,,pAs%>7kM'/:nB_:YVX.b''3B>npDf\MBL9_K54:,"_CnSn<MYEsI^bM1/#Oo4#Qg7*dler7+TWpjNA&"HR`%urm,><^tdDbg+cf&X!RS(m\lm6_+JFJ0u`[\fK6"HMg:Ca+lO,5eBTjA0QkP0mXk>lphT'ao.5hf?L7b3f"2h^*76PB:ouY9nSQX1NmD+!itj"p6DrI=r#+M4im2W.qh.!QkGh>?]m!%m*+*a0f8KD?DZq*,'lgAEkIh<3pJCB\_-#rV>\"OGR$Im81F(g)4eo`Q^&SDssaLO*%_+bVH/TG(6OV[nmTG];;q"#'I2tUPY8%OWi2ZWa%F@@?iM<&p>u#1QYd@e(B#bOB/@&VSAEuW&,VS]cdi#Ah#nGNLEcS<NQY'.02`#7912$XgDe]7>L/3NM[^)hEF6'VE)[UF``<?<QpL=[E_uaeU/qoL]iigjA77HAQC`BEFoY>?S#k+dN$"BK+d4sRj[@B34L`SI"fS;BoSo%Kj]R)%\\WGkh>GID_VnO]8UN;[[k,Upb>bHiS,aD=/Lk>X1BZb2k(,;73,q7-HJN)!I0NqVRNXO/6K$QH-#"-$^iJcoCXN-erJ?/3_ck`Y>&>qVX2Pmp-r)H\eps?"HOeOK@Q_&\aBKV:p:Y2;k9qq$K4%20oZ&qUa9nDL753^el`=@-V[4])KI)J6%iSCibra)dKgu''c0u?o;7nRQnaeE8Ubm5fs!Ybo+ErUF*+S;Pa8"B8kV-4=!gnu#WtT7[(;b]HF]5;:p#?:Jk1\g[boe9l;If=`7H5ANrB*ZT5cJOj3u8[Jq<ba/B_K7l@9H9/=()-`@dB++(ChFUtfL,AVNL%dn<LCWu`MN@/E[V&JTl45dkl(%)`)N,H#_!Wa8*UiJLQ5V+sOSV2g^I`L[W&'/:;7N!#%\DS918!o)(;.T&2&08mU56N~>endstream
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2700
|
||||
>>
|
||||
stream
|
||||
Gb!TY>C5)6(5D;L/(R^EAl!An2GC:[8QquO23?MgU,TrT5uZJ-82^eSIP8e[aFUp>nhcgm:BRj*Q9MGDY(Q+lNB`I!*G5@B@lQSn^i<eQK&^'!N6gEm]_BaDZQ/3uQL@3%"]c2o8+;IScH,6Vo3pC$fR<D>qBC.a#Hj,5<WM.g*)DV[4E[?q&#<Sn[aPU)I!#P+LG.JdlNMMRfH4*^+_1oJi0Y9b/2EZ\E0="":9".#`dbo$htkcnnRm8q5O^8N`A_B=QL"3K-NqUKs1n3k^[$$DVs!Bfl","hX7EjuMf>'jm(9]A_\^o6!T,o^`B,#+<YP<,E'g.Yde-X=Y1Dsm]rpaT(&3e&4eC/$1Ta]e<i_hErhq)?bub!V)UEH?`KX6-?'0F7G-m^RrM<_9ZhVd.[@F2P&_Has03Tf\47`PApV/[bA7gSFg-0Cq7aA[rFffs[N8<im':,![T-c7eKU4J;Glj.l"HOu8+pA$H/gc6=asepeOfB,+a@)jITq'B,>_!M%;79%3p,pOTFifX]RH?i0@^T0-n@=jGaQ/XXH2pR5Ac5@7@!O5Y.V0?]Q))3[Wi1MKM@<+W9)M+5r"e[eXn"p:h7'lp)HVcAPu:Qp:=W$oP3#W`86un2N+Rp&.h*k(16I2mW01bkR?4)-#SRB,k%qYAmaC/[5GE-7oN(,Lj##U"g9&S%&pi%"BMS,cf%=Cc,<60f^RW5;Dae.4-V,6Rd7VDkPIR7/[3E_]`![DZ3G3=^O@.@IICcN25=%O0g.BtgnVF5e5YnmN)lNjp76[UW+n;[$AOPQ$#>5?SgmKt+iB1u*3T9CiV-aq,TlPj_$&_H89*gfJO8T+@N62Rh(s<2^4OXD2G_p)Lk]d<Nk*SOV5tias;+8><MR@54D^A*(MdDN"+#/_l$)_bl%9n9E=J?!N:@BRG&p/bm"3W!gE/r<^qW3[b')*B0?m85aB3KI<#^a/oQAnSAc<CXmcr#<Gm/nA]r_p)='EobJ!i7*2"'Nd#nX%1QZa)_M%a^_hSgNXar_q<:<$f9D4KlP:K,X86$dg+hkCD9>3[Mrt,/hE=e5;JV:"qMq]A'=D"g:IVCE5h8I]nru?Or0)"cheZ^u9Sm#EHP%_m3sC-P^7`%(CF*EGO<>4*jQX_!"<:($"C2_]YHq-C<<f@:n@j/!f,:SBb5qaZYji_m)b:pbBl]M4_[HW=9u!ceX#">Y-tHQ9Ii,N,fGE+-^@hU&M1]X>@bf>bD#0*7"#-:Cq)_/e!6^+^D^Lg*%Z@DJ\!<@>BVWFaa)Ka^@5GS'hXaGZd,Dl[`XAo]:'7K!61Xe8rS5\*9`Ck)uWE1KHP?>tOQF`iE,l]I%)l*aZk*rPQ#eN;sc;rF+$+gV)C$cO^imU(Z@((d7[phH!JMY5O6N*mitT$8*q9R["JTBhKE%ml"EGFG2t,3c6V/R&J\+T`=rlSqgF+iQrM,I?TYo5e_NHL#fu(I6!JR,.?JK_6@3V`D"@kMF@a'lX>[0Y9s,76S,s!Zq^M!3\umq:*qRTL9g/0kDqIQJ`u5<Y;;W;QFB20h.X5^N'sF=1O[O]bpM9G1UZAn`Xm4nQE!+3IC4nK]n(XtT;0Sf:*NQ"*&'8`81@Fe@B/6rTp?tUENlOK:?RH04C6N[4N$)RpL*=V8iW(^k`c1uc]*T?(J/BHmY,SPdFuX&fTA#0e9e&em:HX53YbR1=!cR(B0o9.f'$(pSFZE)d]f^RER5%K-Dcfnq1iRY[cis6gK"XZ2pcA('br'#B'm0VRT=)d+!aF_[Xm=Y0[48kUQkn#02S<i`a?,(dqS4En7A6R>0/42LALIFX*36eY+GNZ:"MF<I`-B$+eMH`4OHPI,Z\ssUZ^=>_#OEM.6Zht]<EmGY`>-46>;ohfPdEI)g4&f[HlUZiXTFX<?VQ7%;a(ec[G?uI&\[email protected]#:1nFA5_ca5mB*=Gp:!pC24T:Gm&GOg@qV;oiXTr6Z)>?irY!E)W-oj&;5*2JJmEODXr=f"^Ds3n<UU$s-0'2.m&0Ed#U^A!i03K]jEp:JNmH!3s6_X%*T.W03AY4?]if%"&CrIPGF0?(5qEoDHF70Y;o5N+Wfq$g.H=oa'1T9Sd(U-V4Nff;ESN9UfP(6Y"`W?gd03D)<Sn<#mkcc.]V^I00r3isP)b"5)qg%VCGV4jf&h/\ir@5c$;I2Ap;7I*<kL'g)Y0@cNA4Rok]aqfkCXR(chBKT=N_cMrQ0/>Aq*%&7bJND\!q7[VJ?"BE9@NXWek3n61;FB])HbY$WAQ.$+ahnGPTn39HN`+^PP)9.P-Pc>9@UkE`=b.MXfkXK5`(F1BgO.Dcf;<Qua;<R06^PH^-7eGNg2VG[TXW9K9j.=^mFR2b_D[-11nFE;j:;O@abrfhY2G]gmmCB>n4kN!8U8tF;hSB1B1c23,]:RYo<lMt_HZtLZ]d;sRY?iD;Bpd-II4Opef!c[i8sa4Y((<Ts<Oja=hDI60d*W)MF,Jr*`6u@t,%_*RXFQ?$A$dh(3;+:>JPheD4RBsVVc0P?mo[aCF.IV0CY?:dBnfpCM3o?,`<k[-8Sb`go3^76T!-T3C=%2SJq$`r1_e57\J/\!k+%fBk1\TRriS>9os9h;-dp<%.K>momU.A@qn!RHCQI(s4RMaf;bpmST@?sJp?t]fh'OLj&?3JaWK-FOh6,5^Z/!c-rh5)<.a>X+h+L1FmscnqLjf~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 11
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000102 00000 n
|
||||
0000000209 00000 n
|
||||
0000000321 00000 n
|
||||
0000000514 00000 n
|
||||
0000000708 00000 n
|
||||
0000000776 00000 n
|
||||
0000001056 00000 n
|
||||
0000001121 00000 n
|
||||
0000004086 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<451d734656bfda21b00c95ac21a36c22><451d734656bfda21b00c95ac21a36c22>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 7 0 R
|
||||
/Root 6 0 R
|
||||
/Size 11
|
||||
>>
|
||||
startxref
|
||||
6878
|
||||
%%EOF
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "Ced's NOC",
|
||||
"message": "Healthy | 8/8 online | 0 offline",
|
||||
"color": "brightgreen"
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
{
|
||||
"nocName": "Ced's NOC",
|
||||
"status": "1 System(s) Degraded",
|
||||
"lastUpdated": "2026-05-04T15:40:01Z",
|
||||
"summary": {
|
||||
"nodes": "12+ Pi",
|
||||
"services": "27/28",
|
||||
"vlans": 4,
|
||||
"edgeSystems": 2
|
||||
},
|
||||
"systems": [
|
||||
{
|
||||
"name": "Proxmox \u2014 BigWorld",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.250",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 Biggie",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.192",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.1ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 Snoop",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.153",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 TooShort",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.120",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.7ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 Tupac",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.74",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.5ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 DrDre",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.227",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Control \u2014 django-1",
|
||||
"type": "K3s Control Plane",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.72",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Control \u2014 django-2",
|
||||
"type": "K3s Control Plane",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.245",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Control \u2014 django-3",
|
||||
"type": "K3s Control Plane",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.128",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Ingress \u2014 node-1",
|
||||
"type": "K3s Worker / Ingress",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.219",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Ingress \u2014 node-2",
|
||||
"type": "K3s Worker / Ingress",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.134",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Ingress \u2014 node-3",
|
||||
"type": "K3s Worker / Ingress",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.222",
|
||||
"status": "Offline",
|
||||
"severity": "Critical",
|
||||
"latency": "N/A",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Data \u2014 node-4",
|
||||
"type": "K3s Worker / Data",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.126",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Data \u2014 node-5",
|
||||
"type": "K3s Worker / Data",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.239",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.4ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Data \u2014 node-6",
|
||||
"type": "K3s Worker / Data",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.208",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Monitor \u2014 node-7",
|
||||
"type": "K3s Worker / Monitoring",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.198",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Monitor \u2014 node-8",
|
||||
"type": "K3s Worker / Monitoring",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.216",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Monitor \u2014 node-9",
|
||||
"type": "K3s Worker / Monitoring",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.29",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.4ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "TrueNAS",
|
||||
"type": "Network Attached Storage",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Storage",
|
||||
"address": "10.10.30.143",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.6ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Nginx Proxy Manager",
|
||||
"type": "Reverse Proxy",
|
||||
"layer": "Networking",
|
||||
"label": "Access",
|
||||
"address": "10.10.30.210",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Prometheus",
|
||||
"type": "Metrics Collection",
|
||||
"layer": "Monitoring",
|
||||
"label": "Observability",
|
||||
"address": "10.10.30.140",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Grafana",
|
||||
"type": "Metrics Dashboard",
|
||||
"layer": "Monitoring",
|
||||
"label": "Observability",
|
||||
"address": "10.10.30.68",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Uptime Kuma",
|
||||
"type": "Service Monitor",
|
||||
"layer": "Monitoring",
|
||||
"label": "Observability",
|
||||
"address": "10.10.30.14",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Dashy",
|
||||
"type": "HomeLab Dashboard",
|
||||
"layer": "Services",
|
||||
"label": "Dashboard",
|
||||
"address": "10.10.30.61",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Home Assistant",
|
||||
"type": "Home Automation",
|
||||
"layer": "Services",
|
||||
"label": "Automation",
|
||||
"address": "10.10.30.104",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.6ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "PrimeStation",
|
||||
"type": "Media / Game Server",
|
||||
"layer": "Services",
|
||||
"label": "Media",
|
||||
"address": "10.10.30.233",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "APRS iGate \u2014 Home",
|
||||
"type": "RF Edge / APRS-IS Gateway",
|
||||
"layer": "Edge",
|
||||
"label": "RF",
|
||||
"address": "10.10.30.129",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "3.7ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
},
|
||||
{
|
||||
"name": "APRS iGate \u2014 Mobile",
|
||||
"type": "RF Edge / Mobile Node",
|
||||
"layer": "Edge",
|
||||
"label": "RF",
|
||||
"address": "10.10.30.35",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "47.2ms",
|
||||
"lastCheck": "2026-05-04 15:40 UTC"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8,22 +8,54 @@
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content="Chase Dumphord portfolio - digital systems, infrastructure, networking, automation, homelab engineering, and real-world technical projects."
|
||||
content="Chase Dumphord — digital systems builder focused on infrastructure, Linux, K3s, Proxmox, APRS RF edge systems, and real-world technical problem solving."
|
||||
/>
|
||||
|
||||
<!-- Open Graph for LinkedIn / Discord sharing -->
|
||||
<meta property="og:title" content="Chase Dumphord | Digital Systems & Infrastructure" />
|
||||
<meta property="og:description" content="Hands-on systems builder. Proxmox • K3s • APRS • HomeLab. Based in Oxford, MS." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://chasedumphord.com" />
|
||||
|
||||
<!-- ── Favicon set (from ced-logo-pack) ── -->
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="assets/favicons/favicon-192x192.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="assets/favicons/favicon-512x512.png" />
|
||||
<link rel="shortcut icon" href="assets/favicons/favicon.ico" />
|
||||
|
||||
<!-- ── Sitemap hint for crawlers ── -->
|
||||
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
|
||||
|
||||
<!-- ── Search engine indexing ── -->
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta name="author" content="Chase Dumphord" />
|
||||
|
||||
<!-- ── Social verification (rel=me) ── -->
|
||||
<link rel="me" href="https://www.linkedin.com/in/chase-dumphord/" />
|
||||
<link rel="me" href="https://github.com/ced4568" />
|
||||
|
||||
<!-- Fonts: JetBrains Mono for terminal/code feel, Syne for headings -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Syne:wght@700;800&family=DM+Sans:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- ═══════════════════════════════ NAV ═══════════════════════════════ -->
|
||||
<header class="site-header">
|
||||
<div class="container nav">
|
||||
<a href="#top" class="logo">Chase Dumphord</a>
|
||||
<a href="#top" class="logo">Ced<span class="logo-cursor">_</span></a>
|
||||
|
||||
<nav>
|
||||
<ul class="nav-links">
|
||||
<li><a href="#snapshot">Snapshot</a></li>
|
||||
<li><a href="#noc">NOC</a></li>
|
||||
<li><a href="#about">About</a></li>
|
||||
<li><a href="#projects">Projects</a></li>
|
||||
<li><a href="#stack">Stack</a></li>
|
||||
<li><a href="#resume">Resume</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
</ul>
|
||||
@@ -32,138 +64,134 @@
|
||||
</header>
|
||||
|
||||
<main id="top">
|
||||
|
||||
<!-- ═══════════════════════════════ HERO ═══════════════════════════════ -->
|
||||
<section class="hero">
|
||||
<div class="container hero-grid">
|
||||
<div class="hero-text">
|
||||
<p class="eyebrow">Digital Systems • Infrastructure • Networking • Automation • Edge Systems</p>
|
||||
|
||||
<h1>I build practical systems that connect hardware, networks, software, and operations.</h1>
|
||||
<div class="hero-text">
|
||||
<p class="eyebrow">
|
||||
<span class="eyebrow-dot"></span>
|
||||
Digital Systems • Infrastructure • Networking • Automation • Edge Systems
|
||||
</p>
|
||||
|
||||
<h1>I build systems that <span class="accent-word">connect</span> hardware, networks, and operations.</h1>
|
||||
|
||||
<p class="lead">
|
||||
I’m Chase Dumphord — a hands-on systems builder focused on digital infrastructure,
|
||||
Linux systems, homelab engineering, Raspberry Pi deployments, networking, automation,
|
||||
and real-world technical problem solving.
|
||||
Chase Dumphord — infrastructure builder running Proxmox, K3s, TrueNAS, and APRS RF edge systems out of Oxford, MS.
|
||||
I build things that actually work, then document how they work.
|
||||
</p>
|
||||
|
||||
<div class="hero-actions">
|
||||
<a class="btn btn-primary" href="#projects">View Projects</a>
|
||||
<a class="btn btn-secondary" href="#contact">Contact Me</a>
|
||||
<a class="btn btn-secondary" href="https://noc.chasedumphord.com" target="_blank" rel="noopener noreferrer">
|
||||
<span class="btn-dot"></span> Live NOC
|
||||
</a>
|
||||
<a class="btn btn-ghost" href="#contact">Contact</a>
|
||||
</div>
|
||||
|
||||
<ul class="quick-facts">
|
||||
<li>Oxford, MS</li>
|
||||
<li>📍 Oxford, MS</li>
|
||||
<li>
|
||||
GitHub:
|
||||
<a href="https://github.com/ced4568" target="_blank" rel="noopener noreferrer">ced4568</a>
|
||||
<a href="https://github.com/ced4568" target="_blank" rel="noopener noreferrer">
|
||||
⌥ github/ced4568
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Email:
|
||||
<a href="mailto:[email protected]">[email protected]</a>
|
||||
<a href="mailto:[email protected]">✉ [email protected]</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- LinkedIn badge — prominent social proof row -->
|
||||
<div class="hero-badges">
|
||||
<a
|
||||
href="https://www.linkedin.com/in/chase-dumphord/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="badge-link linkedin-badge"
|
||||
>
|
||||
<svg class="badge-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
|
||||
</svg>
|
||||
Connect on LinkedIn
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/ced4568"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="badge-link github-badge"
|
||||
>
|
||||
<svg class="badge-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
||||
github/ced4568
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-panel">
|
||||
<img
|
||||
src="assets/images/ChaseD_headshot.jpg"
|
||||
alt="Headshot of Chase Dumphord"
|
||||
class="hero-image"
|
||||
/>
|
||||
<div class="hero-image-card">
|
||||
<img
|
||||
src="assets/images/ChaseD_headshot.jpg"
|
||||
alt="Chase Dumphord"
|
||||
class="hero-image"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="terminal-card">
|
||||
<div class="terminal-top">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span class="dot red"></span>
|
||||
<span class="dot yellow"></span>
|
||||
<span class="dot green"></span>
|
||||
<span class="terminal-title">ced's@homelab ~ $</span>
|
||||
</div>
|
||||
<pre><code><span class="t-prompt">ced's@homelab:~$</span> whoami
|
||||
<span class="t-val">systems_builder</span>
|
||||
|
||||
<pre><code>$ whoami
|
||||
systems_builder
|
||||
<span class="t-prompt">ced's@homelab:~$</span> uptime
|
||||
<span class="t-val">12+ nodes • 10+ services • always_on</span>
|
||||
|
||||
$ focus
|
||||
infrastructure
|
||||
<span class="t-prompt">ced's@homelab:~$</span> cat focus.txt
|
||||
<span class="t-val">infrastructure
|
||||
networking
|
||||
automation
|
||||
edge_systems
|
||||
rf_edge_systems</span>
|
||||
|
||||
$ status
|
||||
building_real_systems</code></pre>
|
||||
<span class="t-prompt">ced's@homelab:~$</span> systemctl status life
|
||||
<span class="t-val">● building_real_systems.service</span>
|
||||
<span class="t-muted"> Active: active (running)</span><span class="t-cursor">▌</span></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ SNAPSHOT ═══════════════════════════════ -->
|
||||
<section id="snapshot" class="section section-alt">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">Environment</p>
|
||||
<p class="section-label">// environment</p>
|
||||
<h2>Systems Snapshot</h2>
|
||||
<p class="section-intro">
|
||||
A quick look at the infrastructure and systems I’m actively building and documenting.
|
||||
Live infrastructure I'm actively running, building, and documenting.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<section class="section noc-dashboard">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">Ced’s NOC</p>
|
||||
<h2>Network Operations Dashboard</h2>
|
||||
<p class="section-intro">
|
||||
A portfolio view of the infrastructure, edge systems, and monitoring stack I’m building across Ced’s HomeLab.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="noc-status-grid">
|
||||
<div class="noc-status-card online">
|
||||
<span class="status-dot"></span>
|
||||
<h3>HomeLab Core</h3>
|
||||
<p>Infrastructure services, VLANs, dashboards, and self-hosted systems.</p>
|
||||
<small>Status: Active Build</small>
|
||||
</div>
|
||||
|
||||
<div class="noc-status-card online">
|
||||
<span class="status-dot"></span>
|
||||
<h3>K3s Cluster</h3>
|
||||
<p>Distributed container environment for service deployment and orchestration.</p>
|
||||
<small>Status: Active Build</small>
|
||||
</div>
|
||||
|
||||
<div class="noc-status-card warning">
|
||||
<span class="status-dot"></span>
|
||||
<h3>APRS iGate</h3>
|
||||
<p>RF-to-IP edge system using Raspberry Pi, Direwolf, APRS-IS, and mobile expansion.</p>
|
||||
<small>Status: Operational / Tuning</small>
|
||||
</div>
|
||||
|
||||
<div class="noc-status-card planned">
|
||||
<span class="status-dot"></span>
|
||||
<h3>Unified Monitoring</h3>
|
||||
<p>Future Grafana/Uptime Kuma view for services, nodes, and edge devices.</p>
|
||||
<small>Status: Planned</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<h3>12+</h3>
|
||||
<p>Nodes</p>
|
||||
<span>K3s cluster environment</span>
|
||||
<span>K3s cluster • Raspberry Pi</span>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h3>10+</h3>
|
||||
<p>Services</p>
|
||||
<span>Self-hosted stack</span>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h3>4</h3>
|
||||
<p>VLANs</p>
|
||||
<span>Segmented network design</span>
|
||||
<span>Segmented UniFi network</span>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h3>2</h3>
|
||||
<p>iGate Nodes</p>
|
||||
@@ -173,37 +201,103 @@ building_real_systems</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ NOC ═══════════════════════════════ -->
|
||||
<section id="noc" class="section noc-dashboard">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">// ced's noc</p>
|
||||
<h2>Live Systems Overview</h2>
|
||||
<p class="section-intro">
|
||||
Real infrastructure inventory from Ced's HomeLab, K3s cluster, and APRS edge systems.
|
||||
Data refreshes every 30s.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="noc-command-bar">
|
||||
<span class="status-dot" id="noc-dot"></span>
|
||||
<span id="noc-status-text">Connecting to NOC feed...</span>
|
||||
<span class="noc-refresh-badge" id="noc-refresh-badge"></span>
|
||||
</div>
|
||||
|
||||
<p class="noc-proof">
|
||||
Proxmox • K3s • TrueNAS • VLAN segmentation • APRS RF Edge Systems
|
||||
</p>
|
||||
|
||||
<div class="noc-metrics-grid">
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-nodes">--</h3>
|
||||
<p>Infrastructure Nodes</p>
|
||||
</div>
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-services">--</h3>
|
||||
<p>Services Online</p>
|
||||
</div>
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-vlans">--</h3>
|
||||
<p>Network Segments</p>
|
||||
</div>
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-edge">--</h3>
|
||||
<p>Edge Systems</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noc-alert-panel">
|
||||
<div class="noc-alert-header">
|
||||
<h3>🚨 Alert Panel</h3>
|
||||
<span>Top 3 System Notes</span>
|
||||
</div>
|
||||
<div id="noc-alert-list" class="noc-alert-list">
|
||||
<p class="noc-loading">Awaiting data feed...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="noc-system-grid" class="noc-system-grid"></div>
|
||||
|
||||
<!-- Fallback shown when data can't load -->
|
||||
<div id="noc-fallback" class="noc-fallback" style="display:none;">
|
||||
<p class="noc-fallback-msg">
|
||||
📡 NOC feed unavailable from this context — systems run locally.<br/>
|
||||
<a href="https://noc.chasedumphord.com" target="_blank" rel="noopener noreferrer">
|
||||
View the live NOC dashboard →
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ ABOUT ═══════════════════════════════ -->
|
||||
<section id="about" class="section">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">About</p>
|
||||
<p class="section-label">// about</p>
|
||||
<h2>Hands-on systems builder with a digital infrastructure mindset</h2>
|
||||
</div>
|
||||
|
||||
<div class="content-grid">
|
||||
<div class="card">
|
||||
<p>
|
||||
I’m a technical professional focused on digital systems, infrastructure, networking,
|
||||
automation, and hands-on system integration. I enjoy building systems that are practical,
|
||||
reliable, and well documented — from homelab services and dashboards to Raspberry Pi
|
||||
deployments, APRS iGates, and troubleshooting workflows.
|
||||
I'm a technical professional focused on digital systems, infrastructure, networking,
|
||||
automation, and hands-on system integration. I build things that are practical,
|
||||
reliable, and well-documented — from homelab services and live dashboards to Raspberry Pi
|
||||
deployments, APRS iGates, and complex troubleshooting workflows.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
My background blends field engineering, industrial technology, software-oriented thinking,
|
||||
and infrastructure problem solving. I’m especially interested in projects that connect the
|
||||
physical and digital worlds through monitoring, networking, automation, and resilient design.
|
||||
My background blends field engineering, industrial technology, and infrastructure
|
||||
problem solving. Increasingly I'm integrating AI tooling — using LLMs for system
|
||||
documentation, automated diagnostics, and workflow acceleration — as part of how
|
||||
modern infrastructure gets built and maintained.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Core Focus Areas</h3>
|
||||
|
||||
<ul class="clean-list">
|
||||
<li>Digital systems and infrastructure</li>
|
||||
<li>Digital systems and infrastructure engineering</li>
|
||||
<li>Linux systems and service management</li>
|
||||
<li>Networking, VLANs, failover, and connectivity troubleshooting</li>
|
||||
<li>Raspberry Pi and edge-device deployments</li>
|
||||
<li>AI-assisted automation, documentation, and diagnostic workflows</li>
|
||||
<li>Documentation, process building, and reproducible project design</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -211,240 +305,384 @@ building_real_systems</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ PROJECTS ═══════════════════════════════ -->
|
||||
<section id="projects" class="section section-alt">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">Projects</p>
|
||||
<h2>🔧 Infrastructure & Systems Projects</h2>
|
||||
<p class="section-intro">
|
||||
These projects are built around real systems, networking, Linux services, edge devices,
|
||||
and practical documentation.
|
||||
</p>
|
||||
<p class="section-label">// projects</p>
|
||||
<h2>Infrastructure & Systems Projects</h2>
|
||||
<p class="section-intro">Built on real systems. Not demos, not tutorials — running infrastructure.</p>
|
||||
</div>
|
||||
|
||||
<div class="projects-grid">
|
||||
|
||||
<article class="project-card featured-project">
|
||||
<div class="project-top">
|
||||
<h3>🧠 Ced’s HomeLab Infrastructure</h3>
|
||||
<h3>Ced's HomeLab Infrastructure</h3>
|
||||
<span class="status-pill">Flagship</span>
|
||||
</div>
|
||||
|
||||
<p class="tags">Infrastructure • Networking • Virtualization • Monitoring • Self-Hosting</p>
|
||||
|
||||
<p class="project-impact">
|
||||
Designed as a practical infrastructure environment for networking, monitoring,
|
||||
service hosting, and documentation.
|
||||
Full homelab environment built for real network segmentation, service hosting, and architecture documentation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Personal infrastructure lab focused on network segmentation, virtualization,
|
||||
self-hosted services, monitoring, and architecture documentation.
|
||||
</p>
|
||||
|
||||
<ul class="clean-list">
|
||||
<li>VLAN segmentation and network design</li>
|
||||
<li>Proxmox virtualization</li>
|
||||
<li>Self-hosted services and monitoring</li>
|
||||
<li>System architecture documentation</li>
|
||||
<li>Proxmox VE virtualization platform</li>
|
||||
<li>VLAN segmentation via UniFi (Main / IoT / HomeLab / Guest)</li>
|
||||
<li>Self-hosted services behind Nginx Proxy Manager + Cloudflare Tunnels</li>
|
||||
<li>Uptime Kuma + Grafana monitoring stack</li>
|
||||
</ul>
|
||||
|
||||
<a href="https://github.com/ced4568/ceds-homelab" target="_blank" rel="noopener noreferrer" class="project-link">
|
||||
View Project →
|
||||
View on GitHub →
|
||||
</a>
|
||||
</article>
|
||||
|
||||
<article class="project-card">
|
||||
<div class="project-top">
|
||||
<h3>☸️ K3s Kubernetes Cluster</h3>
|
||||
<h3>K3s Kubernetes Cluster</h3>
|
||||
<span class="status-pill">Infrastructure</span>
|
||||
</div>
|
||||
|
||||
<p class="tags">Kubernetes • Containers • Linux • Infrastructure • Automation</p>
|
||||
|
||||
<p class="tags">Kubernetes • Containers • Linux • Automation</p>
|
||||
<p class="project-impact">
|
||||
Built to simulate distributed infrastructure, container orchestration, and scalable service deployment.
|
||||
12-node K3s cluster on Raspberry Pi built to simulate distributed infrastructure and container orchestration at scale.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Multi-node K3s cluster built for container orchestration, service deployment,
|
||||
and infrastructure experimentation.
|
||||
</p>
|
||||
|
||||
<ul class="clean-list">
|
||||
<li>Multi-node cluster setup</li>
|
||||
<li>Containerized workloads</li>
|
||||
<li>Service deployment</li>
|
||||
<li>Infrastructure automation</li>
|
||||
<li>Multi-node cluster setup and management</li>
|
||||
<li>Containerized workload deployment</li>
|
||||
<li>Infrastructure automation via manifest-driven configuration</li>
|
||||
</ul>
|
||||
|
||||
<a href="https://github.com/ced4568/ced-k3s-homelab" target="_blank" rel="noopener noreferrer" class="project-link">
|
||||
View Project →
|
||||
View on GitHub →
|
||||
</a>
|
||||
</article>
|
||||
|
||||
<article class="project-card">
|
||||
<div class="project-top">
|
||||
<h3>📡 APRS iGate System</h3>
|
||||
<h3>APRS iGate System</h3>
|
||||
<span class="status-pill">Edge System</span>
|
||||
</div>
|
||||
|
||||
<p class="tags">RF • Linux • Raspberry Pi • Networking • APRS-IS • Edge Systems</p>
|
||||
|
||||
<p class="tags">RF • Linux • Raspberry Pi • APRS-IS • Edge Systems</p>
|
||||
<p class="project-impact">
|
||||
Bridges RF communication into IP-based infrastructure using Linux, Direwolf, and APRS-IS.
|
||||
Operational dual-node RF-to-internet gateway. Decodes real beacon packets and uplinks live to aprs.fi.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Operational dual-node APRS iGate system built with Raspberry Pi, Direwolf, APRS-IS,
|
||||
RF radios, HomeLab network integration, and planned mobile GPS support.
|
||||
</p>
|
||||
|
||||
<ul class="clean-list">
|
||||
<li>RF packet decoding with Direwolf</li>
|
||||
<li>Direwolf APRS TNC with tuned audio chain (target: 50–60 level)</li>
|
||||
<li>APRS-IS uplink verified on aprs.fi</li>
|
||||
<li>HomeLab WiFi + mobile hotspot failover</li>
|
||||
<li>Mobile build includes ETH-USB-HUB-BOX expansion</li>
|
||||
<li>Documented configs, architecture, and troubleshooting</li>
|
||||
<li>Mobile build with ETH-USB-HUB-BOX expansion</li>
|
||||
</ul>
|
||||
|
||||
<a href="https://github.com/ced4568/ceds-aprs-igate" target="_blank" rel="noopener noreferrer" class="project-link">
|
||||
View Project →
|
||||
View on GitHub →
|
||||
</a>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ NOC ROADMAP ═══════════════════════════════ -->
|
||||
<section class="section noc-section">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">Future Buildout</p>
|
||||
<h2>📊 Ced’s NOC Vision</h2>
|
||||
<p class="section-label">// noc roadmap</p>
|
||||
<h2>Ced's NOC Vision</h2>
|
||||
<p class="section-intro">
|
||||
The long-term goal is to bring these systems together into a unified network operations view.
|
||||
Staged monitoring and systems-visibility platform built on real infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="noc-grid">
|
||||
<div class="noc-card">
|
||||
<h3>Monitoring</h3>
|
||||
<p>Grafana, Prometheus, Uptime Kuma, and service-level visibility.</p>
|
||||
<div class="noc-card-badge done">✅ Live</div>
|
||||
<h3>Portfolio NOC</h3>
|
||||
<p>
|
||||
JSON-driven dashboard showing real inventory, online/offline checks, service labels,
|
||||
latency, and last-check timestamps.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="noc-card">
|
||||
<h3>Infrastructure</h3>
|
||||
<p>HomeLab services, K3s nodes, VLANs, and self-hosted systems.</p>
|
||||
<div class="noc-card-badge next">⚙️ Next</div>
|
||||
<h3>Automated Data Updates</h3>
|
||||
<p>
|
||||
Scheduled local scripts will auto-refresh system status and push dashboard-ready
|
||||
JSON on a cron interval — no manual updates.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="noc-card">
|
||||
<h3>Edge Systems</h3>
|
||||
<p>APRS iGate nodes, Raspberry Pi devices, and field/mobile deployments.</p>
|
||||
<div class="noc-card-badge future">📈 Future</div>
|
||||
<h3>Grafana + Prometheus</h3>
|
||||
<p>
|
||||
Full observability stack for Proxmox, TrueNAS, K3s, Raspberry Pi nodes, Uptime Kuma,
|
||||
and APRS edge systems with real-time metrics ingestion.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CTA to live NOC -->
|
||||
<div class="noc-roadmap-cta">
|
||||
<a
|
||||
href="https://noc.chasedumphord.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-secondary"
|
||||
>
|
||||
<span class="btn-dot"></span> View Live NOC Dashboard
|
||||
</a>
|
||||
<span class="noc-cta-sub">noc.chasedumphord.com — live infrastructure visibility</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ TECH STACK ═══════════════════════════════ -->
|
||||
<section id="stack" class="section section-alt">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">// tech stack</p>
|
||||
<h2>Tools & Technologies</h2>
|
||||
</div>
|
||||
|
||||
<div class="stack-groups">
|
||||
|
||||
<div class="stack-group">
|
||||
<h4 class="stack-group-label">Infrastructure</h4>
|
||||
<div class="stack-pills">
|
||||
<span class="stack-pill">Proxmox VE</span>
|
||||
<span class="stack-pill">K3s</span>
|
||||
<span class="stack-pill">Docker</span>
|
||||
<span class="stack-pill">TrueNAS</span>
|
||||
<span class="stack-pill">Nginx Proxy Manager</span>
|
||||
<span class="stack-pill">Cloudflare Tunnels</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stack-group">
|
||||
<h4 class="stack-group-label">Monitoring & Observability</h4>
|
||||
<div class="stack-pills">
|
||||
<span class="stack-pill">Grafana</span>
|
||||
<span class="stack-pill">Prometheus</span>
|
||||
<span class="stack-pill">Uptime Kuma</span>
|
||||
<span class="stack-pill">Custom NOC Dashboard</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stack-group">
|
||||
<h4 class="stack-group-label">Networking</h4>
|
||||
<div class="stack-pills">
|
||||
<span class="stack-pill">UniFi</span>
|
||||
<span class="stack-pill">VLAN Segmentation</span>
|
||||
<span class="stack-pill">pfSense</span>
|
||||
<span class="stack-pill">Cloudflare DNS</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stack-group">
|
||||
<h4 class="stack-group-label">RF & Edge</h4>
|
||||
<div class="stack-pills">
|
||||
<span class="stack-pill">Direwolf</span>
|
||||
<span class="stack-pill">APRS-IS</span>
|
||||
<span class="stack-pill">Raspberry Pi</span>
|
||||
<span class="stack-pill">RTL-SDR</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stack-group">
|
||||
<h4 class="stack-group-label">Development</h4>
|
||||
<div class="stack-pills">
|
||||
<span class="stack-pill">Python</span>
|
||||
<span class="stack-pill">Bash</span>
|
||||
<span class="stack-pill">JavaScript</span>
|
||||
<span class="stack-pill">HTML / CSS</span>
|
||||
<span class="stack-pill">Git</span>
|
||||
<span class="stack-pill">Linux</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stack-group">
|
||||
<h4 class="stack-group-label">AI & Automation</h4>
|
||||
<div class="stack-pills">
|
||||
<span class="stack-pill">Claude (Anthropic)</span>
|
||||
<span class="stack-pill">ChatGPT</span>
|
||||
<span class="stack-pill">LLM-assisted Documentation</span>
|
||||
<span class="stack-pill">AI-driven Diagnostics</span>
|
||||
<span class="stack-pill">Prompt Engineering</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ RESUME ═══════════════════════════════ -->
|
||||
<section id="resume" class="section">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">Resume Snapshot</p>
|
||||
<p class="section-label">// resume snapshot</p>
|
||||
<h2>Technical experience that bridges field work and digital systems</h2>
|
||||
</div>
|
||||
|
||||
<div class="content-grid">
|
||||
<div class="card">
|
||||
<h3>What I Bring</h3>
|
||||
<div class="resume-grid">
|
||||
|
||||
<div class="card resume-card">
|
||||
<h3>What I Bring</h3>
|
||||
<ul class="clean-list">
|
||||
<li>Industrial and field-service technical experience</li>
|
||||
<li>Linux, Raspberry Pi, and systems administration work</li>
|
||||
<li>Networking, connectivity, and troubleshooting depth</li>
|
||||
<li>Documentation, process building, and reproducible project design</li>
|
||||
<li>Industrial and field-service technical background — hands-on problem solving under real constraints</li>
|
||||
<li>Linux systems administration — service management, troubleshooting, automation</li>
|
||||
<li>Networking depth — VLANs, DNS, reverse proxy, firewall config, failover design</li>
|
||||
<li>Infrastructure-as-documentation mindset — everything I build gets written up</li>
|
||||
<li>Homelab → production thinking — I build lab environments that mirror real-world system design</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Current Direction</h3>
|
||||
<div class="card resume-card">
|
||||
<h3>Target Roles</h3>
|
||||
<ul class="clean-list">
|
||||
<li>Systems / Infrastructure Engineer</li>
|
||||
<li>NOC Technician / Network Operations</li>
|
||||
<li>Linux Systems Administrator</li>
|
||||
<li>Technical Operations / IT Infrastructure</li>
|
||||
<li>Edge Systems / Field Technical Roles</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
I’m positioning myself around digital systems, infrastructure, networking,
|
||||
automation, and technical operations — especially roles where hands-on problem
|
||||
solving and system integration matter.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
More detailed resume content will be added here as the portfolio grows.
|
||||
</p>
|
||||
<div class="resume-note">
|
||||
<p>
|
||||
Currently positioning around digital systems, infrastructure, and technical operations —
|
||||
especially roles where hands-on problem solving and system integration matter more than certifications.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card resume-card resume-card-full">
|
||||
<h3>Currently Learning / Building Toward</h3>
|
||||
<div class="learning-grid">
|
||||
<div class="learning-item">
|
||||
<span class="learning-icon">📈</span>
|
||||
<span>Grafana + Prometheus full observability stack</span>
|
||||
</div>
|
||||
<div class="learning-item">
|
||||
<span class="learning-icon">☸️</span>
|
||||
<span>Kubernetes production patterns (GitOps, Helm, ArgoCD)</span>
|
||||
</div>
|
||||
<div class="learning-item">
|
||||
<span class="learning-icon">🔐</span>
|
||||
<span>Network security and zero-trust architecture</span>
|
||||
</div>
|
||||
<div class="learning-item">
|
||||
<span class="learning-icon">📡</span>
|
||||
<span>Mobile APRS iGate deployment</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resume download CTA -->
|
||||
<div class="resume-download-row">
|
||||
<a
|
||||
href="assets/ChaseD_Resume.pdf"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-primary"
|
||||
download
|
||||
>
|
||||
↓ Download Resume (PDF)
|
||||
</a>
|
||||
<span class="resume-download-note">Updated 2025 • PDF format</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ GITHUB REPOS ═══════════════════════════════ -->
|
||||
<section id="repos" class="section section-alt">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">// github</p>
|
||||
<h2>Pinned Repositories</h2>
|
||||
<p class="section-intro">
|
||||
Active projects on GitHub — source code, configs, and documentation for everything I'm building.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="github-repos" class="repos-grid">
|
||||
<!-- Populated by script.js via GitHub API -->
|
||||
<div class="repo-loading">
|
||||
<span class="noc-loading">Fetching repositories...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="repos-footer">
|
||||
<a
|
||||
href="https://github.com/ced4568"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-ghost"
|
||||
>
|
||||
View all repositories on GitHub →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ PERSONAL ═══════════════════════════════ -->
|
||||
<section class="section section-alt personal-section">
|
||||
<div class="container personal-grid">
|
||||
<div class="personal-image-wrap">
|
||||
<img
|
||||
src="assets/images/lakephotopinkpants.png"
|
||||
alt="Chase Dumphord standing by a fence with a lake view in the background"
|
||||
alt="Chase Dumphord"
|
||||
class="personal-image"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<p class="section-label">Personal Note</p>
|
||||
<p class="section-label">// personal</p>
|
||||
<h2>Technical, curious, and always building</h2>
|
||||
|
||||
<p>
|
||||
Outside of work, I enjoy electronics, self-hosting, coding, drones, radio, and
|
||||
hands-on technical projects that push me to learn something useful. That curiosity
|
||||
carries directly into the way I build and document systems.
|
||||
Outside of work I'm into electronics, self-hosting, coding, drones, ham radio, and
|
||||
hands-on projects that force me to learn something real. Ball pythons and dogs round
|
||||
out the home lab. That curiosity carries directly into how I build and document systems.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════ CONTACT ═══════════════════════════════ -->
|
||||
<section id="contact" class="section">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<p class="section-label">Contact</p>
|
||||
<h2>Let’s connect</h2>
|
||||
<p class="section-label">// contact</p>
|
||||
<h2>Let's connect</h2>
|
||||
</div>
|
||||
|
||||
<div class="contact-grid">
|
||||
<div class="card">
|
||||
<h3>Contact Info</h3>
|
||||
|
||||
<h3>Reach Out</h3>
|
||||
<p>Email: <a href="mailto:[email protected]">[email protected]</a></p>
|
||||
<p>Phone: <a href="tel:+16622142231">662-214-2231</a></p>
|
||||
<p>Location: Oxford, MS</p>
|
||||
<p>
|
||||
GitHub:
|
||||
<a href="https://github.com/ced4568" target="_blank" rel="noopener noreferrer">github.com/ced4568</a>
|
||||
</p>
|
||||
<p>GitHub: <a href="https://github.com/ced4568" target="_blank" rel="noopener noreferrer">github.com/ced4568</a></p>
|
||||
<p>LinkedIn: <a href="https://www.linkedin.com/in/chase-dumphord/" target="_blank" rel="noopener noreferrer">linkedin.com/in/chase-dumphord</a></p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>What I’m Open To</h3>
|
||||
|
||||
<h3>Open To</h3>
|
||||
<ul class="clean-list">
|
||||
<li>Digital systems and infrastructure roles</li>
|
||||
<li>Networking and technical operations work</li>
|
||||
<li>Networking and technical operations</li>
|
||||
<li>Automation and monitoring projects</li>
|
||||
<li>Projects involving hardware + software integration</li>
|
||||
<li>Hardware + software integration work</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<!-- ═══════════════════════════════ FOOTER ═══════════════════════════════ -->
|
||||
<footer class="site-footer">
|
||||
<div class="container footer-content">
|
||||
<p>© Chase Dumphord</p>
|
||||
<a href="#top" class="back-to-top">Back to top ↑</a>
|
||||
<p>© <span data-year></span> Chase Dumphord — <span class="footer-mono">systems_builder</span></p>
|
||||
<a href="#top" class="back-to-top">↑ back to top</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,445 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<title>Ced's NOC | Live Systems Dashboard</title>
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content="Ced's NOC — live network operations center dashboard showing real-time infrastructure health, service status, and edge system monitoring."
|
||||
/>
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="Ced's NOC | Live Systems Dashboard" />
|
||||
<meta property="og:description" content="Live infrastructure visibility — Proxmox, K3s, TrueNAS, APRS edge systems." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://noc.chasedumphord.com" />
|
||||
|
||||
<!-- Favicons (path up one level since we're in /noc/) -->
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="../assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="../assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="../assets/favicons/favicon-192x192.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="../assets/favicons/favicon-512x512.png" />
|
||||
<link rel="shortcut icon" href="../assets/favicons/favicon.ico" />
|
||||
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta name="author" content="Chase Dumphord" />
|
||||
|
||||
<!-- Fonts — same as main site -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Syne:wght@700;800&family=DM+Sans:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Shared stylesheet (up one level) -->
|
||||
<link rel="stylesheet" href="../style.css" />
|
||||
|
||||
<!-- NOC-specific styles -->
|
||||
<style>
|
||||
/* ── NOC page overrides & extras ── */
|
||||
.noc-page-hero {
|
||||
padding: 3.5rem 0 2rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.noc-page-hero .eyebrow {
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.noc-page-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(2rem, 4vw, 3.2rem);
|
||||
font-weight: 800;
|
||||
margin: 0 0 0.75rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.noc-page-title span {
|
||||
color: var(--accent-2);
|
||||
}
|
||||
|
||||
.noc-page-lead {
|
||||
color: var(--muted);
|
||||
font-size: 1rem;
|
||||
max-width: 60ch;
|
||||
margin: 0 0 1.5rem;
|
||||
}
|
||||
|
||||
.noc-page-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.6rem 1.4rem;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.78rem;
|
||||
color: var(--muted);
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.noc-page-meta a { color: var(--muted); }
|
||||
.noc-page-meta a:hover { color: var(--accent-2); }
|
||||
|
||||
/* Full-width NOC content area */
|
||||
.noc-full {
|
||||
padding: 2.5rem 0 4rem;
|
||||
}
|
||||
|
||||
/* Uptime summary bar */
|
||||
.uptime-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.uptime-pill {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.76rem;
|
||||
padding: 0.35rem 0.75rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
color: var(--muted);
|
||||
background: rgba(255,255,255,0.03);
|
||||
}
|
||||
|
||||
.uptime-pill.online {
|
||||
color: var(--accent-2);
|
||||
border-color: rgba(94, 250, 204, 0.3);
|
||||
background: rgba(94, 250, 204, 0.06);
|
||||
}
|
||||
|
||||
.uptime-pill.warning {
|
||||
color: var(--warning);
|
||||
border-color: rgba(242, 204, 96, 0.3);
|
||||
background: rgba(242, 204, 96, 0.06);
|
||||
}
|
||||
|
||||
.uptime-pill.offline {
|
||||
color: var(--danger);
|
||||
border-color: rgba(255, 95, 86, 0.3);
|
||||
background: rgba(255, 95, 86, 0.06);
|
||||
}
|
||||
|
||||
/* Layer filter tabs */
|
||||
.layer-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.layer-tab {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.76rem;
|
||||
font-weight: 700;
|
||||
padding: 0.35rem 0.85rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
color: var(--muted);
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.layer-tab:hover,
|
||||
.layer-tab.active {
|
||||
color: var(--accent-2);
|
||||
border-color: rgba(94, 250, 204, 0.35);
|
||||
background: rgba(94, 250, 204, 0.07);
|
||||
}
|
||||
|
||||
/* Roadmap section on NOC page */
|
||||
.noc-roadmap {
|
||||
margin-top: 3rem;
|
||||
padding-top: 2.5rem;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
/* Stack info footer on NOC page */
|
||||
.noc-stack-bar {
|
||||
margin-top: 2.5rem;
|
||||
padding: 1rem 1.25rem;
|
||||
border-radius: var(--radius);
|
||||
background: rgba(0,0,0,0.2);
|
||||
border: 1px solid var(--line);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.78rem;
|
||||
color: var(--muted);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem 1.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.noc-stack-bar strong {
|
||||
color: var(--accent-2);
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.layer-tabs { gap: 0.4rem; }
|
||||
.layer-tab { font-size: 0.7rem; padding: 0.3rem 0.65rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- ═══════════════════════════════ NAV ═══════════════════════════════ -->
|
||||
<header class="site-header">
|
||||
<div class="container nav">
|
||||
<a href="https://chasedumphord.com" class="logo">Ced<span class="logo-cursor">_</span></a>
|
||||
|
||||
<nav>
|
||||
<ul class="nav-links">
|
||||
<li><a href="https://chasedumphord.com/#snapshot">Snapshot</a></li>
|
||||
<li><a href="https://chasedumphord.com/#about">About</a></li>
|
||||
<li><a href="https://chasedumphord.com/#projects">Projects</a></li>
|
||||
<li><a href="https://chasedumphord.com/#stack">Stack</a></li>
|
||||
<li><a href="https://chasedumphord.com/#contact">Contact</a></li>
|
||||
<li><a href="https://chasedumphord.com/assets/images/ChaseD_Resume.pdf" target="_blank" rel="noopener noreferrer">Resume</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="top">
|
||||
|
||||
<!-- ═══════════════════════════════ NOC HERO ═══════════════════════════════ -->
|
||||
<div class="noc-page-hero">
|
||||
<div class="container">
|
||||
<p class="eyebrow">
|
||||
<span class="eyebrow-dot"></span>
|
||||
Ced's NOC • Live Infrastructure Dashboard • Auto-refresh: 30s
|
||||
</p>
|
||||
|
||||
<h1 class="noc-page-title">
|
||||
Live Systems <span>Dashboard</span>
|
||||
</h1>
|
||||
|
||||
<p class="noc-page-lead">
|
||||
Real-time visibility into Ced's HomeLab infrastructure — Proxmox, K3s,
|
||||
TrueNAS, APRS RF edge systems, and self-hosted services.
|
||||
Not simulated. Not a demo. Running hardware.
|
||||
</p>
|
||||
|
||||
<ul class="noc-page-meta">
|
||||
<li>📍 Oxford, MS</li>
|
||||
<li><a href="https://chasedumphord.com">← Portfolio</a></li>
|
||||
<li><a href="https://github.com/ced4568" target="_blank" rel="noopener noreferrer">github/ced4568</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════════════════════ NOC DASHBOARD ═══════════════════════════════ -->
|
||||
<div class="noc-full">
|
||||
<div class="container">
|
||||
|
||||
<!-- Status command bar -->
|
||||
<div class="noc-command-bar">
|
||||
<span class="status-dot" id="noc-dot"></span>
|
||||
<span id="noc-status-text">Connecting to NOC feed...</span>
|
||||
<span class="noc-refresh-badge" id="noc-refresh-badge"></span>
|
||||
</div>
|
||||
|
||||
<p class="noc-proof">
|
||||
Proxmox • K3s • TrueNAS • VLAN Segmentation • APRS RF Edge Systems
|
||||
</p>
|
||||
|
||||
<!-- Uptime summary pills (populated by JS) -->
|
||||
<div class="uptime-bar" id="uptime-bar"></div>
|
||||
|
||||
<!-- Metrics -->
|
||||
<div class="noc-metrics-grid">
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-nodes">--</h3>
|
||||
<p>Infrastructure Nodes</p>
|
||||
</div>
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-services">--</h3>
|
||||
<p>Services Online</p>
|
||||
</div>
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-vlans">--</h3>
|
||||
<p>Network Segments</p>
|
||||
</div>
|
||||
<div class="noc-metric">
|
||||
<h3 id="metric-edge">--</h3>
|
||||
<p>Edge Systems</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alert panel -->
|
||||
<div class="noc-alert-panel">
|
||||
<div class="noc-alert-header">
|
||||
<h3>🚨 Alert Panel</h3>
|
||||
<span>Top 3 Priority Systems</span>
|
||||
</div>
|
||||
<div id="noc-alert-list" class="noc-alert-list">
|
||||
<p class="noc-loading">Awaiting data feed...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Layer filter tabs -->
|
||||
<div class="layer-tabs" id="layer-tabs">
|
||||
<button class="layer-tab active" data-layer="all">All Systems</button>
|
||||
</div>
|
||||
|
||||
<!-- System cards grid -->
|
||||
<div id="noc-system-grid" class="noc-system-grid"></div>
|
||||
|
||||
<!-- Fallback -->
|
||||
<div id="noc-fallback" class="noc-fallback" style="display:none;">
|
||||
<p class="noc-fallback-msg">
|
||||
📡 NOC feed unavailable from this context — systems run locally.<br/>
|
||||
Data updates when the local pipeline pushes a fresh noc-status.json.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Stack info bar -->
|
||||
<div class="noc-stack-bar">
|
||||
<span><strong>Stack:</strong> Python health checks → JSON → JS dashboard</span>
|
||||
<span><strong>Next:</strong> Grafana + Prometheus integration</span>
|
||||
<span><strong>Source:</strong>
|
||||
<a href="https://github.com/ced4568/ceds-homelab" target="_blank" rel="noopener noreferrer">
|
||||
github/ceds-homelab
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- NOC Roadmap -->
|
||||
<div class="noc-roadmap">
|
||||
<p class="section-label">// noc roadmap</p>
|
||||
<h2 class="section-h2" style="font-family:var(--font-display);font-size:1.6rem;margin:0 0 1.25rem;">Build Stages</h2>
|
||||
|
||||
<div class="noc-grid">
|
||||
<div class="noc-card">
|
||||
<div class="noc-card-badge done">✅ Live</div>
|
||||
<h3>Portfolio NOC</h3>
|
||||
<p>
|
||||
JSON-driven dashboard showing real inventory, online/offline checks,
|
||||
service labels, latency, and last-check timestamps.
|
||||
</p>
|
||||
</div>
|
||||
<div class="noc-card">
|
||||
<div class="noc-card-badge next">⚙️ Next</div>
|
||||
<h3>Automated Data Updates</h3>
|
||||
<p>
|
||||
Scheduled scripts auto-refresh system status and push dashboard-ready
|
||||
JSON on a cron interval — no manual updates.
|
||||
</p>
|
||||
</div>
|
||||
<div class="noc-card">
|
||||
<div class="noc-card-badge future">📈 Future</div>
|
||||
<h3>Grafana + Prometheus</h3>
|
||||
<p>
|
||||
Full observability stack for Proxmox, TrueNAS, K3s, Raspberry Pi,
|
||||
Uptime Kuma, and APRS edge systems with real-time metrics.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<!-- ═══════════════════════════════ FOOTER ═══════════════════════════════ -->
|
||||
<footer class="site-footer">
|
||||
<div class="container footer-content">
|
||||
<p>© <span data-year></span> Chase Dumphord — <span class="footer-mono">noc.chasedumphord.com</span></p>
|
||||
<a href="#top" class="back-to-top">↑ back to top</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Shared script (up one level) -->
|
||||
<script src="../script.js"></script>
|
||||
|
||||
<!-- NOC page extras — layer filter tabs + uptime pills -->
|
||||
<script>
|
||||
// ── Layer filter tabs ──────────────────────────────────────────
|
||||
// Populated after NOC data loads. Filters the system grid by layer.
|
||||
let allSystems = [];
|
||||
|
||||
const originalLoad = window.loadNocStatus;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// Hook into data after the shared script loads it
|
||||
const observer = new MutationObserver(() => {
|
||||
const cards = document.querySelectorAll(".noc-system-card");
|
||||
if (cards.length > 0) {
|
||||
buildLayerTabs();
|
||||
buildUptimePills();
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
const grid = document.getElementById("noc-system-grid");
|
||||
if (grid) observer.observe(grid, { childList: true });
|
||||
});
|
||||
|
||||
function buildLayerTabs() {
|
||||
const cards = document.querySelectorAll(".noc-system-card");
|
||||
const layers = new Set(["all"]);
|
||||
|
||||
cards.forEach(card => {
|
||||
const layerEl = card.querySelector(".noc-system-top span:last-child");
|
||||
if (layerEl) layers.add(layerEl.textContent.trim());
|
||||
});
|
||||
|
||||
const tabContainer = document.getElementById("layer-tabs");
|
||||
tabContainer.innerHTML = "";
|
||||
|
||||
layers.forEach(layer => {
|
||||
const btn = document.createElement("button");
|
||||
btn.className = "layer-tab" + (layer === "all" ? " active" : "");
|
||||
btn.dataset.layer = layer;
|
||||
btn.textContent = layer === "all" ? "All Systems" : layer;
|
||||
btn.addEventListener("click", () => filterByLayer(layer, btn));
|
||||
tabContainer.appendChild(btn);
|
||||
});
|
||||
}
|
||||
|
||||
function filterByLayer(layer, activeBtn) {
|
||||
document.querySelectorAll(".layer-tab").forEach(t => t.classList.remove("active"));
|
||||
activeBtn.classList.add("active");
|
||||
|
||||
document.querySelectorAll(".noc-system-card").forEach(card => {
|
||||
if (layer === "all") {
|
||||
card.style.display = "";
|
||||
return;
|
||||
}
|
||||
const layerEl = card.querySelector(".noc-system-top span:last-child");
|
||||
card.style.display =
|
||||
layerEl && layerEl.textContent.trim() === layer ? "" : "none";
|
||||
});
|
||||
}
|
||||
|
||||
function buildUptimePills() {
|
||||
const bar = document.getElementById("uptime-bar");
|
||||
if (!bar) return;
|
||||
|
||||
const cards = document.querySelectorAll(".noc-system-card");
|
||||
let online = 0, warning = 0, offline = 0;
|
||||
|
||||
cards.forEach(card => {
|
||||
const dot = card.querySelector(".mini-status");
|
||||
if (!dot) return;
|
||||
if (dot.classList.contains("online")) online++;
|
||||
else if (dot.classList.contains("warning")) warning++;
|
||||
else if (dot.classList.contains("offline")) offline++;
|
||||
});
|
||||
|
||||
bar.innerHTML = `
|
||||
<span class="uptime-pill online">● ${online} Online</span>
|
||||
${warning > 0 ? `<span class="uptime-pill warning">● ${warning} Degraded</span>` : ""}
|
||||
${offline > 0 ? `<span class="uptime-pill offline">● ${offline} Offline</span>` : ""}
|
||||
<span class="uptime-pill">${online + warning + offline} Total Systems</span>
|
||||
`;
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 301 KiB |
|
After Width: | Height: | Size: 180 KiB |
@@ -1,6 +1,280 @@
|
||||
// ═══════════════════════════════════════════════
|
||||
// Ced's Portfolio — script.js
|
||||
// NOC data loads from data/noc-status.json
|
||||
// Refreshes every 30s. Graceful fallback on fail.
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// Set copyright year
|
||||
const yearSpan = document.querySelector("[data-year]");
|
||||
if (yearSpan) {
|
||||
yearSpan.textContent = new Date().getFullYear();
|
||||
if (yearSpan) yearSpan.textContent = new Date().getFullYear();
|
||||
|
||||
// NOC data
|
||||
loadNocStatus();
|
||||
setInterval(loadNocStatus, 30000);
|
||||
|
||||
// GitHub pinned repos
|
||||
loadGithubRepos();
|
||||
});
|
||||
|
||||
// Track consecutive failures so we can show the fallback
|
||||
let failCount = 0;
|
||||
const MAX_FAILS = 3;
|
||||
|
||||
async function loadNocStatus() {
|
||||
const dot = document.getElementById("noc-dot");
|
||||
const statusText = document.getElementById("noc-status-text");
|
||||
const badge = document.getElementById("noc-refresh-badge");
|
||||
const nodes = document.getElementById("metric-nodes");
|
||||
const services = document.getElementById("metric-services");
|
||||
const vlans = document.getElementById("metric-vlans");
|
||||
const edge = document.getElementById("metric-edge");
|
||||
const grid = document.getElementById("noc-system-grid");
|
||||
const alertList = document.getElementById("noc-alert-list");
|
||||
const fallback = document.getElementById("noc-fallback");
|
||||
|
||||
try {
|
||||
// Cache-bust to always get fresh data
|
||||
// Use absolute URL when on NOC subdomain, relative when on main portfolio
|
||||
const nocDataUrl = window.location.hostname === 'noc.chasedumphord.com'
|
||||
? `https://chasedumphord.com/data/noc-status.json?t=${Date.now()}`
|
||||
: `data/noc-status.json?t=${Date.now()}`;
|
||||
|
||||
const res = await fetch(nocDataUrl);
|
||||
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// Reset fail counter on success
|
||||
failCount = 0;
|
||||
|
||||
// ── Status bar ──
|
||||
if (dot) {
|
||||
dot.className = "status-dot live";
|
||||
}
|
||||
if (statusText) {
|
||||
const d = new Date(data.lastUpdated);
|
||||
const formatted = d.toLocaleString('en-US', { month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true });
|
||||
statusText.textContent = `${data.nocName} — ${data.status} — Last updated: ${formatted}`;
|
||||
}
|
||||
if (badge) {
|
||||
badge.textContent = `Auto-refresh: 30s`;
|
||||
}
|
||||
|
||||
// Hide fallback if it was showing
|
||||
if (fallback) fallback.style.display = "none";
|
||||
|
||||
// ── Metrics ──
|
||||
if (nodes) animateMetric(nodes, data.summary.nodes);
|
||||
if (services) animateMetric(services, data.summary.services);
|
||||
if (vlans) animateMetric(vlans, data.summary.vlans);
|
||||
if (edge) animateMetric(edge, data.summary.edgeSystems);
|
||||
|
||||
// ── System cards ──
|
||||
if (grid) {
|
||||
grid.innerHTML = "";
|
||||
data.systems.forEach((system) => {
|
||||
const card = document.createElement("article");
|
||||
card.className = "noc-system-card";
|
||||
|
||||
const rawStatus = system.status.toLowerCase();
|
||||
const statusClass =
|
||||
rawStatus.includes("online") || rawStatus.includes("operational") ? "online"
|
||||
: rawStatus.includes("building") || rawStatus.includes("tuning") || rawStatus.includes("active") ? "warning"
|
||||
: "offline";
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="noc-system-top">
|
||||
<span class="mini-status ${statusClass}"></span>
|
||||
<span>${system.layer}</span>
|
||||
</div>
|
||||
<div class="system-label">${system.label || "System"}</div>
|
||||
<div class="severity-pill ${(system.severity || "unknown").toLowerCase()}">
|
||||
${system.severity || "Unknown"}
|
||||
</div>
|
||||
<h3>${system.name}</h3>
|
||||
<p>${system.type}</p>
|
||||
<code>${system.address}</code>
|
||||
<div class="system-meta">
|
||||
<small>Status: ${system.status}</small>
|
||||
<small>Latency: ${system.latency || "N/A"}</small>
|
||||
<small>Last Check: ${system.lastCheck || "Manual"}</small>
|
||||
</div>
|
||||
`;
|
||||
|
||||
grid.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
// ── Alerts ──
|
||||
if (alertList) renderAlerts(data.systems, alertList);
|
||||
|
||||
} catch (err) {
|
||||
failCount++;
|
||||
console.warn(`[NOC] Fetch failed (${failCount}/${MAX_FAILS}):`, err.message);
|
||||
|
||||
// Update dot to error state
|
||||
if (dot) dot.className = "status-dot error";
|
||||
|
||||
if (statusText) {
|
||||
statusText.textContent = failCount >= MAX_FAILS
|
||||
? "NOC feed offline — view live dashboard at noc.chasedumphord.com"
|
||||
: `NOC data unavailable — retrying... (${failCount}/${MAX_FAILS})`;
|
||||
}
|
||||
|
||||
if (badge) badge.textContent = "";
|
||||
|
||||
// After MAX_FAILS attempts, show the fallback block
|
||||
if (failCount >= MAX_FAILS && fallback) {
|
||||
fallback.style.display = "block";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Animate a number metric with a quick pop
|
||||
function animateMetric(el, value) {
|
||||
el.classList.remove("metric-pop");
|
||||
el.textContent = value;
|
||||
void el.offsetWidth; // force reflow
|
||||
el.classList.add("metric-pop");
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// GitHub Repos — fetches public repos for ced4568
|
||||
// Sorted by last pushed, capped at 6 cards
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
// Language → color map (subset of GitHub's palette)
|
||||
const LANG_COLORS = {
|
||||
Python: "#3572A5",
|
||||
JavaScript: "#f1e05a",
|
||||
Shell: "#89e051",
|
||||
HTML: "#e34c26",
|
||||
CSS: "#563d7c",
|
||||
Dockerfile: "#384d54",
|
||||
YAML: "#cb171e",
|
||||
Makefile: "#427819",
|
||||
};
|
||||
|
||||
async function loadGithubRepos() {
|
||||
const container = document.getElementById("github-repos");
|
||||
if (!container) return;
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
"https://api.github.com/users/ced4568/repos?sort=pushed&per_page=6",
|
||||
{ headers: { Accept: "application/vnd.github+json" } }
|
||||
);
|
||||
|
||||
if (!res.ok) throw new Error(`GitHub API ${res.status}`);
|
||||
|
||||
const repos = await res.json();
|
||||
|
||||
// Filter out forks for cleaner display
|
||||
const ownRepos = repos.filter((r) => !r.fork).slice(0, 6);
|
||||
|
||||
if (ownRepos.length === 0) {
|
||||
container.innerHTML = `<p class="noc-loading">No public repositories found.</p>`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = ownRepos.map((repo) => {
|
||||
const langColor = LANG_COLORS[repo.language] || "var(--accent-2)";
|
||||
const desc = repo.description
|
||||
? repo.description
|
||||
: "No description provided.";
|
||||
|
||||
const updatedDate = new Date(repo.pushed_at).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
return `
|
||||
<div class="repo-card">
|
||||
<div class="repo-card-top">
|
||||
<span class="repo-icon">📁</span>
|
||||
<a
|
||||
class="repo-name"
|
||||
href="${repo.html_url}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="${repo.name}"
|
||||
>${repo.name}</a>
|
||||
<span class="repo-visibility">${repo.private ? "private" : "public"}</span>
|
||||
</div>
|
||||
|
||||
<p class="repo-desc">${desc}</p>
|
||||
|
||||
<div class="repo-meta">
|
||||
${repo.language
|
||||
? `<span>
|
||||
<span class="repo-lang-dot" style="background:${langColor}"></span>
|
||||
${repo.language}
|
||||
</span>`
|
||||
: ""}
|
||||
<span>★ ${repo.stargazers_count}</span>
|
||||
<span>Updated ${updatedDate}</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join("");
|
||||
|
||||
} catch (err) {
|
||||
console.warn("[GitHub] Failed to load repos:", err.message);
|
||||
if (container) {
|
||||
container.innerHTML = `
|
||||
<div class="repo-loading">
|
||||
<p class="noc-loading">
|
||||
Could not load repositories.
|
||||
<a href="https://github.com/ced4568" target="_blank" rel="noopener noreferrer">
|
||||
View on GitHub →
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Build the alert panel from system data
|
||||
function renderAlerts(systems, alertList) {
|
||||
const scored = systems
|
||||
.map((sys) => {
|
||||
const sev = (sys.severity || "").toLowerCase();
|
||||
const status = (sys.status || "").toLowerCase();
|
||||
|
||||
let score = 0;
|
||||
if (sev.includes("critical") || status.includes("offline")) score = 3;
|
||||
else if (sev.includes("degraded")) score = 2;
|
||||
else if (sev.includes("unknown")) score = 1;
|
||||
|
||||
return { ...sys, score };
|
||||
})
|
||||
.filter((s) => s.score > 0)
|
||||
.sort((a, b) => b.score - a.score)
|
||||
.slice(0, 3);
|
||||
|
||||
if (scored.length === 0) {
|
||||
alertList.innerHTML = `
|
||||
<div class="noc-alert healthy">
|
||||
<strong>All monitored systems nominal</strong>
|
||||
<span>No critical or degraded systems detected.</span>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
alertList.innerHTML = scored.map((sys) => {
|
||||
const cls =
|
||||
sys.score === 3 ? "critical"
|
||||
: sys.score === 2 ? "degraded"
|
||||
: "unknown";
|
||||
|
||||
return `
|
||||
<div class="noc-alert ${cls}">
|
||||
<strong>${sys.name}</strong>
|
||||
<span>${sys.severity || sys.status} • ${sys.layer} • Latency: ${sys.latency || "N/A"}</span>
|
||||
</div>
|
||||
`;
|
||||
}).join("");
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
NOC_FILE = ROOT / "data" / "noc-status.json"
|
||||
BADGE_FILE = ROOT / "data" / "noc-badge.json"
|
||||
|
||||
with open(NOC_FILE, "r", encoding="utf-8") as file:
|
||||
data = json.load(file)
|
||||
|
||||
status = data.get("status", "Unknown")
|
||||
summary = data.get("summary", {})
|
||||
|
||||
online = int(summary.get("online", 0))
|
||||
offline = int(summary.get("offline", 0))
|
||||
total = online + offline
|
||||
|
||||
# 🔥 Determine severity
|
||||
if offline == 0:
|
||||
severity = "Healthy"
|
||||
color = "brightgreen"
|
||||
elif offline <= 2:
|
||||
severity = "Degraded"
|
||||
color = "yellow"
|
||||
else:
|
||||
severity = "Critical"
|
||||
color = "red"
|
||||
|
||||
# 🔥 Build message
|
||||
message = f"{severity} | {online}/{total} online | {offline} offline"
|
||||
|
||||
badge = {
|
||||
"schemaVersion": 1,
|
||||
"label": "Ced's NOC",
|
||||
"message": message,
|
||||
"color": color
|
||||
}
|
||||
|
||||
with open(BADGE_FILE, "w", encoding="utf-8") as file:
|
||||
json.dump(badge, file, indent=2)
|
||||
|
||||
print(f"NOC badge updated: {message}")
|
||||
@@ -0,0 +1,181 @@
|
||||
import json
|
||||
import socket
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
OUTPUT_FILE = Path(__file__).resolve().parent.parent / "data" / "noc-status.json"
|
||||
|
||||
SYSTEMS = [
|
||||
{
|
||||
"name": "Proxmox VE",
|
||||
"type": "Virtualization Platform",
|
||||
"host": "10.10.30.250",
|
||||
"port": 8006,
|
||||
"address": "10.10.30.250:8006",
|
||||
"layer": "Core Infrastructure",
|
||||
"label": "Hypervisor"
|
||||
},
|
||||
{
|
||||
"name": "TrueNAS",
|
||||
"type": "Storage Platform",
|
||||
"host": "10.10.30.143",
|
||||
"port": 80,
|
||||
"address": "10.10.30.143",
|
||||
"layer": "Storage",
|
||||
"label": "NAS"
|
||||
},
|
||||
{
|
||||
"name": "Nginx Proxy Manager",
|
||||
"type": "Reverse Proxy",
|
||||
"host": "10.10.30.210",
|
||||
"port": 81,
|
||||
"address": "10.10.30.210:81",
|
||||
"layer": "Access Layer",
|
||||
"label": "Proxy"
|
||||
},
|
||||
{
|
||||
"name": "Dashy",
|
||||
"type": "Service Dashboard",
|
||||
"host": "10.10.30.61",
|
||||
"port": 4000,
|
||||
"address": "10.10.30.61:4000",
|
||||
"layer": "Dashboard",
|
||||
"label": "Portal"
|
||||
},
|
||||
{
|
||||
"name": "Jellyfin",
|
||||
"type": "Media Service",
|
||||
"host": "10.10.30.143",
|
||||
"port": 30013,
|
||||
"address": "10.10.30.143:30013",
|
||||
"layer": "Application Service",
|
||||
"label": "App"
|
||||
},
|
||||
{
|
||||
"name": "K3s API",
|
||||
"type": "Kubernetes API",
|
||||
"host": "10.10.30.72",
|
||||
"port": 6443,
|
||||
"address": "10.10.30.72:6443",
|
||||
"layer": "Compute Cluster",
|
||||
"label": "Cluster"
|
||||
},
|
||||
{
|
||||
"name": "APRS Home iGate",
|
||||
"type": "RF Edge Gateway",
|
||||
"host": "10.10.30.129",
|
||||
"port": 8001,
|
||||
"address": "KJ5JCO-10 / Direwolf KISS 8001",
|
||||
"layer": "Edge / RF",
|
||||
"label": "iGate"
|
||||
},
|
||||
{
|
||||
"name": "APRS-IS",
|
||||
"type": "APRS Internet Service",
|
||||
"host": "noam.aprs2.net",
|
||||
"port": 14580,
|
||||
"address": "noam.aprs2.net:14580",
|
||||
"layer": "Edge / RF",
|
||||
"label": "External"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def check_tcp(host, port, timeout=2):
|
||||
start = time.perf_counter()
|
||||
|
||||
try:
|
||||
with socket.create_connection((host, port), timeout=timeout):
|
||||
latency_ms = round((time.perf_counter() - start) * 1000)
|
||||
return True, latency_ms
|
||||
except OSError:
|
||||
return False, None
|
||||
|
||||
|
||||
def severity_from_status(online, latency):
|
||||
if not online:
|
||||
return "Critical"
|
||||
|
||||
if latency is None:
|
||||
return "Unknown"
|
||||
|
||||
if latency < 50:
|
||||
return "Healthy"
|
||||
|
||||
if latency <= 150:
|
||||
return "Degraded"
|
||||
|
||||
return "Critical"
|
||||
|
||||
|
||||
def health_label(online_count, total):
|
||||
if online_count == total:
|
||||
return "All Systems Online"
|
||||
|
||||
if online_count >= max(1, total - 2):
|
||||
return "Degraded"
|
||||
|
||||
return "Action Required"
|
||||
|
||||
|
||||
def main():
|
||||
checked_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
systems = []
|
||||
online_count = 0
|
||||
offline_count = 0
|
||||
|
||||
for system in SYSTEMS:
|
||||
online, latency = check_tcp(system["host"], system["port"])
|
||||
|
||||
if online:
|
||||
status = "Online"
|
||||
online_count += 1
|
||||
latency_value = f"{latency} ms"
|
||||
else:
|
||||
status = "Offline"
|
||||
offline_count += 1
|
||||
latency_value = "N/A"
|
||||
|
||||
systems.append({
|
||||
"name": system["name"],
|
||||
"type": system["type"],
|
||||
"address": system["address"],
|
||||
"status": status,
|
||||
"severity": severity_from_status(online, latency),
|
||||
"layer": system["layer"],
|
||||
"label": system["label"],
|
||||
"latency": latency_value,
|
||||
"lastCheck": checked_at
|
||||
})
|
||||
|
||||
total_systems = len(SYSTEMS)
|
||||
|
||||
data = {
|
||||
"nocName": "Ced's NOC",
|
||||
"status": health_label(online_count, total_systems),
|
||||
"lastUpdated": checked_at,
|
||||
"summary": {
|
||||
"nodes": "12+",
|
||||
"services": f"{online_count}/{total_systems}",
|
||||
"online": str(online_count),
|
||||
"offline": str(offline_count),
|
||||
"vlans": "4",
|
||||
"edgeSystems": "2"
|
||||
},
|
||||
"systems": systems
|
||||
}
|
||||
|
||||
OUTPUT_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(OUTPUT_FILE, "w", encoding="utf-8") as file:
|
||||
json.dump(data, file, indent=2)
|
||||
|
||||
print(f"NOC status written to {OUTPUT_FILE}")
|
||||
print(f"Online systems: {online_count}/{total_systems}")
|
||||
print(f"Offline systems: {offline_count}/{total_systems}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
|
||||
<url>
|
||||
<loc>https://chasedumphord.com/</loc>
|
||||
<lastmod>2025-05-01</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://noc.chasedumphord.com/</loc>
|
||||
<lastmod>2025-05-01</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
|
||||
</urlset>
|
||||