Homelab Stack
Self-hosted infrastructure stack with GPU support, S3-compatible storage, Git server with container registry, CI/CD, and research tools.
Services
| Service | URL | Description |
|---|---|---|
| Gitea | http://gitea.home.fhirworx.io:3000 | Git server with LFS + container registry |
| Woodpecker CI | http://ci.home.fhirworx.io:8000 | CI/CD pipelines |
| RustFS | http://s3.home.fhirworx.io:9000 | S3-compatible object storage |
| RustFS Console | http://s3.home.fhirworx.io:9001 | Storage management UI |
| Notebooks | http://notebooks.home.fhirworx.io:2718 | GPU-accelerated Jupyter |
| Zotero | http://zotero.home.fhirworx.io:8080 | Reference manager with VNC |
| PostgreSQL | localhost:5432 | Database (Bitnami hardened) |
Prerequisites
- Docker with rootless mode
- NVIDIA GPU with container toolkit
- Fix for rootless NVIDIA containers:
sudo sed -i 's/#no-cgroups = false/no-cgroups = true/' /etc/nvidia-container-runtime/config.toml
DNS Setup
Add to /etc/hosts (replace with your server's LAN IP):
cat << 'EOF' | sudo tee -a /etc/hosts
# homelab stack
192.168.1.192 gitea.home.fhirworx.io
192.168.1.192 ci.home.fhirworx.io
192.168.1.192 s3.home.fhirworx.io
192.168.1.192 notebooks.home.fhirworx.io
192.168.1.192 zotero.home.fhirworx.io
EOF
Or configure these records on your router/DNS server.
Setup
1. Environment Variables
Create .env file:
POSTGRES_PASSWORD=<your_password>
RUSTFS_ACCESS_KEY=<your_access_key>
RUSTFS_SECRET_KEY=<your_secret_key>
GITEA_S3_ACCESS_KEY=<gitea_s3_user>
GITEA_S3_SECRET_KEY=<gitea_s3_password>
GITEA_DB_PASSWORD=<gitea_db_password>
GITEA_TOKEN=<gitea_api_token>
WOODPECKER_DB_PASSWORD=<woodpecker_db_password>
WOODPECKER_AGENT_SECRET=<generated_secret>
WOODPECKER_GITEA_CLIENT=<oauth_client_id>
WOODPECKER_GITEA_SECRET=<oauth_client_secret>
Generate agent secret:
openssl rand -hex 32
2. Start Core Services
docker compose up -d postgres rustfs
3. Configure RustFS
- Access console at http://s3.home.fhirworx.io:9001
- Create user
gitwith S3 credentials matchingGITEA_S3_ACCESS_KEYandGITEA_S3_SECRET_KEY - Create buckets:
gitea,gitea-lfs,gitea-packages - Apply IAM policy to
gituser:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:ListBucketMultipartUploads"
],
"Resource": [
"arn:aws:s3:::gitea",
"arn:aws:s3:::gitea-lfs",
"arn:aws:s3:::gitea-packages"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload"
],
"Resource": [
"arn:aws:s3:::gitea/*",
"arn:aws:s3:::gitea-lfs/*",
"arn:aws:s3:::gitea-packages/*"
]
}
]
}
4. Configure PostgreSQL
Create databases and users:
# Gitea database
docker exec -e PGPASSWORD=<postgres_password> postgres psql -U postgres -c "CREATE DATABASE gitea;"
docker exec -e PGPASSWORD=<postgres_password> postgres psql -U postgres -c "CREATE USER git WITH PASSWORD '<gitea_db_password>'; ALTER DATABASE gitea OWNER TO git;"
# Woodpecker database
docker exec -e PGPASSWORD=<postgres_password> postgres psql -U postgres -c "CREATE DATABASE woodpecker;"
docker exec -e PGPASSWORD=<postgres_password> postgres psql -U postgres -c "CREATE USER woodpecker WITH PASSWORD '<woodpecker_db_password>'; ALTER DATABASE woodpecker OWNER TO woodpecker;"
5. Start Gitea
docker compose up -d gitea
6. Configure Gitea
- Complete initial setup at http://gitea.home.fhirworx.io:3000
- Create organization
homelab - Create repository
stack - Generate API token for container registry access
- Create OAuth2 application for Woodpecker:
- Name:
Woodpecker CI - Redirect URI:
http://ci.home.fhirworx.io:8000/authorize - Copy Client ID and Secret to
.env
- Name:
7. Start Woodpecker CI
docker compose up -d woodpecker-server woodpecker-agent
Add secrets in Woodpecker UI (http://ci.home.fhirworx.io:8000):
registry_user- Gitea usernameregistry_pass- Gitea token
8. SSH and GPG Keys
Generate SSH key:
ssh-keygen -t ed25519 -C "user@homelab" -f ~/.ssh/gitea_ed25519 -N ""
Generate GPG key:
gpg --batch --gen-key <<EOF
Key-Type: eddsa
Key-Curve: ed25519
Key-Usage: sign
Subkey-Type: ecdh
Subkey-Curve: cv25519
Subkey-Usage: encrypt
Name-Real: <your_name>
Name-Email: <your_email>
Expire-Date: 2y
%no-protection
%commit
EOF
Configure Git:
git config --global user.name "<your_name>"
git config --global user.email "<your_email>"
git config --global user.signingkey <GPG_KEY_ID>
git config --global commit.gpgsign true
Add to ~/.ssh/config:
Host gitea
HostName gitea.home.fhirworx.io
Port 2222
User git
IdentityFile ~/.ssh/gitea_ed25519
IdentitiesOnly yes
Add host key:
ssh-keyscan -p 2222 gitea.home.fhirworx.io >> ~/.ssh/known_hosts
Add SSH and GPG public keys to Gitea: http://gitea.home.fhirworx.io:3000/user/settings/keys
9. Deploy Key (for CI/CD)
ssh-keygen -t ed25519 -C "deploy@homelab/stack" -f .deploy_key -N ""
Add .deploy_key.pub to repository deploy keys: http://gitea.home.fhirworx.io:3000/homelab/stack/settings/keys
10. Push to Gitea
git remote add gitea gitea:homelab/stack.git
git push -u gitea main
11. Container Registry
Login:
echo "<GITEA_TOKEN>" | docker login localhost:3000 -u <username> --password-stdin
Tag and push images:
docker tag <image>:latest localhost:3000/homelab/<image>:latest
docker push localhost:3000/homelab/<image>:latest
12. Start All Services
docker compose up -d
Container Registry Images
All images are hosted in the Gitea container registry:
localhost:3000/homelab/postgresql:latestlocalhost:3000/homelab/rustfs:latestlocalhost:3000/homelab/gitea:latest-rootlesslocalhost:3000/homelab/woodpecker-server:latestlocalhost:3000/homelab/woodpecker-agent:latestlocalhost:3000/homelab/notebooks:latestlocalhost:3000/homelab/zotero:latest
CI/CD Pipeline
The .woodpecker.yml pipeline:
- validate - Validates docker compose config
- build-notebooks - Builds notebooks image (on changes to
notebooks/) - build-zotero - Builds zotero image (on changes to
zotero/) - push-images - Pushes to container registry (on main branch)
- deploy - Pulls and restarts services (on main branch)
Endpoints
| Service | URL |
|---|---|
| Gitea Web | http://gitea.home.fhirworx.io:3000 |
| Gitea SSH | ssh://git@gitea.home.fhirworx.io:2222 |
| Container Registry | http://gitea.home.fhirworx.io:3000/v2/ |
| Woodpecker CI | http://ci.home.fhirworx.io:8000 |
| RustFS S3 API | http://s3.home.fhirworx.io:9000 |
| RustFS Console | http://s3.home.fhirworx.io:9001 |
| PostgreSQL | localhost:5432 |
| Notebooks | http://notebooks.home.fhirworx.io:2718 |
| Zotero | http://zotero.home.fhirworx.io:8080 |