So… what now?#
Since we already glossed over the hardware in the last post, the obvious question is:
what do you actually start with when you’re about to homelab?
There is no right answer here. Anyone telling you otherwise is either selling something or lying.
That said — if I had to pick a starting point, I’d argue that a Git solution is a pretty solid one.
Not because it’s flashy, but because once you have Git, a lot of other things start to make sense.
Gitea – the center of gravity#
For my setup, that role is filled by Gitea.
It’s self-hosted, boring in the best possible way, and quietly ends up being the glue between:
- documentation
- configuration
- automation
- and the occasional “this worked yesterday” moment
Gitea VM (Proxmox)#
Gitea runs on its own virtual machine in the Proxmox cluster.
Identity#
- VM ID: 100 - so actually the first VM on the cluster
- Name: git - yes boring 😄
- Proxmox node: node3
- Tag: prod
OS#
- Ubuntu
- SSH login: keys only (no password login)
Network#
- IPv4: 192.168.80.136 (eth0)
Resources#
- vCPU: 4
- RAM: 4 GB (observed usage ~88%)
- Disk: 50 GB (usage ~15% of 47.39 GB)
- Load: ~0.0
- Processes: ~153
Workloads#
This VM runs exactly two things, both in Docker:
- Gitea
- Gitea Actions runner “More on this later”
What Gitea is used for#
Purpose#
- Self-hosted Git service
- CI via Gitea Actions
- Container registry
In practice, this means:
- all site content lives here
- all automation starts here
- most “production” changes pass through here
If something breaks, there’s usually a commit for it.
Authentication & SSO#
Authentication is handled via Pocket-ID for SSO.
Details on this setup will come in a separate post.
The important parts:
- no local password sprawl
- consistent identity across services
Notifications#
Gitea sends commit and Actions updates to a dedicated Discord #logs channel.
It sounds noisy, but in practice it’s extremely useful. You notice broken pipelines immediately — even when you weren’t planning to.
Why start with Git?#
Because once Git is in place:
- documentation has a home
- configuration becomes history-aware
- automation stops being “that one script on that one server”
- rebuilding things becomes less scary
Everything else in the lab either feeds into Git — or is triggered by it.
Here are basic standard code, doc can be found here.
compose.yml
services:
server:
image: docker.gitea.com/gitea:1.24.6-rootless # i use verson spesific containers where i can
environment:
- GITEA__database__DB_TYPE=postgres #Change your designated passwords
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
restart: always
volumes:
- ./data:/var/lib/gitea
- ./config:/etc/gitea
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:2222"
depends_on:
- db
db:
image: docker.io/library/postgres:14
restart: always
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea
- POSTGRES_DB=gitea
volumes:
- ./postgres:/var/lib/postgresql/dataapp.ini
APP_NAME = Gitea: Git with a cup of tea
RUN_USER = git
RUN_MODE = prod
WORK_PATH = /var/lib/gitea
[repository]
ROOT = /var/lib/gitea/git/repositories
[repository.local]
LOCAL_COPY_PATH = /tmp/gitea/local-repo
[repository.upload]
TEMP_PATH = /tmp/gitea/uploads
[server]
APP_DATA_PATH = /var/lib/gitea
SSH_DOMAIN = gitea.your.LTD
HTTP_PORT = 3000
ROOT_URL = https://gitea.your.LTD/
DISABLE_SSH = false
; In rootless gitea container only internal ssh server is supported
START_SSH_SERVER = true
SSH_PORT = 2222
SSH_LISTEN_PORT = 2222
BUILTIN_SSH_SERVER_USER = git
LFS_START_SERVER = true
DOMAIN = git.skui.io
LFS_JWT_SECRET = W9_hmEXRS-pg_Ydhv8KnrfBM0-Otb0jF3cj3gtQtqjo
OFFLINE_MODE = true
[database]
PATH = /var/lib/gitea/data/gitea.db
DB_TYPE = postgres
HOST = db:5432
NAME = gitea
USER = gitea
PASSWD = gitea
SCHEMA =
SSL_MODE = disable
LOG_SQL = false
[session]
PROVIDER_CONFIG = /var/lib/gitea/data/sessions
PROVIDER = file
[picture]
AVATAR_UPLOAD_PATH = /var/lib/gitea/data/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /var/lib/gitea/data/repo-avatars
[attachment]
PATH = /var/lib/gitea/data/attachments
[log]
ROOT_PATH = /var/lib/gitea/data/log
MODE = console
LEVEL = info
[security]
INSTALL_LOCK = true
SECRET_KEY =
REVERSE_PROXY_LIMIT = 1
REVERSE_PROXY_TRUSTED_PROXIES = *
INTERNAL_TOKEN = Get#a#long#strong#one#here
PASSWORD_HASH_ALGO = pbkdf2
[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = [email protected]
[lfs]
PATH = /var/lib/gitea/git/lfs
[openid]
ENABLE_OPENID_SIGNIN = true
ENABLE_OPENID_SIGNUP = true
[cron.update_checker]
ENABLED = false
[repository.pull-request]
DEFAULT_MERGE_STYLE = merge
[repository.signing]
DEFAULT_TRUST_MODEL = committer
[oauth2]
JWT_SECRET = generate#a#safe#long#and#strong#one
[actions]
ENABLED=true # Action-runners
[packages]
ENABLED = true # needed to store docker imgNext up will probably be:
- how Gitea Actions build and deploy this site
- how Pocket-ID ties multiple services together
- or something that broke while I wasn’t paying attention
As usual.

