This commit is contained in:
Neale Pickett 2021-12-17 09:38:07 -07:00
commit 9357112dbe
17 changed files with 349 additions and 0 deletions

8
deploy.sh Executable file
View File

@ -0,0 +1,8 @@
#! /bin/sh
stack=$(basename $(pwd))
cat HOSTS | while read host; do
echo "=== $host"
HOSTNAME=$host docker -H ssh://$host stack deploy -c docker-compose.yaml --prune $stack
done

11
gdrive-backup/backup.sh Executable file
View File

@ -0,0 +1,11 @@
#! /bin/sh -e
for user in neale amy ginnie; do
dir=/mnt/ext/backups/$user
rclone \
--config=$dir/rclone.conf \
--bwlimit=2M \
--transfers=1 \
sync gdrive: $dir/gdrive
chown -R $(stat -c %u:%g $dir) $dir
done

View File

@ -0,0 +1,17 @@
version: "3.8"
services:
cron:
image: rclone/rclone
configs:
- source: backup.sh
target: /etc/periodic/daily/gdrive-backup
volumes:
- type: bind
source: /mnt/
target: /mnt/
entrypoint: [ "/usr/sbin/crond", "-fd", "8" ]
configs:
backup.sh:
file: backup.sh
name: backup.sh-v1

1
homelab/HOSTS Normal file
View File

@ -0,0 +1 @@
sweetums.woozle.org

14
homelab/README.md Normal file
View File

@ -0,0 +1,14 @@
# Authentication
Grafana is exposed to the world. Let's hope that's safe.
Its auth has this nice property that if you send basic-auth creds,
it'll use that instead of presenting a login screen.
Things using basic authentication:
* traefik dashboard
Things using traefik forward-authentication to grafana (you have to log in to grafana first):
* prometheus
* transmission

137
homelab/docker-compose.yaml Normal file
View File

@ -0,0 +1,137 @@
version: "3.8"
services:
traefik:
image: traefik
environment:
TRAEFIK_API: "true"
TRAEFIK_API_INSECURE: "true"
TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: :80
TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_TO: websecure
TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_SCHEME: https
TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS: :443
TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_TLS_CERTRESOLVER: letsencrypt
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCYRPT_ACME_EMAIL: neale@woozle.org
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_STORAGE: /acme.json
XXX_TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE_ENTRYPOINT: web
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_TLSCHALLENGE: "true"
TRAEFIK_PROVIDERS_DOCKER_SWARMMODE: "true"
TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: "false"
ports:
- target: 443
published: 443
mode: host
- target: 80
published: 80
mode: host
volumes:
- type: bind
source: /var/run/docker.sock
target: /var/run/docker.sock
read_only: true
- type: bind
source: /mnt/ext/srv/traefik/acme.json
target: /acme.json
secrets:
- htaccess
deploy:
labels:
traefik.enable: "true"
# XXX: This HSTS stuff doesn't seem to be working
traefik.frontend.headers.STSSeconds: "31536000"
traefik.frontend.headers.STSPreload: "true"
traefik.http.routers.dashboard.rule: "Host(`$HOSTNAME`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
traefik.http.routers.dashboard.tls.certresolver: letsencrypt
traefik.http.routers.dashboard.middlewares: forward-auth
traefik.http.routers.dashboard.service: api@internal
traefik.http.middlewares.basic-auth.basicauth.usersfile: /run/secrets/htaccess
traefik.http.middlewares.forward-auth.forwardauth.address: http://simpleauth:8080/
traefik.http.services.traefik.loadbalancer.server.port: "1"
simpleauth:
image: ghcr.io/nealey/simpleauth
secrets:
- password
deploy:
labels:
traefik.enable: "true"
traefik.http.routers.simpleauth.rule: "PathPrefix(`/`)"
traefik.http.services.simpleauth.loadbalancer.server.port: "8080"
plex:
image: ghcr.io/linuxserver/plex:1.25.1
networks:
- hostnet
environment:
TZ: US/Mountain
volumes:
- type: bind
source: /mnt/ext/srv/plex
target: /config
- type: bind
source: /media
target: /media
bind:
propagation: rslave
transmission:
image: ghcr.io/linuxserver/transmission
networks:
- hostnet
volumes:
- type: bind
source: /mnt/ext/srv/transmission
target: /config
- type: bind
source: /mnt/ext/torrents
target: /mnt/ext/torrents
deploy:
labels:
traefik.enable: "true"
traefik.http.routers.transmission.rule: "PathPrefix(`/transmission`)"
traefik.http.routers.transmission.tls: "true"
traefik.http.routers.transmission.middlewares: forward-auth
traefik.http.services.transmission.loadbalancer.server.port: "9091"
nextcloud:
image: ghcr.io/linuxserver/nextcloud:23.0.0
environment:
OVERWRITEPROTOCOL: https
volumes:
- type: bind
source: /mnt/ext/srv/nextcloud
target: /config
- type: bind
source: /mnt/ext/storage
target: /data
- type: bind
source: /mnt/ext
target: /mnt/ext
read_only: true
bind:
propagation: rslave
deploy:
labels:
traefik.enable: "true"
traefik.http.routers.nextcloud.rule: "Host(`drive.woozle.org`) || PathPrefix(`/nextcloud`)"
traefik.http.routers.nextcloud.tls: "true"
traefik.http.routers.nextcloud.tls.certresolver: letsencrypt
traefik.http.routers.nextcloud.middlewares: nextcloud-caldav@docker
traefik.http.middlewares.nextcloud-caldav.redirectregex.permanent: "true"
traefik.http.middlewares.nextcloud-caldav.redirectregex.regex: ^https://(.*)/.well-known/(card|cal)dav
traefik.http.middlewares.nextcloud-caldav.redirectregex.replacement: https://$${1}/remote.php/dav/
traefik.http.services.nextcloud.loadbalancer.server.port: "80"
redis:
image: redis
volumes:
- type: bind
source: /mnt/ext/srv/redis
target: /var/lib/redis
secrets:
htaccess:
file: htaccess
name: htaccess-v3
password:
file: password
name: password-v1
networks:
hostnet:
external: true
name: host

