ArticleReadView sourceAbout this wiki

Nathan's IT and Cybersecurity Journey

From learning fundamentals to building and securing real applications.

Nathan's Technology Wiki is a personal knowledge base for documenting my growth in information technology, secure software development, cybersecurity, AI, and responsible security testing.

This is where I turn lessons into plain-English notes, keep track of projects, and connect what I learn to practical work. It is a living record—updated as my skills and interests evolve.

My journey

I am building a broad, hands-on foundation in technology. That means learning the systems behind the screen—networks, operating systems, code, cloud services—and then asking how each one can be built and used more safely.

My goal is not just to collect tools or certifications. I want to understand the reasoning behind good technical decisions: how an application handles user data, why a network is segmented, how a scanner finding becomes a fix, and where AI can genuinely help.

Learning topics

This wiki is organized around the skills I am actively developing.

TopicWhat I am learning
IT fundamentalsNetworking, operating systems, cloud, and help desk practice.
Secure codingDesigning, reviewing, and maintaining applications safely.
Vulnerability scanningFinding, triaging, and documenting security weaknesses.
Penetration testingAuthorized testing methodology, labs, and evidence collection.
AI & automationUsing AI and scripting thoughtfully in IT and security work.
Vibe codingA practical workflow for AI-assisted building, versioning, and experience design.
Network & homelabA sanitized record of local services, routing boundaries, and operational lessons.

Vibe coding

Vibe coding is my approach to building quickly with AI while still owning the thinking: defining the goal, shaping the experience, reviewing every change, and documenting what happened. AI can accelerate a build; quality comes from the checks around it.

Build with intentionStart with a user problem, a small outcome, and clear acceptance checks.
Review the changeRead the diff, test key paths, and look for security or accessibility risks.
Leave a trailVersion the work, write a changelog entry, and capture the lesson learned.

3D image project

My 3D image project is a study in turning an idea into a visual experience. The focus is not only on making an image look good, but also on composition, performance, loading behavior, responsive presentation, and the way a visitor understands the work.

What I learned
  • Make the creative goal and audience clear before prompting or modeling.
  • Prototype small, then test the image on different screen sizes and connection speeds.
  • Keep original assets organized and name versions consistently.
  • Review the final result for visual clarity, accessibility text, and page performance.

OpenTrail

OpenTrail is a project space for documenting how an idea moves from an early concept to a dependable product. It gives me a place to record decisions, track changes, test the user journey, and explain why a version was released.

StageOpenTrail practice
PlanWrite the user story, success condition, scope, and risks.
BuildMake one focused code change with a clear purpose.
ReviewCheck the diff, security impact, UI states, and error paths.
ReleaseVersion the update and add a short changelog entry.

Code changes and best practices

Every change should be small enough to understand and easy enough to reverse. I use descriptive names, keep secrets out of code, validate inputs, update dependencies carefully, and test the behavior that users will actually touch.

Preflight checks

  • Does the change solve a specific user need?
  • Did I review the changed files and remove debug code?
  • Are secrets, keys, and personal data protected?
  • Do links, forms, loading states, and error states work?
  • Does the UI work on desktop and mobile?

Postflight checks

  • Did the release match the planned version and changelog?
  • Can I complete the main user journey without confusion?
  • Do logs or monitoring show an unexpected error?
  • Is the site fast enough with the new assets?
  • What did I learn for the next version?

Versioning, UI, and UX

Versioning gives every meaningful release a name and history. UI is what the interface looks like and how controls are arranged. UX is how the whole experience feels—from the first click to a successful outcome. I treat all three as part of the same quality standard.

Example changelog format

v0.3.0 — Added 3D gallery view
What changed: added an optimized visual gallery and responsive layout.
Why: makes the project easier to explore on any device.
Checked: navigation, image alt text, load time, and mobile layout.

Network & homelab

This is a sanitized operating record of my local lab. The current inventory shows 23 running containers across 11 named workloads on one local Docker host. IP addresses, hostnames, credentials, and exact proxy destinations are intentionally left out of this public-facing wiki.

EdgeFortinet firewall controls the boundary between the internet and internal services.
Application entryNginx Proxy Manager handles web reverse-proxy traffic and certificate management.
Local computeDocker Compose keeps each application and its data services in deliberate service groups.

