HLBuilder is a comprehensive, interactive web application designed to simplify the process of planning and architecting home laboratory infrastructure. It provides users with a visual interface to design network topologies, receive intelligent hardware recommendations based on their self-hosting needs, and generate actionable shopping lists.
The core of the application is a visual canvas powered by ReactFlow.
- Drag-and-drop hardware nodes: Routers, switches, servers, NAS, Mini-PCs, SBCs (like Raspberry Pi), UPS, and more.
- Wire components: Graph-based representation of physical and logical connections.
- Nested Virtualization: Define Virtual Machines (VMs), Containers, or LXCs directly on compute nodes.
- Real-time Synchronization: The visual state is continuously synchronized with a PostgreSQL database.
A sophisticated backend microservice manages network addressing:
- Microservice Architecture for Scaling: Built as a completely independent, stateless Go service. IP allocation requires heavy graph traversal and subnet math; isolating it means we can horizontally scale the IPAM workers seamlessly under high load without dragging down the main API server.
- Topology-Aware BFS: Automatically assigns IP addresses by performing a Breadth-First Search from the gateway.
- Dynamic Pool Sizing: Intelligently packs VM-hosting devices into separate pools without collisions.
- Conflict Prevention: Handles custom IP assignments and avoids DHCP range overlaps.
- Comprehensive Catalog: Browse popular homelab services with pre-defined resource requirements.
- 3-Tier Suggestions: Generates "Minimal", "Recommended", and "Optimal" hardware profiles.
- Live Resource Dashboard: Calculates aggregate CPU, RAM, Storage, and Power needs to ensure hardware can handle the concurrent load.
- Itemized Components: Automatically generates a shopping list including main hardware and necessary peripherals (RAM, NVMe, etc.).
- Price Estimation: Provides estimated costs with direct purchase links based on your region.
| Layer | Technology |
|---|---|
| Frontend | React 18 + TypeScript, Vite, ReactFlow, TailwindCSS, Zustand |
| Backend API | Go 1.24+, Gin, GORM v1.25.x |
| IPAM Microservice | Go 1.24+, Standard Library REST API |
| Database | PostgreSQL 15 |
| Auth & Security | Google OAuth 2.0 + JWT |
| Deploy | Docker & Docker Compose |
For detailed information on the codebase architecture, folder structure, testing infrastructure, and known pitfalls, please refer to docs/ARCHITECTURE.md. For the feature roadmap and future ideas, see ROADMAP.md.
HLBuilder ships with a built-in auth-disabled mode designed for self-hosted / local deployments where you don't want to (or can't) set up Google OAuth credentials. When enabled, the application bypasses all login screens and automatically provisions a local admin user - no Google account, no OAuth app registration, and no tokens required.
The entire mechanism is driven by a single condition: whether GOOGLE_CLIENT_ID is set.
| Component | What happens when GOOGLE_CLIENT_ID is empty / unset |
|---|---|
| Backend | config.AuthDisabled becomes true. Every protected endpoint's auth middleware skips JWT validation and instead auto-provisions a Local Admin user ([email protected]) with full access, including admin privileges. |
| Frontend | VITE_GOOGLE_CLIENT_ID is empty, so the Google login button is non-functional. The auth hook detects this and calls /auth/me without a token - the backend responds with the Local Admin user, automatically logging you in. |
| Login Page | You will still briefly see the login page on first load, but the auto-login fires immediately and redirects you to the projects dashboard. |
Start the stack with the published Docker Hub app image and leave Google/JWT variables empty:
git clone https://github.com/Butterski/homelab-builder.git
cd homelab-builder
cp .env.hosted.example .env
docker compose pull
docker compose up -dThat's it. Open http://localhost:3000 and you'll be automatically logged in as Local Admin.
The default docker-compose.yml pulls butterski/homelab-builder from Docker Hub and postgres:17 from Docker Hub. It only exposes the frontend port; the app container runs Nginx, the backend, and hlbIPAM together, with Postgres kept as a separate persistent database container.
Important: DB_HOST=postgres only resolves inside the Docker Compose network created by this compose file. The compose stack also provides homelab-builder-db as an alias for compatibility. If you run the app image by itself with docker run, Docker has no database hostname, and startup will fail with lookup ... no such host. In that case either use docker compose up -d, or put the app and database containers on the same user-defined Docker network and set DB_HOST to the database container name or external database hostname.
Use this when you want to run HLBuilder from published images only. This still uses Docker Compose because HLBuilder needs two containers: the app image and Postgres.
mkdir hlbuilder
cd hlbuilder
curl -fsSLO https://raw.githubusercontent.com/Butterski/homelab-builder/master/docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/Butterski/homelab-builder/master/.env.hosted.example -o .env
docker compose pull
docker compose up -ddocker compose pull should pull exactly these images:
butterski/homelab-builder:latest
postgres:17
Open http://localhost:3000.
Do not run only docker run butterski/homelab-builder:latest unless you also create a PostgreSQL container on the same Docker network. The app container expects DB_HOST=postgres, which is provided by the Compose service name.
Use this if you want HLBuilder running as a private local workspace on a Proxmox Docker LXC. This path pulls published Docker Hub images only; it does not build anything locally.
Use a Debian or Ubuntu LXC with Docker installed. A small instance is enough for testing, for example 2 CPU cores, 2 GB RAM, and 8 GB disk. For longer-term use, give the LXC more disk because Postgres data is stored in the postgres_data Docker volume.
Inside the LXC:
mkdir -p ~/homelab-builder
cd ~/homelab-builder
curl -fsSLO https://raw.githubusercontent.com/Butterski/homelab-builder/master/docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/Butterski/homelab-builder/master/.env.hosted.example -o .env
nano .env
docker compose pull
docker compose up -dFor local workspace mode, keep Google empty:
GIN_MODE=debug
GOOGLE_CLIENT_ID=
JWT_SECRET=Set DB_PASSWORD to something private if this LXC is not disposable. Leave DB_HOST=postgres; that name is created by Docker Compose.
Expected containers:
homelab-builder-app
homelab-builder-db
For local access, open http://LXC_IP:3000 from your browser. The app will use the built-in Local Admin workspace account.
You can confirm the mode is active by checking the backend logs on startup:
Starting HLBuilder Backend...
Database connected. Setting up routes...
There will be no panic or error about JWT_SECRET because the default Compose config sets GIN_MODE=debug for local self-hosting. The published one-image setup can run in local auth-disabled mode or hosted Google OAuth mode; set GOOGLE_CLIENT_ID and JWT_SECRET in .env for hosted mode.
| Variable | Where | Required for Auth-Disabled? | Description |
|---|---|---|---|
GOOGLE_CLIENT_ID |
Backend | No - leave unset | When empty, backend sets AuthDisabled=true and skips JWT validation on all protected routes. |
VITE_GOOGLE_CLIENT_ID |
Frontend (build arg) | No - leave unset | Only needed when rebuilding the frontend image with Google OAuth enabled. The published image defaults to local auth-disabled mode. |
JWT_SECRET |
Backend | No (unless GIN_MODE=release) |
Secret for signing JWTs. In auth-disabled mode JWTs are never issued, so this is unused. If running in release mode, set it to any random string. |
GIN_MODE |
Backend | No | Set to debug (or omit) to skip the JWT_SECRET strength check. Set to release for production with Google OAuth. |
When auth is disabled, the backend automatically creates (or reuses) a user with these properties:
| Field | Value |
|---|---|
[email protected] |
|
| Name | Local Admin |
| Google ID | local-auth-disabled |
| Avatar | DiceBear generated avatar |
This user is created on first request to any protected endpoint and persists in the database. All builds, selections, and preferences are stored under this single user. If you later enable Google OAuth, this user remains in the database but will no longer be auto-selected - you'll log in with your Google account instead.
In addition to auth-disabled mode, when the backend is not running in release mode (GIN_MODE != release), a development login endpoint is available:
POST /auth/dev
Content-Type: application/json
{ "email": "[email protected]" }
This creates (or logs into) a user with the given email - no Google account needed. It returns a JWT token you can use in Authorization: Bearer <token> headers. This is useful for:
- Testing multi-user scenarios locally
- Scripting / API access without a browser
- Frontend development with
api.devLogin("[email protected]")
Note: The
/auth/devendpoint is disabled whenGIN_MODE=releaseto prevent unauthorized access in production.
- Auth-disabled mode is intended for local / trusted network deployments only. Anyone who can reach your HLBuilder instance will have full admin access without any credentials.
- Do not expose an auth-disabled instance to the public internet. If you need external access, set up Google OAuth or put the instance behind a VPN / reverse proxy with its own authentication.
- The dev login endpoint (
/auth/dev) is also only available in non-release mode. It will not be exposed in production deployments.
git clone https://github.com/Butterski/homelab-builder.git
cd homelab-builder
cp .env.hosted.example .env
docker compose pull
docker compose up -d
# Open http://localhost:3000# Docker build from local source
docker compose -f deploy/docker/docker-compose.dev.yml up -d --build
# Backend (requires Go 1.24+)
cd backend
cp ../.env.example ../.env
go run ./cmd/server
# Frontend (requires Node 20+)
cd frontend
npm install
npm run devHLBuilder's custom 3-layer structural logo was designed and created by PaweΕ KrΔczewski.
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See the LICENSE file for details.