10
homelab/grafana.ini.tmpl Normal file
View File

@ -0,0 +1,10 @@
[server]
domain = {{.Node.Hostname}}
root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/
serve_from_sub_path = true
[auth.anonymous]
enabled = false
org_name = Main Org.
org_role = Viewer

View File

@ -0,0 +1,3 @@
#! /bin/sh
tar czf /mnt/ardenne/backups/sweetums.tar.gz /host/etc/systemd

9
homelab/periodic/btrfs-scrub Executable file
View File

@ -0,0 +1,9 @@
#! /bin/sh
# We do this on the host's cron now
exit 0
for mnt in /mnt/ardenne; do
chroot /host /usr/bin/btrfs scrub start -B $mnt
done

38
homelab/periodic/ddns-update Executable file
View File

@ -0,0 +1,38 @@
#! /bin/sh
domain=woozle.org
host=sweetums
key=6SRjTBJG7v2bHyG9gqX913w1
log() {
echo "=== $*"
}
json() {
ip4=$1
ip6=$2
printf '{"items": ['
if [ -n "$ip6" ]; then
printf '{"rrset_type":"AAAA","rrset_values":["%s"],"rrset_ttl":300},' "$ip6"
fi
printf '{"rrset_type":"A","rrset_values":["%s"],"rrset_ttl":300}' "$ip4"
printf ']}'
}
push() {
host=$1
domain=$2
authh="Authorization: Apikey $key"
log "$host.$domain"
curl -s -H "$authh" -T - https://api.gandi.net/v5/livedns/domains/$domain/records/$host
echo
}
me4=$(curl -s -4 https://api64.ipify.org/)
me6=$(curl -s -6 https://api64.ipify.org/)
log "IPv4: $me4"
log "IPv6: $me6"
json $me4 $me6 | push sweetums woozle.org
json $me4 | push drive woozle.org

11
homelab/periodic/gdrive-backup Executable file
View File

@ -0,0 +1,11 @@
#! /bin/sh -e
for user in neale amy ginnie; do
dir=/mnt/ext/backups/$user
rclone \
--config=$dir/rclone.conf \
--bwlimit=2M \
--transfers=1 \
sync gdrive: $dir/gdrive
chown -R $(stat -c %u:%g $dir) $dir
done

3
homelab/periodic/last-run Executable file
View File

@ -0,0 +1,3 @@
#! /bin/sh
date > /mnt/ext/srv/periodic/last-run

View File

@ -0,0 +1,4 @@
#! /bin/sh
[ $(hostname) = sweetums ] || exit 0
wget -O - https://drive.woozle.org/cron.php >/dev/null

7
homelab/prometheus.yaml Normal file
View File

@ -0,0 +1,7 @@
global:
scrape_configs:
- job_name: node_exporter
static_configs:
- targets:
- node-exporter:9100

1
melville/HOSTS Normal file
View File

@ -0,0 +1 @@
melville.woozle.org

View File

@ -0,0 +1,74 @@
version: "3.8"
services:
traefik:
image: traefik
environment:
TRAEFIK_API: "true"
TRAEFIK_API_INSECURE: "true"
TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: :80
TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_TO: websecure
TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_SCHEME: https
TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS: :443
TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_TLS_CERTRESOLVER: letsencrypt
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCYRPT_ACME_EMAIL: neale@woozle.org
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_STORAGE: /acme.json
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE_ENTRYPOINT: web
TRAEFIK_PROVIDERS_DOCKER_SWARMMODE: "true"
TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: "false"
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
- target: 8080
published: 8080
volumes:
- type: bind
source: /var/run/docker.sock
target: /var/run/docker.sock
read_only: true
- type: bind
source: /srv/traefik/acme.json
target: /acme.json
secrets:
- htaccess
deploy:
labels:
traefik.enable: "true"
traefik.http.routers.dashboard.rule: "Host(`melville.woozle.org`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
traefik.http.routers.dashboard.tls.certresolver: letsencrypt
traefik.http.routers.dashboard.middlewares: auth
traefik.http.routers.dashboard.service: api@internal
traefik.http.middlewares.auth.basicauth.usersfile: /run/secrets/htaccess
traefik.http.services.traefik.loadbalancer.server.port: "1"
vail:
image: ghcr.io/nealey/vail:master
deploy:
labels:
traefik.enable: "true"
traefik.http.routers.vail.rule: "PathPrefix(`/vail`) || Host(`vail.woozle.org`)"
traefik.http.services.vail.loadbalancer.server.port: "8080"
chat:
image: ghcr.io/dirtbags/microchat
command:
- --redis=redis:6379
- --noauth
deploy:
labels:
traefik.enable: "true"
traefik.http.routers.chat.rule: "Host(`melville.woozle.org`) && PathPrefix(`/chat`)"
traefik.http.routers.chat.middlewares: chat-prefix
traefik.http.middlewares.chat-prefix.stripprefix.prefixes: "/chat"
traefik.http.services.chat.loadbalancer.server.port: "8080"
redis:
image: redis
secrets:
htaccess:
file: htaccess
name: htaccess-v1

1
melville/htaccess Normal file
View File

@ -0,0 +1 @@
user:$apr1$tIOiVTs2$vDOzHYgsomLL5aCvAinUs1