How the setup works

InternetRequests arrive at the network edge.
Fortinet firewallApplies the approved network policy before any service is reached.
Nginx Proxy ManagerReceives approved web traffic and routes it to configured internal application targets.
Docker workloadsApplications run in separate Compose networks with their own databases and supporting services.

Nginx Proxy Manager is currently attached to its own proxy network and the OpenLinks network. The wiki and OpenTrail use separate application networks, so any proxy reachability must be configured deliberately rather than assumed. This page documents the design boundary, not private routing details.

Running applications

ApplicationWhat it doesStackKnown status / duration
Technology WikiLocal knowledge base for my IT and cybersecurity journey.Vinext, React, Next.js, DockerRunning; created during this wiki build.
Nginx Proxy ManagerReverse proxy and certificate-management entry point for approved web services.Nginx Proxy Manager, DockerRunning; observed about 13 hours at inventory time.
OpenTrailOutdoor trail web application with a documented product and release workflow.Web app, API, PostGIS, Redis, MinIO, migration jobRunning; historical record includes release v0.3.0. Current runtime observed about 13 hours.
OpenLinksLink and knowledge workspace.Node.js app, PostgreSQL, MinIOHealthy; current runtime observed about 13 hours.
WeaveNotePersonal notes and workspace application.Node.js app, PostgreSQL, AdminerHealthy; current runtime observed about 13 hours.
Cinderstrike SecuritySecurity project application and supporting data service.Node.js app, PostgreSQLHealthy; current runtime observed about 13 hours.
ShadowbrokerOSINT workspace for tracking global events, aircraft, satellites, and related signals.Node.js frontend, Python APIHealthy; current runtime observed about 13 hours.
Apache GuacamoleBrowser-based remote-access gateway for approved systems.Guacamole, guacd, PostgreSQLRunning; current runtime observed about 13 hours.
Krawl honeypotControlled security monitoring and deception-lab service.Python serviceRunning; current runtime observed about 1 hour.
AudiobookshelfPersonal audio and media library.Audiobookshelf, DockerRunning; current runtime observed about 13 hours.
PortainerContainer-management dashboard for the local Docker host.Portainer CE, DockerRunning; current runtime observed about 13 hours.

Databases, object storage, Redis, guacd, and Adminer are supporting services within these workloads, not separate user-facing applications. A running-container count is not the same as a physical host count: this inventory confirms one Docker host, while the total number of devices on the internal network is not documented here.

Past, one-time, and stopped work

ItemRecord
OpenTrail migrationCompleted successfully and exited with code 0. It is a one-time job, not a failed application.
BiasLens v1Prototype Node.js application. It is currently stopped after exit code 137; the cause is unconfirmed and should be checked through logs and host resources before restarting.

Limits, hurdles, and what I learned

Operational limits

  • Service groups are intentionally isolated, so proxy access needs an explicit route or shared network.
  • Container uptime is a runtime snapshot, not proof of when a project began.
  • Stateful services need tested backups, health checks, and careful update planning.
  • Admin tools should remain trusted-only and should not be exposed publicly by default.

Current hurdles

  • One local host runs multiple workloads, so CPU, memory, storage, patching, and monitoring must be managed together.
  • BiasLens needs evidence-based troubleshooting before it is brought back online.
  • Exact reverse-proxy mappings require a separate private configuration record.
  • Project timelines need repository first-commit dates or release notes before they can be stated precisely.
Documentation rule
I record architecture and lessons here, but keep secrets, internal addresses, firewall rules, and remote-access details in a protected administrator-only location.

Secure coding

Secure coding is the practice of considering security throughout an application's life—not just after something breaks. My notes cover input validation, authentication, secrets management, dependency updates, error handling, logging, and code review.

Learning principle
A secure app protects people as well as systems. I look for practical ways to reduce risk without making software harder to use.

Application security

I learned that application security starts before code: identify what data the app handles, who should be allowed to use each action, where information crosses a trust boundary, and what happens when a request fails. That turns security into design work rather than a last-minute patch.

Build habits

  • Validate input at the boundary and return safe, useful errors.
  • Keep dependencies updated and review changes before merging.
  • Minimize data collected, displayed, and retained.

