This repository contains configuration files for self-hosting various services using Docker Compose and Kubernetes.
-
Clone the repository:
git clone https://github.com/sppidy/selfhost.git cd selfhost -
Set up environment variables:
cp .env.sample secrets.env nano secrets.env # Edit with your actual values -
Docker services (using Fish shell):
chmod +x run-docker.fish ./run-docker.fish traefik # Start with the reverse proxy ./run-docker.fish --all # Start all services
Alternative with Bash:
chmod +x run-docker.sh ./run-docker.sh traefik # Start with the reverse proxy ./run-docker.sh --all # Start all services
-
Kubernetes services (using Fish shell):
chmod +x apply-k8s.fish ./apply-k8s.fish --all # Deploy all servicesAlternative with Bash:
chmod +x apply-k8s.sh ./apply-k8s.sh --all # Deploy all services
For more detailed instructions, see the relevant sections below.
selfhost/
├── .env.sample # Sample environment variables
├── secrets.env # Actual secrets (gitignored)
├── apply-k8s.fish # Script to apply Kubernetes manifests with variables
├── apply-k8s.sh # Bash wrapper for apply-k8s.fish
├── run-docker.fish # Script to run Docker services with variables
├── run-docker.sh # Bash wrapper for run-docker.fish
├── cleanup-templates.fish # Script to clean up template files (if needed)
├── docker/ # Docker Compose configurations
└── kubernetes/ # Kubernetes manifest files
├── ansible/ # K3s installation playbooks
├── argocd/ # ArgoCD configuration
├── metal-lb/ # MetalLB configuration
├── nginx-for-traefik/ # Nginx configuration for Traefik
├── sppidy-website/ # Personal website deployment
└── vaultwarden/ # Password manager deployment
The docker/ directory contains Docker Compose configurations for various self-hosted services:
| Service | Description |
|---|---|
| Baikal | CalDAV and CardDAV server |
| DocMost | Document collaboration platform |
| Jenkins | CI/CD automation server |
| Navidrome | Music server and streaming |
| Registry | Docker image registry |
| Traefik | Edge router/reverse proxy |
| Wastebin | Pastebin alternative |
All Docker Compose files use environment variables to allow customization. You can use the provided run-docker.fish script to manage services:
# Make the script executable
chmod +x run-docker.fish
# Start a single service
./run-docker.fish traefik up
# Start all services
./run-docker.fish --all up
# View logs for a service
./run-docker.fish navidrome logs
# Restart a service
./run-docker.fish jenkins restart
# Stop a service
./run-docker.fish wastebin down
# See all available options
./run-docker.fish --helpEach service's configuration can be customized through environment variables defined in secrets.env. The script automatically loads these variables before running Docker Compose commands.
The kubernetes/ directory contains Kubernetes manifest files for deploying services:
| Service | Description |
|---|---|
| sppidy-website | Personal website |
| Vaultwarden | Self-hosted password manager |
| ArgoCD | GitOps continuous delivery |
| Component | Description | Configuration |
|---|---|---|
| MetalLB | Load balancer for bare metal Kubernetes | IP range configured via METALLB_IP_RANGE |
| Nginx for Traefik | Nginx configuration for Traefik integration | Directs traffic from Nginx to Traefik |
| ArgoCD | GitOps continuous delivery tool | Configured via templates using domain from DOMAIN |
These components are critical infrastructure elements that support the Kubernetes cluster:
- MetalLB: Provides an implementation of network load balancers for bare metal Kubernetes clusters
- Nginx for Traefik: Configures Nginx to work alongside Traefik for ingress traffic
- ArgoCD: Enables declarative, GitOps continuous delivery for Kubernetes
The repository includes Ansible playbooks for setting up a K3s Kubernetes cluster:
- Master node: Tailscale IP
100.122.87.2 - Worker nodes: Tailscale IPs
100.87.119.92and100.85.214.51
To set up the K3s cluster:
cd kubernetes/ansible
ansible-playbook -i inventory.ini install-k3s.ymlThis repository uses environment variables directly in Kubernetes YAML files:
- Each Kubernetes manifest includes placeholders like
${VARIABLE_NAME}that get replaced during deployment - Default values are specified using the pattern
${VARIABLE_NAME:-default_value} - The
apply-k8s.fishscript applies these manifests with environment variables fromsecrets.env
To deploy a service:
# Make sure you've created and filled out your secrets.env file
cp .env.sample secrets.env
nano secrets.env
# Make the deployment script executable
chmod +x apply-k8s.fish
# Deploy a specific service
./apply-k8s.fish sppidy-website
# Deploy all services
./apply-k8s.fish --all
# View available services
./apply-k8s.fish --helpThe environment variable system includes:
- Default values (e.g.,
${VARIABLE:-default_value}) - Namespace creation during deployment
- Diff display showing changes before applying
- Color-coded output for better readability
For manual deployment without the script:
# Process manifests with environment variables
source secrets.env
kubectl apply -f <(envsubst < kubernetes/sppidy-website/deployment.yaml)- All services are exposed through Traefik as the reverse proxy
- External network named
webis used for Docker services - Kubernetes ingress is configured to work with Traefik
- Services use Tailscale for secure networking between nodes
This repository uses environment variables for managing secrets and configuration:
.env.sample- Template file containing all required environment variablessecrets.env- Your actual secrets file (not committed to git)
# Copy the sample file to create your secrets file
cp .env.sample secrets.env
# Edit the secrets file with your actual values
nano secrets.envThe same environment variables are used for both Docker Compose and Kubernetes:
- Environment variables follow the naming convention related to the service:
SERVICE_PROPERTY - Default values are specified where possible:
${VARIABLE:-default} - Critical secrets like passwords have no defaults and must be provided
Example of using the same variables across platforms:
# In a Docker Compose file
services:
app:
image: ${SERVICE_IMAGE:-default/image:latest}
environment:
- DB_PASSWORD=${SERVICE_DB_PASSWORD}
# In a Kubernetes deployment
containers:
- image: ${SERVICE_IMAGE:-default/image:latest}
env:
- name: DB_PASSWORD
value: ${SERVICE_DB_PASSWORD}For different environments, you can maintain separate secrets files:
cp .env.sample secrets.env.production
cp .env.sample secrets.env.staging
cp .env.sample secrets.env.development
# To use a specific environment
source secrets.env.production
./run-docker.fish --allDocker Compose files use environment variables directly:
services:
app:
image: ${APP_IMAGE:-myapp:latest}
environment:
- DB_PASSWORD=${DB_PASSWORD}The run-docker.fish script automatically loads environment variables from secrets.env:
# Start a service with all environment variables loaded
./run-docker.fish registry up
# Manual approach without the script
source secrets.env
cd docker/registry
docker compose up -dFor Kubernetes deployments, environment variables are used directly in the YAML files:
# Example deployment.yaml
apiVersion: apps/v1
kind: Deployment
spec:
replicas: ${REPLICAS:-2}
template:
spec:
containers:
- image: ${DOCKER_REGISTRY}/myapp:${VERSION}The apply-k8s.fish script applies these manifests with environment variables:
# Use the apply-k8s.fish script
./apply-k8s.fish sppidy-website
# Manual approach with kubectl and envsubst
source secrets.env
kubectl apply -f <(envsubst < kubernetes/sppidy-website/deployment.yaml)Docker Compose files already reference environment variables:
services:
app:
image: myapp
environment:
- DB_PASSWORD=${DB_PASSWORD}Load the environment variables before running docker-compose:
source secrets.env
cd docker/<service-name>
docker compose up -dFor Kubernetes deployments, environment variables are used directly in the YAML files:
# Example deployment.yaml
apiVersion: apps/v1
kind: Deployment
spec:
replicas: ${REPLICAS:-2}
template:
spec:
containers:
- image: ${DOCKER_REGISTRY}/myapp:${VERSION}To apply these manifests with environment variables:
# Source your secrets.env file
source secrets.env
# Use the apply-k8s.fish script
./apply-k8s.fish <service-name>
# Or manually with kubectl and envsubst
kubectl apply -f <(envsubst < kubernetes/service-name/deployment.yaml)All services in this repository are configured using environment variables, providing a consistent approach to configuration across Docker and Kubernetes.
Variables follow these naming conventions:
- Service-specific variables are prefixed with the service name:
SERVICE_VARIABLE - General settings use descriptive names:
DOMAIN,DATA_PATH - Sensitive information has clear names:
SERVICE_PASSWORD,SERVICE_API_KEY
Environment variables are inserted using the ${VARIABLE} syntax:
image: ${SERVICE_IMAGE}Default values are provided using the ${VARIABLE:-default} syntax:
replicas: ${SERVICE_REPLICAS:-2}
image: ${SERVICE_IMAGE:-service:latest}Core variables used throughout the infrastructure:
| Variable | Description | Used By |
|---|---|---|
DOMAIN |
Primary domain name | All ingress/services |
DOCKER_REGISTRY |
Docker registry hostname | Kubernetes deployments |
*_VERSION |
Service version/tag | All services |
*_DOMAIN |
Service-specific domain | All web services |
*_PORT |
Service port | All services |
*_DATA_PATH |
Data storage location | All stateful services |
.env.sample: Template with all variables and documentationsecrets.env: Your actual configuration (gitignored)secrets.env.<environment>: Optional environment-specific configurations
- Docker: Use
./run-docker.fishwhich automatically sources variables - Kubernetes: Use
./apply-k8s.fishwhich handles variable substitution - Manual: Source the file with
source secrets.envbefore running commands
This repository follows consistent patterns for data persistence:
- Docker services store data in configurable paths (default:
/data/<service-name>/) - Data paths can be customized via environment variables (
SERVICE_DATA_PATH) - Volume mounts are used to persist data between container restarts
Example Docker Compose configuration:
services:
app:
volumes:
- ${APP_DATA_PATH:-/data/app}:/data- Kubernetes services use PersistentVolumeClaims for data storage
- PVC size is configurable via environment variables (
SERVICE_STORAGE) - Standard StorageClass is used for dynamic provisioning
Example PVC configuration:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: ${APP_STORAGE:-1Gi}- The Docker registry runs on port 5000 and is used for hosting Kubernetes container images
- Jenkins is configured with Docker, Maven, and ArgoCD CLI tools
- K3s is installed with Flannel using Tailscale network interface
This repository is for personal use and reference.
Spidy (sppidy)