Skip to content
Open
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
149 changes: 42 additions & 107 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,122 +1,57 @@
# =============================================================================
# HomeLab Stack — Environment Configuration
# Copy this file to .env and fill in your values
# Run: cp .env.example .env && ./scripts/setup-env.sh
# Homelab Stack — Environment Configuration
# =============================================================================

# -----------------------------------------------------------------------------
# GENERAL
# -----------------------------------------------------------------------------
# ── General ──────────────────────────────────────────────────────────────────
DOMAIN=home.example.com
TZ=Asia/Shanghai
PUID=1000
PGID=1000
DOMAIN=yourdomain.com # Your base domain (e.g. home.example.com)
ACME_EMAIL=you@example.com # Let's Encrypt notification email
CN_MODE=false

# -----------------------------------------------------------------------------
# TRAEFIK
# -----------------------------------------------------------------------------
# ── Traefik (proxy) ────────────────────────────────────────────────────────────
ACME_EMAIL=admin@example.com
TRAEFIK_DASHBOARD_USER=admin
# Generate password hash: echo $(htpasswd -nb admin yourpassword) | sed -e s/\$/\$\$/g
TRAEFIK_DASHBOARD_PASSWORD_HASH=

# -----------------------------------------------------------------------------
# PORTAINER
# -----------------------------------------------------------------------------
# No config needed — admin password set on first login

# -----------------------------------------------------------------------------
# AUTHENTIK (SSO)
# -----------------------------------------------------------------------------
AUTHENTIK_SECRET_KEY= # REQUIRED: openssl rand -base64 32
AUTHENTIK_POSTGRES_PASSWORD= # REQUIRED: strong random password
AUTHENTIK_REDIS_PASSWORD= # REQUIRED: strong random password
AUTHENTIK_ADMIN_EMAIL=
AUTHENTIK_ADMIN_PASSWORD=
AUTHENTIK_DOMAIN=auth.${DOMAIN}

# OAuth2 clients — auto-filled by scripts/setup-authentik.sh
GRAFANA_OAUTH_CLIENT_ID=
GRAFANA_OAUTH_CLIENT_SECRET=
GITEA_OAUTH_CLIENT_ID=
GITEA_OAUTH_CLIENT_SECRET=
# ── Portainer ─────────────────────────────────────────────────────────────────
PORTAINER_ADMIN_PASSWORD=changeme

# ── Databases ────────────────────────────────────────────────────────────────
POSTGRES_ROOT_PASSWORD=changeme
REDIS_PASSWORD=changeme
MARIADB_ROOT_PASSWORD=changeme

# ── Productivity Stack ───────────────────────────────────────────────────────
GITEA_DB_PASSWORD=changeme
GITEA_OAUTH2_JWT_SECRET=changeme
VAULTWARDEN_ADMIN_TOKEN=changeme
VAULTWARDEN_DB_PASSWORD=changeme
OUTLINE_SECRET_KEY=changeme
OUTLINE_UTILS_SECRET=changeme
OUTLINE_DB_PASSWORD=changeme
OUTLINE_OAUTH_CLIENT_ID=
OUTLINE_OAUTH_CLIENT_SECRET=
PORTAINER_OAUTH_CLIENT_ID=
PORTAINER_OAUTH_CLIENT_SECRET=

# -----------------------------------------------------------------------------
# DATABASES (shared stack)
# -----------------------------------------------------------------------------
POSTGRES_PASSWORD= # REQUIRED: master postgres password
REDIS_PASSWORD= # REQUIRED
MARIADB_ROOT_PASSWORD= # REQUIRED
BOOKSTACK_APP_KEY=base64:changeme
BOOKSTACK_DB_PASSWORD=changeme
BOOKSTACK_AUTH_METHOD=standard
BOOKSTACK_OIDC_CLIENT_ID=
BOOKSTACK_OIDC_CLIENT_SECRET=