Review questions

  • Can an unauthenticated user reach this action?
  • Can a valid user access another user's data?
  • Does an error reveal internals, secrets, or stack traces?

JWT tokens

JSON Web Tokens are signed credentials, not a substitute for authorization. I learned to keep tokens short-lived, verify their signature and expected issuer, audience, expiry, and algorithm on every protected request, and make authorization decisions from trusted server-side rules. Tokens must never contain passwords, secrets, or unnecessary personal data.

Practice: store signing keys outside source code, rotate them deliberately, use secure transport, and revoke or disable access through server-side account controls when needed.

Hashing and encryption

Hashing passwords

Passwords are one-way protected values. I use a purpose-built password-hashing algorithm such as Argon2id or bcrypt with a unique salt, never a fast general-purpose hash alone.

Encrypting data

Encryption protects data that must later be read. I use established libraries and TLS for data in transit, separate keys from data, and plan for key access, rotation, and recovery.

User management

User management taught me that a login is only the beginning. Each account needs a clear lifecycle: create, verify, assign the minimum role, change access when responsibilities change, disable promptly, and record important security events. Roles should describe tasks, while permissions control exactly what a role can do.

Least privilege: users, service accounts, and administrators receive only the access they need. Multi-factor authentication and audit logs add protection for higher-risk access.

Database management

Databases hold the information that makes an app valuable, so I learned to treat them as private dependencies. Applications use separate, restricted database accounts; migrations are reviewed; backups are tested; and database administration is kept off the public internet. The app should receive only the database permissions required for its own tables and actions.

SQL injection defense

SQL injection is prevented by separating data from commands. I use parameterized queries or a trusted ORM, validate input types and limits, avoid building queries through string concatenation, and give database accounts minimal privileges. Testing includes malformed and unexpected inputs so failures are safe and visible to the development team, not exploitable by a user.

Hardening APIs

API security combines strong request validation with clear authorization. I learned to authenticate protected endpoints, check permissions for every object and action, enforce schemas and size limits, rate-limit sensitive routes, minimize response data, use safe error messages, protect secrets in environment-managed configuration, and review CORS rules intentionally.

Before release

  • Confirm every endpoint has the correct access rule.
  • Test invalid input, missing tokens, and cross-user access attempts.
  • Verify logs help diagnose issues without recording secrets.

After release

  • Watch authentication failures and unusual error rates.
  • Patch vulnerable dependencies and rotate exposed credentials.
  • Review permissions as the API gains new features.

Permissions for other containers

Container security is also application security. Each service should run as a non-root user where practical, avoid privileged mode, use only the capabilities and mounted volumes it needs, and communicate over intentional Docker networks. Databases and admin tools should not be exposed by default, and inter-service credentials should be narrowly scoped and kept out of images and source control.

What I apply to my lab: isolate Compose stacks, grant service accounts only required database rights, keep management interfaces trusted-only, use health checks and backups for stateful services, and review network exposure before adding a proxy route.

Vulnerability scanning and pentesting

Vulnerability scanning helps identify potential weaknesses. Penetration testing validates risk through carefully scoped testing. Both require clear authorization, a defined scope, and responsible reporting.

My study notes focus on asset discovery, scanner results, false-positive triage, remediation, evidence, and how to communicate findings so they can be fixed.

Project log

Large projects now have their own wiki articles so architecture, releases, security lessons, roadmaps, and limitations can grow without overloading the main page.

OpenTrail

Outdoor trail application, modular stack, release history, migrations, and operational lessons.

Shadowbroker

OSINT application with separate frontend, Python API, data pipelines, and deployment assets.

WeaveNote

Notes workspace, authentication hardening, database management, and delivery lessons.

Planning, architecture & delivery

My projects taught me that reliable software starts with a plan and ends with evidence. The goal is to design the user journey, data boundaries, security controls, and recovery path before writing a large amount of code—then make each release traceable and testable.

Plan and architect first with advanced models

Advanced reasoning models are useful planning partners when I give them a clear product brief, not a vague request to build everything. I use them to challenge assumptions, draft alternatives, identify missing user states, propose a data model, and turn a feature into testable acceptance criteria. I keep the final decisions, security review, and code ownership human-led.

