← All projects

DEVOPS · INFRASTRUCTURE

Portfolio Infrastructure - Self-Hosted CI/CD

The deployment platform behind this portfolio: an Astro application built through GitHub Actions, published as a Docker image to GHCR and automatically deployed to my TrueNAS homelab.

AstroDockerGitHub ActionsGHCRTrueNASDockgeNginxDNSCI/CD
TYPEPersonal Infrastructure Project
ROLEDesign · Development · Operations
YEAR2026
STATUSLive
01 · OVERVIEW

The portfolio is part of the portfolio.

Instead of deploying this site through a managed static-hosting platform, I chose to run the complete production environment from my own homelab.

The website is developed locally, version-controlled through GitHub, built automatically into a container image, stored in GitHub Container Registry and deployed onto my TrueNAS server.

Public traffic reaches the application through my domain and Nginx Proxy Manager, which handles HTTPS and forwards the request to the running portfolio container.

THIS PAGEYou are currently viewing the application running through the infrastructure described below.
02 · CI/CD

From source code to my home server.

The deployment process is designed so that normal website changes happen through Git rather than by editing files directly on the production server.

01VS CodeDevelop locally
→
02GitHubPush to main
→
03GitHub ActionsBuild application
→
04GHCRPublish image
→
05TrueNASPull & deploy

Source controlled

Production changes originate from the Git repository rather than manual modifications on the server.

Repeatable builds

The same Dockerfile is used each time the application is built, reducing differences between deployments.

Container registry

GitHub Container Registry acts as the handoff point between the CI environment and my self-hosted infrastructure.

Automated deployment

TrueNAS periodically checks for the current production image and recreates the container when a new version is available.

03 · BUILD

A containerized Astro application.

Astro is used for the main website because most portfolio content can be generated as static HTML. Interactive elements, such as the homelab architecture explorer, use React where browser-side state is actually needed.

The production build is packaged into a Docker image so the hosting environment only needs to know how to run the container.

APPLICATIONAstro

Static-first site structure, reusable layouts and project components.

INTERACTIVITYReact

Used selectively for components such as the interactive homelab topology.

PACKAGINGDocker

Provides a reproducible artifact that can be built in CI and executed on TrueNAS.

04 · VERSIONING

Current release plus immutable builds.

Container images are published with both a production tag and a commit-specific tag.

PRODUCTIONghcr.io/.../portfolio:latest

Used by the normal deployment so the server can follow the current production release.

IMMUTABLE BUILDghcr.io/.../portfolio:sha-<commit>

Identifies a specific build and provides a straightforward rollback target when necessary.

05 · HOSTING

Running production from TrueNAS.

The production container runs alongside the other services in my homelab. Docker Compose defines how the application runs, while Dockge provides a convenient interface for managing the stack.

TRUENAS SERVER
Docker
Portfolio
Nginx Proxy Manager
Dockge
06 · NETWORK

How a visitor reaches the site.

DNS directs the portfolio hostname toward my public connection. Incoming HTTPS traffic is forwarded to Nginx Proxy Manager, which terminates TLS and proxies the request to the portfolio container.

VISITORBrowser
→
DNSDomain
→
EDGERouter
→
HTTPSNginx Proxy Manager
→
CONTAINERPortfolio
DOMAINgeorg.nordicgh.net
TLSHTTPS termination
PROXYNginx Proxy Manager
07 · OPERATIONS

Deployment is not finished when the container starts.

The portfolio container includes a Docker health check that verifies the web server can actually respond from inside the running container.

This distinguishes a container that merely has a running process from one that is able to serve the application.

CONTAINER HEALTHhealthy

Application endpoint responds successfully.

08 · SECURITY

Keep the public surface small.

Self-hosting a public website also means owning the security boundary. The portfolio is therefore treated differently from internal administrative services in the homelab.

01

Reverse proxy

Public web traffic reaches the application through a dedicated reverse-proxy layer instead of exposing management interfaces directly.

02

HTTPS

TLS is terminated at the reverse proxy and HTTP requests can be redirected to encrypted connections.

03

Management separation

Administrative services are kept separate from the public portfolio and can remain LAN- or VPN-oriented.

04

Container boundary

The website runs as a dedicated container rather than directly modifying the underlying TrueNAS host environment.

09 · WHY SELF-HOST?

A managed platform would have been easier.

Hosting an Astro site through a managed provider would require much less infrastructure. I deliberately chose the self-hosted route because operating the deployment environment was part of the project.

Networking

DNS, public ingress, port forwarding, TLS and reverse proxy routing become real parts of the application architecture.

Containers

Application packaging, registries, Compose stacks and container lifecycle management become practical operational concerns.

CI/CD

Development and production are connected through an automated build and deployment process rather than manual file copying.

Operations

Availability, health checks, rollback strategy and service exposure become my responsibility rather than the hosting provider's.

10 · OUTCOME

A portfolio that demonstrates its own infrastructure.

The final result is more than a frontend project. A change made in my local development environment can move through source control, automated build infrastructure, a container registry, my homelab and the public reverse proxy before appearing on the live site.

The same infrastructure also ties directly into the interactive Homelab page, which documents the environment this application is actually running inside.

KEY TAKEAWAYBuilding the website was only half of the project. The other half was designing a repeatable path from source code to a service running on infrastructure I operate myself.