Skip to main content

What now?

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/data

app.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 img

Next 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.

Steffen Skui
Author
Steffen Skui
Working in IT in the private sector, spending free time on automation, self-hosted services, and small homelab experiments. Father of two.