# Per-service database credentials
GITEA_DB_PASSWORD=
NEXTCLOUD_DB_PASSWORD=
OUTLINE_DB_PASSWORD=
AUTHENTIK_DB_PASSWORD=
# ── AI Stack ────────────────────────────────────────────────────────────────
WEBUI_SECRET_KEY=changeme

# -----------------------------------------------------------------------------
# GRAFANA
# -----------------------------------------------------------------------------
# ── Monitoring Stack ──────────────────────────────────────────────────────────
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD= # REQUIRED

# -----------------------------------------------------------------------------
# VAULTWARDEN
# -----------------------------------------------------------------------------
VAULTWARDEN_ADMIN_TOKEN= # REQUIRED: openssl rand -base64 48

# -----------------------------------------------------------------------------
# WIREGUARD
# -----------------------------------------------------------------------------
WG_HOST= # Your public IP or domain
WG_PASSWORD= # WireGuard Easy web UI password
WG_PORT=51820

# -----------------------------------------------------------------------------
# CLOUDFLARE DDNS
# -----------------------------------------------------------------------------
CF_API_TOKEN=
CF_ZONE_ID=
CF_RECORD_NAME=

# -----------------------------------------------------------------------------
# NEXTCLOUD
# -----------------------------------------------------------------------------
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD= # REQUIRED

# -----------------------------------------------------------------------------
# MEDIA STACK
# -----------------------------------------------------------------------------
MEDIA_ROOT=/opt/homelab/media # Host path for media files
DOWNLOADS_ROOT=/opt/homelab/downloads

# -----------------------------------------------------------------------------
# OLLAMA / AI
# -----------------------------------------------------------------------------
OLLAMA_GPU_ENABLED=false # Set to true if you have NVIDIA GPU

# -----------------------------------------------------------------------------
# NOTIFICATIONS
# -----------------------------------------------------------------------------
GOTIFY_PASSWORD= # REQUIRED
NTFY_AUTH_ENABLED=true
GRAFANA_ADMIN_PASSWORD=changeme
GRAFANA_OAUTH_CLIENT_ID=
GRAFANA_OAUTH_CLIENT_SECRET=

# -----------------------------------------------------------------------------
# NETWORK PROXY (optional — for CN users with local proxy)
# -----------------------------------------------------------------------------
HTTP_PROXY=
HTTPS_PROXY=
NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
DOCKER_PROXY_ENABLED=false
# ── Authentik (SSO) ─────────────────────────────────────────────────────────
AUTHENTIK_DOMAIN=sso.example.com
AUTHENTIK_SECRET_KEY=changeme
AUTHENTIK_ERROR_REPORTING=false
AUTHENTIK_POSTGRESQL__PASSWORD=changeme
AUTHENTIK_REDIS__PASSWORD=changeme

# -----------------------------------------------------------------------------
# CN MIRROR CONFIG (auto-set by setup-cn-mirrors.sh)
# -----------------------------------------------------------------------------
CN_MODE=false
CN_APT_MIRROR=https://mirrors.aliyun.com/ubuntu
CN_DOCKER_MIRROR=https://docker.m.daocloud.io
# ── Backup Stack ────────────────────────────────────────────────────────────
DUPLICATI_PASSWORD=changeme
RESTIC_PASSWORD=changeme
48 changes: 31 additions & 17 deletions config/alertmanager/alertmanager.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
global:
resolve_timeout: 5m
smtp_require_tls: false
smtp_smarthost: '${SMTP_HOST}:${SMTP_PORT}'
smtp_from: '${ALERTMANAGER_EMAIL_FROM}'
smtp_auth_username: '${ALERTMANAGER_EMAIL_USER}'
smtp_auth_password: '${ALERTMANAGER_EMAIL_PASS}'
smtp_require_tls: true

route:
group_by: [alertname, cluster]
receiver: 'default'
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
receiver: default
repeat_interval: 4h
group_by: ['alertname', 'cluster', 'service']
routes:
- match:
- receiver: 'critical'
match:
severity: critical
receiver: default
continue: true
repeat_interval: 1h
- receiver: 'default'
match:
severity: warning

