commit 9357112dbe156489e3f9fbbeff81eca21ed25885 Author: Neale Pickett Date: Fri Dec 17 09:38:07 2021 -0700 Initial diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..b8a7fb0 --- /dev/null +++ b/deploy.sh @@ -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 diff --git a/gdrive-backup/backup.sh b/gdrive-backup/backup.sh new file mode 100755 index 0000000..fda7fdf --- /dev/null +++ b/gdrive-backup/backup.sh @@ -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 diff --git a/gdrive-backup/docker-compose.yaml b/gdrive-backup/docker-compose.yaml new file mode 100644 index 0000000..fbb9e10 --- /dev/null +++ b/gdrive-backup/docker-compose.yaml @@ -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 diff --git a/homelab/HOSTS b/homelab/HOSTS new file mode 100644 index 0000000..490e677 --- /dev/null +++ b/homelab/HOSTS @@ -0,0 +1 @@ +sweetums.woozle.org diff --git a/homelab/README.md b/homelab/README.md new file mode 100644 index 0000000..476a0db --- /dev/null +++ b/homelab/README.md @@ -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 + + diff --git a/homelab/docker-compose.yaml b/homelab/docker-compose.yaml new file mode 100644 index 0000000..9e27d7b --- /dev/null +++ b/homelab/docker-compose.yaml @@ -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 diff --git a/homelab/grafana.ini.tmpl b/homelab/grafana.ini.tmpl new file mode 100644 index 0000000..e4f559e --- /dev/null +++ b/homelab/grafana.ini.tmpl @@ -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 + diff --git a/homelab/periodic/backup-systemd b/homelab/periodic/backup-systemd new file mode 100755 index 0000000..b258588 --- /dev/null +++ b/homelab/periodic/backup-systemd @@ -0,0 +1,3 @@ +#! /bin/sh + +tar czf /mnt/ardenne/backups/sweetums.tar.gz /host/etc/systemd diff --git a/homelab/periodic/btrfs-scrub b/homelab/periodic/btrfs-scrub new file mode 100755 index 0000000..36913bb --- /dev/null +++ b/homelab/periodic/btrfs-scrub @@ -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 + diff --git a/homelab/periodic/ddns-update b/homelab/periodic/ddns-update new file mode 100755 index 0000000..abbb58c --- /dev/null +++ b/homelab/periodic/ddns-update @@ -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 diff --git a/homelab/periodic/gdrive-backup b/homelab/periodic/gdrive-backup new file mode 100755 index 0000000..fda7fdf --- /dev/null +++ b/homelab/periodic/gdrive-backup @@ -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 diff --git a/homelab/periodic/last-run b/homelab/periodic/last-run new file mode 100755 index 0000000..790e23f --- /dev/null +++ b/homelab/periodic/last-run @@ -0,0 +1,3 @@ +#! /bin/sh + +date > /mnt/ext/srv/periodic/last-run diff --git a/homelab/periodic/nextcloud-cron b/homelab/periodic/nextcloud-cron new file mode 100755 index 0000000..6b65374 --- /dev/null +++ b/homelab/periodic/nextcloud-cron @@ -0,0 +1,4 @@ +#! /bin/sh + +[ $(hostname) = sweetums ] || exit 0 +wget -O - https://drive.woozle.org/cron.php >/dev/null diff --git a/homelab/prometheus.yaml b/homelab/prometheus.yaml new file mode 100644 index 0000000..eba971e --- /dev/null +++ b/homelab/prometheus.yaml @@ -0,0 +1,7 @@ +global: + +scrape_configs: + - job_name: node_exporter + static_configs: + - targets: + - node-exporter:9100 diff --git a/melville/HOSTS b/melville/HOSTS new file mode 100644 index 0000000..006025f --- /dev/null +++ b/melville/HOSTS @@ -0,0 +1 @@ +melville.woozle.org diff --git a/melville/docker-compose.yaml b/melville/docker-compose.yaml new file mode 100644 index 0000000..fefaf05 --- /dev/null +++ b/melville/docker-compose.yaml @@ -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 diff --git a/melville/htaccess b/melville/htaccess new file mode 100644 index 0000000..af49f59 --- /dev/null +++ b/melville/htaccess @@ -0,0 +1 @@ +user:$apr1$tIOiVTs2$vDOzHYgsomLL5aCvAinUs1