1. Product briefDefine the user, problem, success metric, constraints, and what is out of scope.
2. Architecture reviewMap UI, API, data, identities, integrations, trust boundaries, and failure paths.
3. Model-assisted critiqueAsk an advanced model for overlooked risks, edge cases, alternatives, and a test plan—without sharing secrets or private user data.
4. Decision recordChoose the smallest workable design, capture tradeoffs, and break it into independently reviewable work.
Planning rule: an AI-generated architecture is a draft to inspect, not an authority to copy. I verify dependencies, permissions, data flows, cost, and operational limits before implementation.

Non-monolithic code

Non-monolithic does not have to mean many servers. It means code is organized around clear responsibilities so one feature does not become a single, tangled file or application layer. A modular monorepo can still deploy as one product while keeping UI, domain logic, API routes, data access, and shared types separate.

Module boundaries

  • Presentation: pages, components, accessibility, and user states.
  • Domain: business rules and use cases that do not depend on a screen.
  • Infrastructure: database, storage, third-party APIs, and container configuration.
  • Shared packages: stable contracts, types, validation, and reusable utilities.

Why it matters

  • Smaller changes are easier to review, test, and roll back.
  • Permissions and secrets stay closer to the service that truly needs them.
  • A failure or redesign is less likely to spread across unrelated features.
  • Teams or future contributors can work without hidden coupling.

Versioning and change tracking

I use a changelog as the plain-English record of what changed and why, and tags/releases as the exact version that was delivered. Semantic versioning gives a useful shared language: a patch for compatible fixes, a minor version for compatible features, and a major version when the contract changes. Every release should point to its source revision, migration impact, known limitations, and rollback plan.

Issue / decisionRecord the problem, intent, scope, owner, and acceptance checks.
Focused changeUse a small branch or change set with a readable commit message and reviewable diff.
Release recordTag the version, update the changelog, and identify deployment notes and compatibility risks.
Operational historyLink incidents, hotfixes, migrations, and follow-up work back to the release.

Delivery pipelines

A pipeline is the repeatable path from a code change to a verified release. I learned that pipeline visibility matters as much as speed: a failing install, test, or migration must stop the release and show the real error. Silent success is not success.

StageWhat the pipeline provesEvidence to keep
ValidateFormatting, types, lint rules, unit tests, dependency and secret checks pass.Build/test logs and resolved findings.
BuildThe production artifact and container image are created from the intended revision.Version, commit, image tag, and build output.
TestKey user journeys, authorization rules, API errors, and migrations behave safely.Test cases, screenshots only when useful, and health results.
ReleaseThe approved artifact reaches the correct environment with controlled configuration.Changelog, deployment record, and rollback steps.
ObserveHealth checks, logs, and alerts show the release is working for real users.Postflight outcome and follow-up actions.

Detailed preflight checks

Product & architecture

  • Confirm the user story, success condition, non-goals, and accessibility states.
  • Review data flow, system boundaries, API contract, and dependency ownership.
  • Choose a module boundary before adding code; avoid putting UI, business logic, and database access in one place.
  • Write a migration and compatibility plan before changing persisted data.

Security & operations

  • Check authorization on every protected action and object, not only at login.
  • Confirm secrets come from protected configuration and never from committed files or images.
  • Review exposed ports, proxy routes, container privileges, volumes, and network reachability.
  • Verify backups, health checks, observability, resource limits, and a safe rollback path.

Release quality

  • Run the build, type checks, tests, and targeted manual user journeys.
  • Review the complete diff for debug code, unused permissions, and accidental scope expansion.
  • Update version, changelog, release notes, and known limitations.
  • Make sure pipeline failures stop the process rather than hiding an upstream error.

Detailed postflight checks

Verify the experience

  • Complete the highest-value user journey as a real user would.
  • Test login, logout, permissions, error states, and a cross-user access boundary.
  • Confirm the new version and user-facing changes match the approved release notes.

Verify the platform

  • Check service health, startup logs, error rate, latency, storage, and resource use.
  • Confirm migrations completed and backups are still scheduled and recoverable.
  • Watch API authentication failures, unusual access patterns, and container restarts.