receivers:
- name: default
# Uncomment and configure one of the following:
# webhook_configs:
# - url: http://gotify:80/message?token=YOUR_TOKEN
# slack_configs:
# - api_url: YOUR_SLACK_WEBHOOK
# channel: #alerts
- name: 'default'
email_configs:
- to: '${ALERTMANAGER_EMAIL_TO}'
webhook_configs:
- url: 'http://webhook:5000'
send_resolved: true
- name: 'critical'
email_configs:
- to: '${ALERTMANAGER_EMAIL_TO}'
headers:
subject: '[CRITICAL] {{ .GroupLabels.alertname }}'
webhook_configs:
- url: 'http://webhook:5000'
send_resolved: true

inhibit_rules:
- source_match:
severity: critical
severity: 'critical'
target_match:
severity: warning
equal: [alertname, instance]
severity: 'warning'
equal: ['alertname', 'instance']
9 changes: 9 additions & 0 deletions config/grafana/dashboards/node-exporter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"title": "Node Exporter Full",
"uid": "node-exporter-full",
"schemaVersion": 36,
"version": 1,
"panels": [],
"templating": {},
"time": {}
}
10 changes: 5 additions & 5 deletions config/grafana/provisioning/dashboards/dashboards.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Grafana dashboards provisioning
apiVersion: 1

providers:
- name: homelab
- name: Default
orgId: 1
folder: HomeLab
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 30
allowUiUpdates: true
editable: true
options:
path: /var/lib/grafana/dashboards
foldersFromFilesStructure: true
12 changes: 12 additions & 0 deletions config/grafana/provisioning/dashboards/default.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: 1

providers:
- name: 'Default'
orgId: 1
folder: ''
type: file
disableDeletion: true
editable: false
allowUiUpdates: false
options:
path: /var/lib/grafana/dashboards
14 changes: 10 additions & 4 deletions config/grafana/provisioning/datasources/datasources.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
# Grafana datasources provisioning
apiVersion: 1

datasources:
- name: Prometheus
type: prometheus
uid: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
jsonData:
timeInterval: 15s

- name: Loki
type: loki
uid: loki
access: proxy
url: http://loki:3100
editable: false
jsonData:
maxLines: 1000

- name: Tempo
type: tempo
access: proxy
url: http://tempo:3200
editable: false
10 changes: 10 additions & 0 deletions config/grafana/provisioning/datasources/loki.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: 1

datasources:
- name: Loki
type: loki
access: proxy
url: http://loki:3100
jsonData:
maxLines: 1000
editable: false
9 changes: 9 additions & 0 deletions config/grafana/provisioning/datasources/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: 1

datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
14 changes: 14 additions & 0 deletions config/grafana/provisioning/datasources/tempo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: 1

datasources:
- name: Tempo
type: tempo
access: proxy
url: http://tempo:3200
jsonData:
httpMethod: GET
serviceMap:
datasourceUid: Prometheus
nodeGraph:
enabled: true
editable: false
37 changes: 24 additions & 13 deletions config/loki/loki-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ auth_enabled: false

server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: warn
grpc_listen_port: 9095

common:
instance_addr: 127.0.0.1
path_prefix: /loki
storage:
filesystem:
Expand All @@ -17,26 +15,39 @@ common:
kvstore:
store: inmemory

query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100

schema_config:
configs:
- from: 2024-01-01
store: tsdb
store: boltdb-shipper
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h

table_manager:
retention_deletes_enabled: true
retention_period: 30d

limits_config:
allow_structured_metadata: false
volume_enabled: true
reject_old_samples: true
reject_old_samples_max_age: 168h

compactor:
working_directory: /loki/compactor
shared_store: filesystem
retention_enabled: true
retention_mark_version: 3

ruler:
alertmanager_url: http://alertmanager:9093
enable_alertmanager_v2: true
rule_path: /tmp/loki/rules
storage:
type: local
local:
directory: /loki/rules
ring:
kvstore:
store: inmemory
enable_api: true
Loading