No description
  • Python 56%
  • Makefile 44%
Find a file
2026-04-14 09:33:04 +00:00
.env.example added transmute and ittools to the stack 2026-04-14 09:33:04 +00:00
.gitignore initial commit: homestack setup, services, tests 2026-04-07 08:19:42 +00:00
docker-compose.yml added transmute and ittools to the stack 2026-04-14 09:33:04 +00:00
LICENSE initial commit: homestack setup, services, tests 2026-04-07 08:19:42 +00:00
Makefile added transmute and ittools to the stack 2026-04-14 09:33:04 +00:00
README.md added transmute and ittools to the stack 2026-04-14 09:33:04 +00:00
test.py initial commit: homestack setup, services, tests 2026-04-07 08:19:42 +00:00

Poorman's Homestack

A lightweight self-hosted infrastructure stack managed via a single interactive make command. Runs entirely on Docker and is designed for low-end machines.

Includes databases, storage, a git server with CI runners, a local AI interface, and supporting services (more soon to come!! )— all on a single machine.

Goal

Minimal setup. Minimal overhead. Everything in one place.

Resource Usage (Idle)

  • CPU: <10% total
    • ~0.2 core on 2-core systems (~10%)
    • ~0.2 core on 4-core systems (~5%)
  • RAM: <2.5 GB total

Stack

Service Image Default Port Purpose
PostgreSQL postgres:17.4-alpine 9100 Relational database
MongoDB mongo:8.0.4 9101 Document database
Elasticsearch elasticsearch:8.17.0 9102 Search engine
MinIO minio/minio 9103 / 9104 S3-compatible object storage
Forgejo forgejo:14 9203 / 2222 Self-hosted Git + CI
Forgejo Runner forgejo/runner:9.0.3 CI job executor
Open WebUI open-webui:main 9202 Local AI chat interface (Ollama frontend)
File Browser filebrowser:v2.30.0 9200 Web-based file manager
Portainer portainer-ce:2.39.1 9201 Docker management UI
IT Tools corentinth/it-tools:latest 9204 Developer utility web interface
Transmute ghcr.io/transmute-app/transmute:latest 9205 Low-code AI automation platform

Prerequisites

Install these before anything else.

Docker

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in after this

Make

# Debian/Ubuntu
sudo apt install make

# Alpine
sudo apk add make

Gum

Gum powers the interactive CLI menu.

# Debian/Ubuntu
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg
echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list
sudo apt update && sudo apt install gum

# macOS
brew install gum

Ollama (optional)

Required only if you want Open WebUI to work. Install on the host machine (not in Docker):

curl -fsSL https://ollama.com/install.sh | sh
ollama pull llama3  # or any model you prefer

Setup

1. Clone the repo

git clone <repo-url> homestack
cd homestack

2. Create your .env file

cp .env.example .env

Open .env and fill in every value. Do not leave any value as the example default in production.

# PostgreSQL
POSTGRES_USER=mypostgresuser
POSTGRES_PASSWORD=mypostgrespassword
POSTGRES_DB=mypostgresdb
POSTGRES_PORT=9100

# MongoDB
MONGO_USER=mymongouser
MONGO_PASSWORD=mymongopassword
MONGO_DB=mymongodb
MONGO_PORT=9101

# Elasticsearch
ELASTIC_PASSWORD=myelasticpassword
ELASTIC_PORT=9102

# MinIO
MINIO_ROOT_USER=myminiouser
MINIO_ROOT_PASSWORD=myminiopassword
MINIO_API_PORT=9103
MINIO_CONSOLE_PORT=9104

# File Browser
FILEBROWSER_PORT=9200
FILEBROWSER_SRV=/srv
PUID=1000
PGID=1000

# Open WebUI
OPEN_WEBUI_PORT=9202
WEBUI_ADMIN_EMAIL=you@example.com

# Portainer
PORTAINER_PORT=9201
PORTAINER_ADMIN_PASSWORD_HASH=<bcrypt hash>

# ITTOOLS
ITTOOLS_PORT=9204

# TRANSMUTE
TRANSMUTE_PORT=9205

# Forgejo
FORGEJO_HTTP_PORT=9203
FORGEJO_SSH_PORT=2222
FORGEJO_DB_NAME=myforgejodb
FORGEJO_DB_USER=myforgejouser
FORGEJO_DB_PASSWORD=myforgejopassword
FORGEJO_DOMAIN=forgejo.yourdomain.com
FORGEJO_ADMIN_USER=youradminuser
FORGEJO_ADMIN_PASSWORD=yourpassword
FORGEJO_ADMIN_EMAIL=you@example.com

Important notes on .env:

  • Do not wrap values in quotes — the sourcing mechanism reads them literally and quotes become part of the value
  • Passwords with spaces work fine without quotes
  • PORTAINER_ADMIN_PASSWORD_HASH must be a bcrypt hash — generate with: docker run --rm httpd:2.4-alpine htpasswd -nbB admin yourpassword | cut -d: -f2
  • FORGEJO_DOMAIN is used for SSH clone URLs and the ROOT_URL — set it to your actual domain or your server's local hostname/IP

3. Start everything

make

Select Start services → all from the menu.


First Run: Forgejo Setup

