Make the automated pipeline the documented "setup moving forward" and finish scrubbing the last stale GitHub-Actions/racknerd1 references that never reached main. - HANDOFF.md: refresh the stale 2026-06-21 snapshot. New "CI/CD & deploy" section (push to main -> build + push to registry.snsnetlabs.com -> auto-deploy to racknerd2 over SSH, SHA-pinned, /api/health gate), racknerd2 validation-host + SSH-tunnel access notes, Forgejo workflow rule, and a current Deployment + orientation section. - .kiro/steering/project-guide.md: Forgejo-only Git workflow (no gh), CI/CD row, registry host, racknerd2 + forgejo-runner SSH entries, and a CI/CD pipeline section. - .kiro/hooks/tunnel-racknerd2-8080.kiro.hook: the "View ArchNest on racknerd2" hook (ssh -L 8080:localhost:8080 -N) to view the deployed site at http://localhost:8080 (racknerd2's edge only allows port 22). - src/pages/Settings.tsx: About panel repo URL -> Forgejo. - .dockerignore: .github -> .forgejo. - TERMIX_MIGRATION.md / docs/OPEN-SOURCE-RELEASE.md: drop stale .github/workflows + "GitHub Actions deploy" references. Co-authored-by: Samuel James <ssamjame@amazon.com> Co-authored-by: Kiro <noreply@kiro.dev>
12 KiB
ArchNest — Open-Source Release Readiness (v1)
This document is the checklist + plan for publishing ArchNest as an open-source project. It is an internal planning doc — do not copy this file into the public repo. It covers what to copy, what to scrub, licensing, repo structure, README/screenshots, the release cadence, and resume/LinkedIn framing.
The public OSS repo should be a fresh repository with a clean history (see "Why a fresh repo" below), not a fork of the working repo.
1. Security sweep result (done 2026-06-22)
A full secret/credential sweep of tracked files and entire git history
(git log --all -p) was run. Result: clean — no real secrets are committed.
- No private keys, no hardcoded secret assignments in tracked source.
- No real
.env,.pem,.key, or.dbwas ever committed at any point in history. The onlyBEGIN RSA PRIVATE KEY/AKIA…matches are documentation prose and AWS's officialAKIAIOSFODNN7EXAMPLEplaceholder. .gitignorecorrectly excludesbackend/.env,backend/data,*.db.- Both
.env.examplefiles contain only placeholders (empty /change-me-…).
Code-level security review (solid)
- JWT auth (Fastify
@fastify/jwt). Every route group registers a blanketaddHook('onRequest', app.authenticate)before its routes; the three WebSocket routes (terminal,docker,guacamole) verifyapp.jwt.verify(query.token)explicitly (WS can't use header hooks). - Mutating shared-config endpoints (integrations, tunnels, data export/import,
user management) are gated by
adminOnly/requireAdmin.authenticatere-readsrole/activefrom the DB each request, so demote/deactivate takes effect immediately even with an older token. - Integration secrets:
serialize()returns only secret key names (secretKeys), never values. Secrets are encrypted at rest (AES-256-GCM,backend/src/db/crypto.ts). - Docker agent ingest is a separately registered route with a constant-time
bearer-token check; returns 503 when
ARCHNEST_AGENT_TOKENis unset (disabled by default), and is NOT behind the user-auth hook (by design). - Command-injection surfaces are guarded: tmux session names validated against
^[A-Za-z0-9_-]{1,64}$before interpolation;system.tsusesexecFile(no shell); Docker-over-SSH single-quotes container refs.
Things to improve / note for OSS (not leaks)
- CORS default:
server.tsdoesorigin: process.env.ARCHNEST_CORS_ORIGIN ?? true.truereflects any origin. Fine for a self-hosted single-origin deploy, but the OSS README should tell users to setARCHNEST_CORS_ORIGINin production, and the default.env.exampleshould point athttp://localhost:5173(it already does for the backend example). - Default JWT/secret env values in
backend/.env.examplearechange-me-…— the README must stress generating real ones (openssl rand -hex 32). The server already refuses to boot withoutARCHNEST_SECRET_KEY+ARCHNEST_JWT_SECRET.
2. What to SCRUB / NOT copy to the public repo
None of these are security leaks, but they are personal/infra-specific or internal working notes that don't belong in a public project:
| Item | Why | Action |
|---|---|---|
docs/rdp-debug-handoff.md |
Contains lab creds (sam / happy2026) + private VM IP 192.168.122.55 + personal host names |
Exclude (or heavily genericize into a "Remote Desktop setup" guide with no creds/IPs) |
HANDOFF.md |
Internal session-to-session working notes | Exclude |
docs/OPEN-SOURCE-RELEASE.md (this file) |
Internal release plan | Exclude |
archnest.snsnetlabs.com references in .env.example, docker-compose.yml |
Personal domain/deploy target | Genericize to example.com / localhost |
Forgejo CI (.forgejo/workflows/) |
Already build/validate only (no SCP/personal server). The build workflow pushes to a private registry + deploys to a private host | Keep but genericize the registry host + deploy job, or strip the deploy job for a public build-only CI |
agent/ deploy specifics |
Fine to include the agent script, but scrub any host-specific URLs/tokens in its README | Review + genericize |
assets/ personal background images |
Large PNGs; keep the ones the UI needs (hero banner, logo, KPI backgrounds), drop unused experiments (opt1.bg, settings-custom-bg, pics/) |
Trim to what's referenced |
| Test/scratch files | backend/data/, any *.db, session logs |
Already gitignored — confirm none are force-added |
Keep ROADMAP.md and TERMIX_MIGRATION.md? — ROADMAP.md yes (genericize:
it's a fine public roadmap once paid-tier framing is softened). TERMIX_MIGRATION.md
is build history; optional — can keep as docs/HISTORY.md or drop.
3. Why a fresh repo (recommended)
The working repo's history contains personal commit author emails, the personal deploy workflow, the lab-cred debug doc, and the personal domain. The simplest clean cut for a public project:
- Create a new empty public repo (e.g.
archnestunder the personal GitHub). - Copy the working tree (not
.git) of the files in the "INCLUDE" list below. - Genericize the scrubbed items.
git init, single initial commit ("Initial public release — ArchNest v1"), author set to the public identity.- Add
LICENSE, publicREADME.md,CONTRIBUTING.md, screenshots.
This avoids dragging history-scrubbing tooling (BFG/git filter-repo) and
guarantees nothing personal leaks via an old commit.
INCLUDE (the actual app)
src/ # React frontend
backend/src/ # Fastify backend
backend/package.json, backend/tsconfig*.json, backend/Dockerfile
backend/.env.example # (placeholders only — already clean)
package.json, package-lock.json, tsconfig*.json, vite.config.*, index.html
Dockerfile, docker-compose.yml # genericized (no personal domain)
.env.example # genericized
.gitignore, .dockerignore
public/ # fonts + static assets actually referenced
assets/ # ONLY images the UI imports
agent/archnest-docker-agent.sh + a genericized agent/README.md
design-decisions.md, ROADMAP.md # genericized
.kiro/steering/design-rules.md # optional — useful for contributors
LICENSE, README.md, CONTRIBUTING.md, screenshots/ # new, written for OSS
EXCLUDE
.git/ # fresh history instead
HANDOFF.md
docs/rdp-debug-handoff.md
docs/OPEN-SOURCE-RELEASE.md (this file)
.forgejo/workflows/ (genericize: strip registry host + deploy job, or build-only CI)
backend/data/, *.db, session logs, *.tsbuildinfo
unused assets/ experiments + pics/
4. License
Recommended: MIT or Apache-2.0.
- MIT — shortest, most permissive, maximum adoption, easiest "I built this" story. Good default for a portfolio/resume project.
- Apache-2.0 — same permissiveness plus an explicit patent grant and a NOTICE mechanism; slightly more "enterprise-friendly."
Given the goal (resume/LinkedIn showcase, broad adoption, simple), MIT is the
recommendation. Add a LICENSE file with the chosen license and the author's name
- year. Note third-party components keep their own licenses (Guacamole = Apache-2.0,
the bundled Nerd Font has its own license already in
public/fonts/NERD-FONTS-LICENSE.txt).
5. README.md (public) — outline
- Hero: one-line pitch + a screenshot/GIF of the Glance dashboard.
"A self-hosted, web-based control panel for your homelab and cloud — SSH terminal, file manager, Docker, tunnels, RDP/VNC, host metrics, and integration dashboards, all in one browser tab."
- Screenshots (see §6).
- Features — bullet list grouped by page; mark paid add-ons / not-yet-done honestly (mirror the in-app Help "Not in the open-source version" notes).
- Architecture — short: React + Vite + TS frontend, Fastify + SQLite backend, guacd sidecar for RDP/VNC. One diagram is plenty.
- Quick start —
docker compose uppath + the required env vars (withopenssl rand -hex 32generation), and the local-dev path (npm install/npm run devin root andbackend/). - Configuration — env var table (from
.env.example), CORS note, first-run/api/setupadmin creation, the 10-user cap. - Security notes — secrets encrypted at rest; set a real CORS origin in prod; it's designed to sit behind your own mesh/VPN, not be exposed raw to the internet (mesh prerequisite gate exists, defaults off).
- Roadmap — link
ROADMAP.md+ the "updates ~every 3 months" promise. - Contributing — link
CONTRIBUTING.md. - License — MIT.
- Credits / "Built with AI" — see §7.
6. Screenshots to capture (for README + LinkedIn)
Capture in the default dark theme, with demo/sanitized data (no real hostnames, IPs, or tokens — use the placeholder-y names):
- Glance dashboard (hero shot)
- Infrastructure → Node Status with a couple of integrations
- Terminal with a split-pane / multiple tabs
- Files (SFTP browser) + a host-to-host transfer in progress
- Containers list + a container detail tab
- Remote Desktop showing a live XFCE session
- Host Metrics widgets
- Settings → Integrations (shows the breadth) and the locked Appearance "Paid add-on" card (shows the free/paid split honestly)
- Help page (shows the per-page docs + OSS-edition note)
A short screen-recording GIF of opening a terminal or RDP session makes the strongest LinkedIn post.
7. Resume / LinkedIn framing
Honest, specific, and ownership-forward. Suggested phrasing:
ArchNest — a self-hosted, web-based homelab/cloud control panel (React + TypeScript + Fastify + SQLite, Dockerized). Single-pane access to SSH terminals, SFTP, Docker, SSH tunnels, browser-based RDP/VNC (Apache Guacamole), live host metrics, and pluggable infrastructure integrations (Proxmox, AWS, Cloudflare, NetBird, Uptime Kuma). Built with AI-assisted development; I owned the architecture, product decisions, security review, and integration/debugging (e.g. root-caused and fixed a FreeRDP/NLA + Guacamole tunnel-keepalive issue end-to-end across browser, proxy, and target VM). Open source under MIT, shipped v1, ongoing ~quarterly releases.
Notes for credibility:
- It's fine and increasingly normal to say "AI-assisted." Pair it with the engineering judgment you provided (architecture, security, debugging) so it reads as "I directed and verified," not "I prompted and pasted."
- The RDP debugging saga is a genuinely strong, concrete story — it shows multi-layer debugging (browser ↔ guacd/FreeRDP ↔ xrdp/desktop) and root-cause rigor. Worth a short LinkedIn write-up on its own.
8. Pre-publish checklist
- Create fresh public repo, copy INCLUDE list, exclude EXCLUDE list.
- Genericize personal domain →
example.com/localhostin.env.example,docker-compose.yml. - Genericize
.forgejo/workflows/for public use (strip the private registry host + the racknerd2 deploy job, or ship build-only CI). - Add
LICENSE(MIT), publicREADME.md,CONTRIBUTING.md. - Capture + add screenshots (sanitized data, dark theme).
- Re-run a secret scan on the NEW repo before first push
(
git log -p | grep -iE 'AKIA|BEGIN .*PRIVATE KEY|password|secret'plus a tool likegitleaks detectfor good measure). - Confirm
npm run build(root) andnpx tsc --noEmit(backend) pass on the copied tree. - Confirm first-run works from a clean
docker compose upwith freshly generated secrets and no prior DB. - Tag
v1.0.0.
9. Release cadence (commitment)
Public promise: updates approximately every 3 months. Keep a short
CHANGELOG.md in the public repo and cut a tagged release each cycle. The Help
page's "Open-source edition" note and the README both reference this cadence —
keep them in sync.