Close the learning loop

  • Record what went well, what surprised me, and what should become a standard check.
  • Create follow-up work for defects, hardening, documentation, and monitoring gaps.
  • Keep the rollback plan until the release is stable, then close the delivery record.

What my projects taught me

Project evidenceWhat I learned to include next time
OpenTrail is organized with apps, packages, documentation, infrastructure, release tags, and a semantic-versioning changelog.Start with intentional module boundaries, document architecture and release policy, and make each version traceable to a decision and a tested build.
Shadowbroker separates frontend, backend, and deployment assets, including Helm configuration.Keep presentation, API, and deployment concerns separate so each can be tested, secured, and changed without turning the product into one monolith.
WSH records a JWT configuration health check and a build issue where an output pipeline masked an install failure.Fail closed on unsafe authentication configuration, test the health of security-critical dependencies, and preserve real command failures in automated pipelines.
OpenLinks uses Prisma migrations, backup artifacts, and a restore workflow.Plan schema changes, backups, and recovery alongside features—database operations are part of delivery, not an afterthought.

Roadmaps, stack design & app behavior

Future planning is how I turn a good idea into work that can be delivered safely. I learned to plan the outcome, dependencies, architecture, backup and recovery needs, and user flow together—not as separate tasks added after the application already exists.

Roadmaps and future planning

A roadmap is a direction and sequence, not a promise that every feature will ship on a specific day. I organize it by outcomes: what user problem is being improved, what evidence would show success, what dependencies must be ready, and what could make the work unsafe or too expensive.

Now: discover

  • Define the problem, user, success measure, scope, and non-goals.
  • List risks, data involved, integrations, and owners.
  • Use an advanced model to challenge the brief and identify missing states or edge cases.

Next: design & deliver

  • Choose the smallest architecture that meets the need.
  • Break the work into milestones with acceptance checks and dependencies.
  • Build a thin vertical slice first: UI, API, data, and permissions working together.

Later: stabilize & improve

  • Use release evidence, feedback, errors, and performance data to prioritize.
  • Schedule upgrades, backup restore drills, security reviews, and debt reduction.
  • Move uncertain ideas forward only after the current foundation is healthy.

Stack and backup design

A stack is the set of layers that make an application work: interface, application/API, identity, database, cache or queues, file/object storage, observability, network entry, and deployment. I choose each layer based on a real requirement and document the owner, data it handles, access it needs, and how it is recovered.

Design areaWhat I planRecovery question
ApplicationFramework, modules, API contract, configuration, and release artifact.Can I redeploy the exact known-good version?
IdentityAccounts, roles, MFA, session/token policy, and audit events.Can access be disabled quickly without losing evidence?
DatabaseSchema, migrations, retention, restricted accounts, and logical backups.Can I restore to a tested point and verify the data?
Files & storageObject/volume ownership, encryption, lifecycle, and upload limits.Are important files copied separately from the running host?
PlatformContainers, Compose/network policy, proxy entry, logs, health, and resource limits.Can I rebuild infrastructure from versioned configuration?
Backup design lesson: a backup is only useful when it is protected, complete, and restored successfully in a test. I plan recovery targets—how much data loss is acceptable and how long recovery can take—then keep more than one protected copy, separate from the live service.

How an application interacts and functions

Before building a feature, I map the path of one normal request and one failure. The diagram below is the mental model I use for a typical local web application; actual components vary by project.

1. User & browserThe user sees the UI, enters data, and receives accessible loading, success, or error states.
2. Network entryThe firewall and reverse proxy accept only intended traffic and send it to the correct application.
3. FrontendThe interface validates basic input, preserves only needed state, and calls the approved API contract.
4. API & domain logicThe service authenticates the request, checks permission for the exact action and object, validates input again, and applies business rules.
5. Data servicesThe API uses restricted credentials, parameterized queries, and intentional storage access; databases are not trusted directly by the browser.
6. Response & evidenceThe user receives the minimum safe response while health, errors, and important security events are recorded without secrets.

Interaction contract

  • Every boundary has an expected request, response, failure behavior, and owner.
  • UI convenience checks never replace server-side validation or authorization.
  • Services use explicit APIs rather than reaching into another module's private data.

