Projects

Project 02 · Self-hosted infrastructure

Homelab

Not a hobby. A laboratory where I experiment with tools I later use or teach. 12 services running in production on my own server — no dependency on third-party services for any of these functions.

Docker · Traefik RTX 3070 · Ollama 12 containers 11 active subdomains Self-hosted

// why

The main reason

I needed an environment to test Ollama on real hardware before recommending local models to clients or teams. The GPU running the models is the same one powering CertEngine. 83 tok/s with Qwen 2.5 7B — compared to ~8 tok/s on CPU. That difference is what makes RAG a usable experience, not a slow demo.

The second reason: I don't want to depend on external services for critical functions in my workflow. Each homelab service replaces a paid subscription or a third party that has access to my data.

// architecture

How it connects

Internet
  └── CloudFlared Tunnel
        ├── n8n.ericmartinezf.dev        → n8n (directo)
        ├── ai.ericmartinezf.dev         → OpenWebUI (directo)
        ├── ericmartinezf.dev            → Landing page (directo)
        └── Traefik (router HTTP interno)
              ├── git.ericmartinezf.dev      → Gitea
              ├── notes.ericmartinezf.dev    → Outline
              ├── vault.ericmartinezf.dev    → Vaultwarden
              ├── status.ericmartinezf.dev   → Uptime Kuma
              ├── logs.ericmartinezf.dev     → Dozzle
              ├── docker.ericmartinezf.dev   → Dockge
              └── errors.ericmartinezf.dev   → GlitchTip

Ollama (stack_net interno — sin ruta externa)

Existing services (n8n, OpenWebUI, landing) are exposed directly via CloudFlared. Traefik acts as an internal router for new services — existing ones keep their direct route. Intentional architectural debt: paid off by migrating service by service when time allows.

// stack

The 12 services — and why each one

Service Why this one Why not the cloud alternative
Ollama + RTX 3070 Local inference at 83 tok/s with Qwen 2.5 7B. The same engine powering CertEngine. OpenAI/Anthropic API: variable cost, network latency, data leaves the server.
Gitea Private version control for projects I don't want on GitHub. GitHub/GitLab: private repositories on third-party servers.
Vaultwarden Bitwarden-compatible password management, self-hosted. 1Password/Bitwarden cloud: monthly subscription + credentials on external servers.
Outline Documentation with REST API and Google OAuth. Notion/Confluence: architecture notes on an external service.
GlitchTip Error tracking compatible with Sentry SDK. Sentry cloud: limited events on free plan + error data outside the server.
Uptime Kuma Monitoring of all 12 services with alerts. UptimeRobot: only verifies port response, not internal service state.
Traefik Reverse proxy with automatic detection via Docker labels. Manual nginx: static configuration for each new service.
n8n Workflow automation between homelab services. Zapier/Make: automation data on external servers.

CertEngine (cert.ericmartinezf.dev) is container 13 — an independent project using the same shared infrastructure (stack_postgres, stack_redis, stack_ollama).

// decisions

4 decisions with documented trade-offs

CloudFlared + Traefik coexisting, not Traefik replacing

Why

CloudFlared already exposed existing services. Replacing it would have required migrating each one with downtime risk. Traefik enters as an internal router for new services.

Trade-off

Two routing layers. Intentional technical debt paid off by migrating service by service.

Shared PostgreSQL only for new services

Why

Three separate instances would consume ~900MB RAM. One shared instance with separate schemas: ~300MB. Gitea, Outline, and GlitchTip share stack_postgres.

Trade-off

No permission isolation at DB level. Mitigated with dedicated Postgres users per schema.

Outline over Logseq

Why

Outline has a REST API, supports collaboration, and facilitates repo sync. Logseq is local-first with paid sync.

Trade-off

Outline requires PostgreSQL and Redis — dependencies that aren't free in terms of RAM.

pgvector/pg16 over postgres:16-alpine

Why

The official image doesn't include pgvector. The pgvector image has the extension pre-installed — no compiling it in the init script.

Trade-off

Heavier image. Worth it to have vector search available in any stack DB without extra steps.

The homelab is the foundation on which CertEngine runs.