When starting for the first time, Forgejo requires a one-time web UI setup:

  1. Open http://<your-server>:<FORGEJO_HTTP_PORT> in your browser
  2. The setup wizard will appear — the database fields will already be filled from your env vars, do not change them
  3. Fill in your admin account details — use the same username and password as FORGEJO_ADMIN_USER and FORGEJO_ADMIN_PASSWORD in your .env
  4. Click Install Forgejo
  5. Wait for the page to load (can take 3060 seconds on first boot)
  6. Log in to confirm it worked
  7. Go back to the terminal and confirm Yes when asked to register the runner

The runner registration fetches a token from the Forgejo API and registers the CI runner automatically. After this, ./data/forgejo-runner/.runner will exist and the runner daemon will start on all future boots without any manual steps.


Usage

make

The interactive menu offers:

  • Start services — start all or individual services
  • Stop services — stop all or individual services
  • Initialize services — re-run initialization (Forgejo DB + runner, MinIO)
  • View logs — tail logs for any service
  • Clean up — stop everything and delete all volumes (destructive)

Data & Volumes

Named volumes (managed by Docker, wiped on make clean)

  • postgres_data — PostgreSQL data
  • mongo_data — MongoDB data
  • esdata — Elasticsearch indices
  • minio_data — MinIO object storage
  • filebrowser_db — File Browser database
  • portainer_data — Portainer state
  • openwebui_data — Open WebUI data

Bind mounts (host directories, wiped on make clean)

  • ./data/forgejo — Forgejo repos, config, attachments
  • ./data/forgejo-runner — Runner registration state (.runner file)

make clean removes both named volumes and bind mount directories and recreates them with correct permissions.


Networking

All services run on a single Docker bridge network (172.20.0.0/16). Services communicate with each other using their container names as hostnames (e.g. Forgejo connects to Postgres at pg:5432).

No service is exposed to the internet by default — all ports are bound to 0.0.0.0 on the host. Put a reverse proxy (Caddy, Nginx, Traefik) in front if you want HTTPS or external access.


Diagnostics

Check what's running

docker ps

Tail logs for a specific service

make  # → View logs → select service
# or directly:
docker logs <container> -f --tail 50

Check a healthcheck

docker inspect <container> --format '{{.State.Health.Status}}'

Postgres — connect and inspect

docker exec -it pg psql -U <POSTGRES_USER> -d <POSTGRES_DB>
\du   # list users
\l    # list databases

Elasticsearch — cluster health

curl -u elastic:<ELASTIC_PASSWORD> http://localhost:9102/_cluster/health

MinIO — liveness

curl -f http://localhost:<MINIO_API_PORT>/minio/health/live && echo "OK"

MongoDB — ping

curl http://localhost:<MONGO_PORT>/
# Expected: "It looks like you are trying to access MongoDB over HTTP..."
# This means it is running correctly.

Forgejo runner not starting

docker logs forgejo-runner --tail 30

If you see connection refused to Forgejo — the runner registered before Forgejo was ready. Re-run:

make init-forgejo-runner

If you see permission denied writing .runner:

sudo chown -R 1000:1000 ./data/forgejo-runner
make init-forgejo-runner

Common Issues

Forgejo goes straight to login instead of setup wizard The ./data/forgejo directory has data from a previous run. Wipe it:

make clean

Forgejo shows a ROOT_URL warning You are accessing Forgejo via a different URL than FORGEJO_DOMAIN. This is cosmetic if you are accessing locally — it will not break core functionality. Set FORGEJO_DOMAIN to your server's local hostname or IP if you are not using a public domain.

Runner crash-loops with connection refused Forgejo was not fully up when the runner tried to connect. The depends_on healthcheck should prevent this, but if it happens:

docker restart forgejo-runner

make clean fails with permission denied Forgejo creates root-owned files inside ./data/forgejo. The Makefile handles this with sudo rm -rf — if it still fails, run manually:

sudo rm -rf ./data/forgejo ./data/forgejo-runner

Elasticsearch stays YELLOW Normal during startup while shards are being allocated. It resolves to GREEN within 3060 seconds. Only investigate if it stays YELLOW after 2 minutes:

curl -u elastic:<ELASTIC_PASSWORD> http://localhost:9102/_cluster/health?pretty

MongoDB deprecated parameter warnings in logs These are warnings about config parameter names that will be removed in a future MongoDB version. They do not affect functionality. Update the parameter names in your MongoDB config when you have time.

MongoDB swappiness warning MongoDB recommends setting vm.swappiness to 0 or 1 on the host:

sudo sysctl vm.swappiness=1
# To persist across reboots:
echo 'vm.swappiness=1' | sudo tee -a /etc/sysctl.conf

Things Not To Do

  • Do not run docker compose up -d directly — always use make. The Makefile handles initialization order, database setup, and runner registration that docker compose alone does not.
  • Do not delete ./data/forgejo-runner/.runner manually while the stack is running — the runner will lose its registration and crash-loop.
  • Do not change FORGEJO_DOMAIN after the first run without also updating the Forgejo app.ini inside ./data/forgejo/gitea/conf/app.ini — the two must match.
  • Do not wrap .env values in quotes — they are sourced directly by the shell and quotes become part of the value.
  • Do not expose Elasticsearch or MongoDB ports publicly without authentication configured — both have no network-level auth by default beyond what the application layer provides.

Resetting Everything

This is fully destructive — all data will be lost:

make clean

To start fresh after a clean:

make
# → Start services → all
# → Complete Forgejo web UI setup in browser
# → Confirm runner registration in terminal