Initial
This commit is contained in:
commit
9357112dbe
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
sweetums.woozle.org
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#! /bin/sh
|
||||
|
||||
tar czf /mnt/ardenne/backups/sweetums.tar.gz /host/etc/systemd
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
#! /bin/sh
|
||||
|
||||
date > /mnt/ext/srv/periodic/last-run
|
|
@ -0,0 +1,4 @@
|
|||
#! /bin/sh
|
||||
|
||||
[ $(hostname) = sweetums ] || exit 0
|
||||
wget -O - https://drive.woozle.org/cron.php >/dev/null
|
|
@ -0,0 +1,7 @@
|
|||
global:
|
||||
|
||||
scrape_configs:
|
||||
- job_name: node_exporter
|
||||
static_configs:
|
||||
- targets:
|
||||
- node-exporter:9100
|
|
@ -0,0 +1 @@
|
|||
melville.woozle.org
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
user:$apr1$tIOiVTs2$vDOzHYgsomLL5aCvAinUs1
|
Loading…
Reference in New Issue