Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions docker/guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# Docker Compose Architecture and Patterns

This document outlines the common architecture and patterns used in Docker Compose files for the homelab infrastructure.

## File Structure and Naming Conventions

Each Docker service is defined in its own YAML file with the following structure:

```yaml
---
name: service-name
services:
main-service:
image: vendor/image:tag
container_name: service-name
restart: unless-stopped
# other configuration...

# Optional supporting services
supporting-service:
# configuration...

networks:
proxy:
external: true
```

**Common Practices:**
- Service metadata at the top with comments for documentation
- Links to official sites, source repositories, and helpful guides
- Service-specific subdirectories for configuration files
- Consistent naming conventions for container names

## Core Infrastructure Components

### Networking

All services use a shared external `proxy` network for communication:

```yaml
networks:
proxy:
external: true
```

### Traefik Reverse Proxy

Traefik serves as the central reverse proxy for all services with the following features:

- HTTPS with Let's Encrypt automation via Cloudflare DNS
- HTTP to HTTPS redirection
- HTTP/3 support
- Access control via middleware chains
- Integration with Authelia for SSO
- Integration with CrowdSec for security
- Docker provider for automatic service discovery

#### Traefik Labels Pattern

Services expose themselves to Traefik using labels:

```yaml
labels:
traefik.enable: true
traefik.http.routers.service-name.rule: Host(`service.${MYDOMAIN}`)
traefik.http.routers.service-name.middlewares: middleware-name@file
traefik.http.services.service-name.loadbalancer.server.port: 8080
```

### Authentication & Security

#### Authelia SSO Integration

Services requiring authentication use Authelia middleware:

```yaml
traefik.http.routers.service-name.middlewares: localaccess-sso@file
```

#### Access Control Patterns

- `localaccess`: Restricts access to local networks only, default option
- `localaccess-sso`: Restricts access to local networks and requires authentication
- `publicaccess`: Available externally with CrowdSec protection

#### Cloudflare Tunnel

External access is provided securely via Cloudflare Tunnel, avoiding direct port exposure.

### Homepage Dashboard Integration

Services are integrated into the Homepage dashboard using labels:

```yaml
labels:
homepage.group: Category
homepage.name: Service Name
homepage.icon: icon-name.png
homepage.href: https://service.${MYDOMAIN}/
homepage.description: "Service description"
homepage.widget.type: widget-type # Optional
homepage.widget.url: https://service.${MYDOMAIN}/ # Optional
```

## Environment Variables Management

Environment variables are managed through `.env` files in a cascading priority:

1. Common environment variables: `config/docker/.env`
2. Host-specific variables: `config/docker/<hostname>/.env`
3. Service-specific variables: `config/docker/.env.<service-name>`
4. Host and service-specific variables: `config/docker/<hostname>/.env.<service-name>`

Common environment variables include:

- `MYDOMAIN`: Base domain for all services
- `TIMEZONE`: Timezone setting
- `DOCKER_VOLUMES`: Base path for persistent volumes
- Service-specific credentials and API keys

## Volume Management

Persistent data is stored in volumes following this pattern:

```yaml
volumes:
- ${DOCKER_VOLUMES}/service-name:/data # Volumes for data storage, not part of the repository
- ./service-name/config:/config # Local configuration files, committed to the repository
```

## Deployment Workflow

Services are deployed using the Taskfile system:

```
task docker:apply # Deploy all containers
task docker:update # Update and restart containers
task docker:pull # Pull latest container images
task docker:stop # Stop configured containers
```

Under the hood, these tasks use the `docker compose` command with the following pattern:

```bash
docker compose -f "$yaml_file" --env-file "$env_file" up --detach
```

## Service Categories

Services are organized into logical categories:

- **Security**: Traefik, Authelia, Cloudflared, CrowdSec, ...
- **Monitoring**: Prometheus, Grafana, Node-exporter, Uptime-kuma, ...
- **Media**: Jellyfin, Metube, Navidrome, Calibre, ...
- **Storage**: MinIO, Syncthing, FileSharing, ...
- **AI Tools**: Ollama, Open-WebUI, LiteLLM, AutogenStudio, ...
- **Tools**: Guacamole, Vaultwarden, SearXNG, ...

## Template for New Services

When creating a new service, use this template:

```yaml
# Brief description of the service
#
# 🏠 Home: https://service-homepage.com/
# 📜 Source: https://github.com/vendor/service
# Documentation: https://docs.service.com/
---
name: service-name
services:
service:
image: vendor/service:tag
container_name: service-name
restart: unless-stopped
environment:
TZ: ${TIMEZONE}
# Service-specific variables
volumes:
- ${DOCKER_VOLUMES}/service-name:/data
- ./service-name/config:/config # If needed
networks:
- proxy
labels:
traefik.enable: true
traefik.http.routers.service-name.rule: Host(`service.${MYDOMAIN}`)
traefik.http.routers.service-name.middlewares: middleware-name@file
traefik.http.services.service-name.loadbalancer.server.port: PORT
homepage.group: Category
homepage.name: Service Name
homepage.icon: service-icon.png
homepage.href: https://service.${MYDOMAIN}/
homepage.description: "Service description"

networks:
proxy:
external: true
```
2 changes: 1 addition & 1 deletion docker/tools/homelab-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name: homelab-docs
services:
homelab-docs:
image: docs.${MYDOMAIN}:latest
image: local/docs.${MYDOMAIN}:latest
container_name: homelab-docs
restart: unless-stopped
networks:
Expand Down
1 change: 1 addition & 0 deletions docs/learning.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Some good sources of learning materials and inspiration in the area of DevOps, H
| YouTube | [TechWorld with Nana](https://youtube.com/@TechWorldwithNana) | "Some topics covered: Docker, Kubernetes, CI/CD - GitLab CI, GitHub Actions, Jenkins, Python, Ansible, Prometheus Monitoring, Terraform, YAML" |
| YouTube | [Two Minute Papers](https://youtube.com/@TwoMinutePapers) | "What a time to be alive!" |
| YouTube | [David Shapiro](https://youtube.com/@DaveShap) | "Navigating the Fourth Industrial Revolution! The future is incredibly bright, but the journey is fraught with risks." |
| YouTube | [Cole Medin](https://www.youtube.com/@ColeMedin) | "I'm your guy for learning how to make a big impact with Artificial Intelligence. AI is no doubt the future of not just software development but the whole world." |
| Reddit | [r/selfhosted](https://www.reddit.com/r/selfhosted/) | "A place to share, discuss, discover, assist with, gain assistance for, and critique self-hosted alternatives to our favorite web apps, web services, and online tools." |
| Reddit | [r/homelab](https://www.reddit.com/r/homelab/) | "Welcome to your friendly /r/homelab, where techies and sysadmin from everywhere are welcome to share their labs, projects, builds, etc." |
| Reddit | [r/LocalLLaMA](https://www.reddit.com/r/LocalLLaMA/) | "Subreddit to discuss about Llama, the large language model created by Meta AI." |
4 changes: 2 additions & 2 deletions docs/runbooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Reinstall a Docker host

Note: This method is a bit unconventional but simplifies the deployment (and possible rollback) procedure a lot.
A new VM is used to deploy the OS, then the new system disk is attached to the old VM, which is already configured.
A new VM is used to deploy the OS, then the new system disk is attached to the old VM, which is already configured (MAC address, start at boot, start order, protection, USB devices...)

Hosts involved:
- `OLD`: perform on the old host
Expand All @@ -14,7 +14,7 @@ Steps:

- OLD: Install the new host using `proxmox/create-ubuntu-server-vm.sh`
- OLD: Apply ansible using `ansible/apply-homelab.sh`
- OLD: Transfer container images to save bandwidth (Optional, see: [Docker](docker))
- OLD: Transfer container images to save bandwidth (Optional, see: [Docker](../docker/README.md))

Optional: copy **Server Host Key**, an RSA, ED25519, or ECDSA private key

Expand Down
4 changes: 2 additions & 2 deletions docs/web/Taskfile.web.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ tasks:
- |
# build
SITE_DOMAIN=docs.${MYDOMAIN}
TAG=${SITE_DOMAIN}:collect
TAG=local/${SITE_DOMAIN}:collect
docker build -f docs/web/Dockerfile -t "${TAG}" --target collect --progress=plain --no-cache .
# export
site_container_id=$(docker create "${TAG}")
Expand All @@ -29,7 +29,7 @@ tasks:
- |
SITE_DOMAIN=docs.${MYDOMAIN}
HUGO_BASEURL=https://${SITE_DOMAIN}
TAG=${SITE_DOMAIN}:latest
TAG=local/${SITE_DOMAIN}:latest
docker build -f docs/web/Dockerfile -t "${TAG}" --build-arg HUGO_BASEURL="${HUGO_BASEURL}" .

export:
Expand Down