Design for failure

  • Define timeouts, retries, idempotency, and a clear user message for failed requests.
  • Keep changes reversible through versioned artifacts and migration/rollback plans.
  • Use health checks and restore tests to prove the system can recover.

Quality, testing & cybersecurity framework

I learned that building an application is not the same as proving it works. Quality comes from checking the product against its requirements, validating it with real user journeys, and operating it inside a security framework that can prevent, detect, respond to, and recover from problems.

Validation and verification

Verification: built correctly

Verification checks the implementation against the agreed design and acceptance criteria. I use code review, type checks, unit and integration tests, API contract checks, migration review, dependency checks, and configuration review to prove the release matches its specification.

Validation: built the right thing

Validation checks the real outcome. I complete the user journey, confirm the problem is actually solved, test accessibility and error states, and collect feedback or operational evidence. A technically correct feature can still fail validation if users cannot use it safely or clearly.

Quality rule: define evidence before implementation. Every important requirement should have a visible acceptance check, an owner, and a result recorded before a release is considered complete.

Testing to ensure an app works well

Test layerWhat I checkWhen I use it
Unit testsSmall business rules, validators, utilities, and permission decisions.With each focused code change.
Integration testsAPI, database, authentication, storage, and service boundaries working together.Before merging or releasing changes that cross a boundary.
End-to-end testsReal workflows such as sign-in, create, view, edit, access denial, and error recovery.For high-value journeys and release candidates.
Security testsAuthorization checks, malformed input, secret handling, dependency findings, and exposure review.During preflight and whenever a trust boundary changes.
Operational testsHealth checks, backups, restore drills, performance, logs, alerts, and rollback.Before release and periodically after release.

My holistic cybersecurity framework

My framework connects the full lifecycle of an application and lab environment. It is a practical set of habits I can apply to any project, not a claim that a tool or container is secure by itself.

1. PlanIdentify assets, users, data, trust boundaries, risks, and the acceptable recovery target.
2. ProtectUse least privilege, strong identity, secure defaults, patching, secrets management, and segmented networks.
3. VerifyReview code, permissions, exposure, dependencies, tests, backups, and release evidence.
4. DetectUse health checks, logs, error monitoring, audit events, and alerts to find abnormal behavior.
5. RespondContain the issue, disable risky access, preserve useful evidence, communicate, and apply a controlled fix.
6. Recover & learnRestore safely, verify the user experience, document the lesson, and improve the next preflight check.

Containers for isolated troubleshooting

Containers let me package an application with its runtime dependencies and run it separately from other workloads. This makes it easier to reproduce a problem, compare configuration, inspect one service's logs, restart or rebuild a single app, and reduce the chance that a dependency change breaks every other project on the host.

What isolation helps with

  • Separate application dependencies, environment configuration, volumes, and logs.
  • Recreate a known version of one workload without reinstalling the entire host.
  • Limit service-to-service reachability through intentional Compose networks.

What it does not solve alone

  • A container is not automatically a complete security boundary.
  • Privileged containers, broad mounts, exposed ports, and shared secrets can still create risk.
  • Host patching, backup protection, least privilege, and monitoring remain necessary.

Nginx Proxy Manager: multiple apps from one host

Nginx Proxy Manager (NPM) gives one host a controlled front door for multiple web applications. It receives web requests on the standard HTTP/HTTPS entry points, matches the requested hostname to an approved proxy-host rule, terminates TLS when configured, and forwards the request to the correct internal application. This allows several apps to share one host without each app directly owning the public web ports.

One public entryTraffic reaches the firewall and then NPM, instead of exposing every application directly.
Hostname routingNPM uses an approved hostname rule to select the intended app; each app remains a separate workload.
Internal handoffNPM forwards only to the configured upstream target. Separate Docker networks require deliberate connectivity or an explicit upstream route.
App-level securityThe target application still owns authentication, authorization, input validation, and its own data protections.
Operational lesson: NPM reduces port and certificate-management complexity, but it is not a replacement for firewall policy, segmented networks, application security, or permission review. Every new proxy route should go through preflight checks.

About this wiki

This is a personal reference site inspired by the clear, article-based structure of traditional wikis. It is independent and not affiliated with Wikipedia or the Wikimedia Foundation.

This page is a work in progress. Last updated: July 2026.