aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKumar Damani <me@kumardamani.net>2022-09-07 20:40:17 +0000
committerKumar Damani <me@kumardamani.net>2022-09-07 20:40:17 +0000
commitbbe10895d9df8dd7899bbd65575d5bf12e57f8c8 (patch)
tree244d2f1ad38320863fb60f695c88c97799be1171
parent4d34de2f5e757bfeae5738547aabb61d3d28a2f8 (diff)
parentc85806e3289b5e207d51d382f8dc75edad04404d (diff)
Merge branch 'alpine' into 'master'
switched to alpine initial commit See merge request kdam0/vps!2
-rw-r--r--README.md128
-rw-r--r--group_vars/all/vars.yaml45
-rw-r--r--group_vars/all/vault50
-rw-r--r--group_vars/all/vault.example36
-rw-r--r--hosts.example2
-rw-r--r--hosts.vault45
-rw-r--r--playbooks/deploy.yaml212
-rw-r--r--requirements.yml8
-rw-r--r--roles/bitwarden/tasks/main.yaml7
-rw-r--r--roles/ddclient/handlers/main.yaml2
-rw-r--r--roles/ddclient/tasks/main.yaml17
-rw-r--r--roles/media_downloader/defaults/main.yaml7
-rw-r--r--roles/media_downloader/handlers/main.yaml2
-rw-r--r--roles/media_downloader/tasks/main.yaml91
-rw-r--r--roles/monitoring/defaults/main.yaml17
-rw-r--r--roles/monitoring/files/zfs-exporter23
-rw-r--r--roles/monitoring/handlers/main.yaml7
-rw-r--r--roles/monitoring/tasks/blackbox.yaml21
-rw-r--r--roles/monitoring/tasks/main.yaml19
-rw-r--r--roles/monitoring/tasks/node.yaml23
-rw-r--r--roles/monitoring/tasks/prometheus.yaml23
-rw-r--r--roles/monitoring/tasks/zfs.yaml49
-rw-r--r--roles/monitoring/templates/blackbox.yml.j24
-rw-r--r--roles/monitoring/templates/prometheus.yml.j262
-rw-r--r--roles/nextcloud/tasks/main.yaml8
-rw-r--r--roles/nginx_docker/defaults/main.yaml7
-rw-r--r--roles/nginx_docker/handlers/main.yaml2
-rw-r--r--roles/nginx_docker/tasks/main.yaml43
-rw-r--r--roles/nginx_docker/templates/app.nginx.conf.j225
-rw-r--r--roles/nginx_docker/templates/http.nginx.conf.j224
-rw-r--r--roles/samba/tasks/main.yaml20
-rw-r--r--roles/samba/templates/smb.conf2
-rw-r--r--roles/transmission/defaults/main.yaml17
-rw-r--r--roles/transmission/handlers/main.yaml2
-rw-r--r--roles/transmission/tasks/main.yaml32
-rw-r--r--roles/website/tasks/main.yaml7
-rw-r--r--roles/wireguard/handlers/main.yaml5
-rw-r--r--roles/wireguard/tasks/main.yaml38
-rw-r--r--roles/wireguard/templates/wg0.conf.j27
39 files changed, 874 insertions, 265 deletions
diff --git a/README.md b/README.md
index 30329f8..a50d41a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# My VPS Setup
+# My Homelab Setup
**This is still very much un-stable, and very much a work-in-progress.**
@@ -9,17 +9,19 @@ So I decided to migrate *most* of my remote VPS to a self-hosted private server.
My requirements are as follows:
-| Status | Feature | Choice |
-| ------------------ | ------------------------------------------- | --------------------------------------- |
-| | Email | n/a |
-| :heavy_check_mark: | Hosting/Sharing files, calender, tasks etc. | [Nextcloud](https://nextcloud.com/) |
-| :heavy_check_mark: | Hosting misc. static websites | [Nginx](https://www.nginx.com/) |
-| :heavy_check_mark: | Media (pictures, tv, movies) Server | [Jellyfin](https://jellyfin.org/) |
-| :heavy_check_mark: | Meta Search Engine | [Searxng](https://docs.searxng.org/) |
-| :heavy_check_mark: | Music Server | [Navidrome](https://www.navidrome.org/) |
-| :heavy_check_mark: | Network accessible storage for media | [Samba](https://www.samba.org/) |
-| :heavy_check_mark: | Password Hosting/Share | [Bitwarden](https://bitwarden.com/) |
-| :heavy_check_mark: | VPN | [Wireguard](https://www.wireguard.com/) |
+| Status | Feature | Choice |
+| ------------------ | ------------------------------------------- | ------------------------------------------- |
+| | Email | n/a |
+| :heavy_check_mark: | Hosting/Sharing files, calender, tasks etc. | [Nextcloud](https://nextcloud.com/) |
+| :heavy_check_mark: | Hosting misc. static websites | [Nginx](https://www.nginx.com/) |
+| :heavy_check_mark: | Media (pictures, tv, movies) Server | [Jellyfin](https://jellyfin.org/) |
+| :heavy_check_mark: | Meta Search Engine | [Searxng](https://docs.searxng.org/) |
+| :heavy_check_mark: | Music Server | [Navidrome](https://www.navidrome.org/) |
+| :heavy_check_mark: | Network accessible storage for media | [Samba](https://www.samba.org/) |
+| :heavy_check_mark: | Password Hosting/Share | [Bitwarden](https://bitwarden.com/) |
+| :heavy_check_mark: | VPN | [Wireguard](https://www.wireguard.com/) |
+| :heavy_check_mark: | Torrents | [Transmission](https://transmissionbt.com/) |
+| :heavy_check_mark: | Media downloader | [Sonarr](https://github.com/Sonarr/Sonarr), [Radarr](https://github.com/Radarr/Radarr), [Prowlarr](https://github.com/Prowlarr/Prowlarr) |
> Consider items marked as :heavy_check_mark: above to be implemented in this repo.
> You may notice more [roles](./roles) than listed here. This is due to me trying other options for that feature, eg. "seafile" for file hosting. Feel free to use that instead.
@@ -36,8 +38,92 @@ Notice that this setup requires a very small VPS since we are just running a wir
There are many cheap VPS providers out there. I use Racknerd now. I have used Vultr previously. Both are good in-terms of technical support.
+## Pre-requisites
+
+### Equipment
+1. Raspberry Pi 4B (4GB).
+2. USB Hub with **with its own power source**.
+3. 2 X TiB external usb SSDs or HDDs for our network-attached-storage (NAS).
+4. (optional, but recommended) 1 external usb SSD or HDD as a backup drive.
+5. A very cheap VPS - I use Racknerd.
+
+### Base Image setup
+For numerous reasons, I have switched to using Alpine Linux `aarch64` as the base OS image.
+Going forward this repo will primarily be geared towards it.
+That being said, all existing roles will continue to work on Raspi OS (debian) based images as well.
+
+1. Follow instructions from [Alpine wiki](https://wiki.alpinelinux.org/wiki/Raspberry_Pi) to create a bootable SD card.
+2. During the `setup-alpine` process, select the **sys** mode for a persistent install.
+3. Reboot
+4.
+```bash
+/boot/usercfg.txt
+dtoverlay=gpio-fan,gpiopin=14,temp=70000
+
+# enable community packages in /etc/apk/repositories
+# enable http://dl-cdn.alpinelinux.org/alpine/edge/testing
+apk update
+apk upgrade
+apk add vim nnn htop bmon rsync py3-pip
+apk add wireguard-tools docker docker-compose certbot
+modprobe wireguard
+# add wireguard to /etc/modules #
+
+# docker stuff
+addgroup username docker
+rc-update add docker boot
+service docker start
+```
+5. Continue to the NAS Setup section.
+
+### NAS Setup
+As a minimum, I recommend setting up two of the external usb drives as a ZFS mirrored pool.
+This will allow you to lose up to one drive at a time, and still operate in a degraded state while you replace it.
+
+```bash
+# install zfs
+apk add udev zfs
+modprobe zfs
+# add zfs to /etc/modules #
+# verify install
+zfs --version
+rc-update add udev sysinit
+rc-update add udev-trigger sysinit
+
+# assuming your first drive is /dev/sda
+zpool create yourpool /dev/sda
+zpool export yourpool
+zpool import -d /dev/disk/by-id/usb-Samsung_PSSD_T7_Shield_S6SMNS0T701007V-0:0-part1 yourpool -N
+zfs set mountpoint=/mnt/yourpool yourpool
+# create datasets
+zfs create yourpool/media
+zfs create yourpool/data
+# for encrypted datasets
+zfs create -o encryption=on -o keylocation=prompt -o keyformat=passphrase yourpool/priv
+# add the second drive to the pool
+zpool attach yourpool usb-Samsung_PSSD_T7_Shield_S6SMNS0T701007V-0:0 usb-Samsung_PSSD_T7_S5T3NJ0N907662T-0:0
+
+# zfs useful cmds
+zpool scrub yourpool
+zpool status -v yourpool
+zfs get mountpoint
+zfs mount -l yourpool/data
+zfs mount -l yourpool/media
+zfs mount -l yourpool/priv # will prompt for passphrase
+```
+
+At the end of this, you should at least have `/mnt/yourpool/media` and `/mnt/yourpool/data`.
+These will be auto mounted at boot.
+These are the volumes assumed by our Ansible playbooks as `vol_media`, and `vol_data` - see the hosts file.
+
## Monitoring
-![Dashboard](https://grafana.com/api/dashboards/15980/images/11892/image)
+I'd like to monitor the following:
+- Basic cpu, mem, disk metrics.
+- Service level metrics with alerts when a service is down.
+- ZFS metrics.
+- CPU temp, Power consumption etc.
+
+![Dashboard](https://grafana.com/api/dashboards/15980/images/12694/image)
You can get this dashboard [here](https://grafana.com/grafana/dashboards/15980).
## Install
@@ -106,7 +192,17 @@ deploy-job:
```
> You need to have the vars `VAULT_PASS`, and `SSH_PRIVATE_KEY` set in the CI/CD settings for each such repo.
+## Example backup script
+```bash
+#!/bin/sh
+
+doas mkdir -p /mnt/backup
+doas chown -R 1000:1000 /mnt/backup
+rsync -avph --info=progress2 /mnt/kdpool/media/media /mnt/backup/
+rsync -avph --info=progress2 /mnt/kdpool/media/pics /mnt/backup/
+rsync -avph --info=progress2 /mnt/kdpool/media/music /mnt/backup/
+```
+
## Future Plans
-1. Documentation for each role.
-2. Backups.
-3. Redundancy.
+1. Pi Hole (in progress).
+2. Better docs for each role.
diff --git a/group_vars/all/vars.yaml b/group_vars/all/vars.yaml
index 87c5503..4daa21d 100644
--- a/group_vars/all/vars.yaml
+++ b/group_vars/all/vars.yaml
@@ -3,28 +3,67 @@
# the wildcard domain under which all apps will be hosted.
apps_domain: 'kumardamani.net'
-# defines the confs for each app we are going to install.
+# list all the app configs you want to host here.
+# port: the host port that this service will be available on.
+# access_domain: external (nginx) domain.
+# Only include when applicable.
+# You should make sure that these subdomains have been created in your DNS settings.
+# status_endpoint: the http endpoint to check for service status.
+# curl_requires_auth: whether or not the http status check requires auth.
apps_conf_map:
nextcloud:
port: 31900
access_domain: 'files.{{ apps_domain }}'
+ status_endpoint: ''
+ curl_requires_auth: false
prometheus:
port: 9090
access_domain: 'metrics.{{ apps_domain }}'
+ status_endpoint: ''
+ curl_requires_auth: false
bitwarden:
port: 31901
access_domain: 'vault.{{ apps_domain }}'
+ status_endpoint: ''
+ curl_requires_auth: false
searxng:
port: 31902
access_domain: 'search.{{ apps_domain }}'
+ status_endpoint: ''
+ curl_requires_auth: false
+ transmission:
+ port: 31903
+ access_domain: 'torrents.{{ apps_domain }}'
+ status_endpoint: ''
+ curl_requires_auth: true
+ sonarr:
+ port: 31904
+ status_endpoint: '/system/status'
+ curl_requires_auth: false
+ radarr:
+ port: 31905
+ status_endpoint: '/system/status'
+ curl_requires_auth: false
+ prowlarr:
+ port: 31906
+ status_endpoint: '/system/status'
+ curl_requires_auth: false
+ bazarr:
+ port: 31907
+ status_endpoint: '/system/status'
+ curl_requires_auth: false
# list all static websites you plan to host here.
+# name: the root domain name of the static website.
+# git_url: the git repo from which to pull this site code from.
+# including the creds.
+# Only include when applicable.
+# git_version: the git branch to use for the pull.
+# Only include when applicable.
nginx_websites:
- name: 'kumardamani.net'
git_url: 'https://{{ (git_user|default(None)) | urlencode() }}:{{ (git_pass|default(None)) | urlencode() }}@gitlab.com/kdam0/kumardamani.net.git' # noqa yaml
git_version: 'main'
- name: 'amayastuff.com'
- git_url: 'https://{{ (git_user|default(None)) | urlencode() }}:{{ (git_pass|default(None)) | urlencode() }}@gitlab.com/kdam0/amayastuff.com.git' # noqa yaml
- git_version: 'main'
vpn_domain: 'kdvpn.crabdance.com'
diff --git a/group_vars/all/vault b/group_vars/all/vault
index 901350b..b7497af 100644
--- a/group_vars/all/vault
+++ b/group_vars/all/vault
@@ -1,24 +1,28 @@
$ANSIBLE_VAULT;1.1;AES256
-35303436363137363039306264356561303133613433613064356632356133616238353531623161
-3131336462653930623037323863383661616265623538660a373263303630646132306562646263
-66303365613431636166316434636461646363333433663031393930626362623337343037336332
-6630653062653039620a633838643166373337316235663363633665613336646534636564646165
-32643062343335313765323266303961366337663233353632333033303463633032623836343463
-38623062393666613331393465383761353235336539633739366333363739363938636561343861
-35346534393565663539353163316230643363343639653030623938353338346638326662373565
-31323736303232346534366536343465386337373636373436383966323732336636656331313631
-38613430666565393132306232626666373362656538306561333535323532666538373766373132
-63316131626232386465316433363239353965383734633366643330646130376263323163633466
-62666466636464666435373564666637343632373362376165626332663732643631323665623839
-63656637633032316264313562313937353265386561353665353161663830393865363834396337
-63666662663763666337656339396339343463643632363639386432356361313664306330366130
-31613734383238333335353863376162626634353839393565306561383764393930333038636538
-35363835616531366664666436616566303338623536366131616239323132393866366434653733
-65626338653866376636393437343132623936626432306134343664363362366666343337666635
-35323535616461323966333165396163383532303561343665393335343963353539376162616264
-31363962646461663834393666316164376533653064313466643364323236623961306432636336
-64653265393765383838646534623966313137356531346662623936643039663861666364396431
-64326339623238633138633166633565343032393863356534366636353362636331383833356334
-33346533643462643062363834313436633337363466643932636431333838343539663863626164
-36376536336465393063313136353831646132336437333366333034346635333837633431623538
-396433393039353238646666323730306166
+63336336613233616539616164616433666436353761376139336663613032323161616536336332
+3963653737353730383561343463623437353230376561350a633133373035393636363762643066
+30613830346231326161666661643065316439323632633434633836326136303339386236386561
+6462346562313464300a633266363066383138396333656338656432633465353365316635613337
+66336532643561363230346164343636663331333436383536653339306332343731386430636262
+33333638333565306331363866343763353434613230646631386234393762366236343633653431
+33613133623664646135616439616165366531303565616439326330646335326536396634316165
+63656431613766643434383565666262356261373937313961376538353037306236653730643564
+35613564393762366335303532366338393930613936383137363435633331323635383837663864
+32663866366131303263636162303837643161306433346433353361616263376265613934653934
+33336161626137343432633561313631396262626665356633343561636133386630323466383636
+34636434396464386265326638303730656166353663343561313737353130333635356337623639
+35373562613765346339303066323136386139326230633732653437623239386132376165386634
+32613162323931346238303334616137356264326663613362366664396162393033343664306663
+34656435316430373534646636653662303962396130323365643966666461613861343131656633
+32666432616238326338613862623638386338303030323365666237616162306133656136623633
+36343964656333663665373062386664626438303866643533303961346431376331373436376339
+31333131363762316563626164356236343862373533633839666133343337653237343730313965
+64333633336630653935636436323132643861666338613631323433353764306266326333653436
+30333661333834323262366464656166373066343035343335636332346561656463616266333866
+39383464343837656562666565393434663363316639323032333330383334616638393463653863
+37643162626335376666666336633339386434633532343765653334333033393830666630656633
+64383730666662363331663965656139336638343532663030343362623134376661313539313132
+30646437616134616538396464636361646435633130333137386332643931303234653738343531
+63363063333233376334326538393233366436353230613430326562643632313738356333383430
+61343262346531656537313965626532656664396139386331623362333538353561303465303466
+616362393632643064653731333335383438
diff --git a/group_vars/all/vault.example b/group_vars/all/vault.example
index 8dc5545..8ca22bf 100644
--- a/group_vars/all/vault.example
+++ b/group_vars/all/vault.example
@@ -1,16 +1,20 @@
-$ANSIBLE_VAULT;1.1;AES256
-33646338366162383266356237656436666231633439663936303263333261386436653331656330
-3666623261626263366232646631633763303363356239640a656165643764393864353137323037
-37343237306361633834366236353539376162373262373161656236616533323633376230666239
-6337306438373536650a373330386330346665643936393839626561383933363031626564343066
-64363335613139323735653230633262396533623065356439356533663631613033356635366163
-65613632623933313734643765373966633231633838306339323461653533386134653239623966
-37393133613836653232613130366535616435333130333332313832363636623066373635626561
-39313238353264336435313735646363326330613538613664363436323362363730663433363833
-61323535306665316664643231306665663665626331356330623265353062353262356661653137
-66643565653934626161326261373934323162386562303265393834393238373566313566383164
-35343438353363326439613462343237303735346134613061323531663534346531356465323964
-61353630373336333131353135623165633365323135383932326562653135633566346165623137
-33306266326238303130393332306463363866656239666130313665333466653631626564346534
-33393434366135633039363935383333363461333835333933346536396364636138356266623965
-373233303165616238303463666635396164
+---
+
+vault_wireguard_server_priv_key: ''
+
+vault_ddclient_user: ''
+vault_ddclient_password: ''
+
+vault_samba_user: ''
+vault_samba_password: ''
+
+vault_nextcloud_postgres_password: ''
+
+vault_git_user: ''
+vault_git_password: ''
+
+vault_searxng_secret_key: ''
+
+vault_transmission_user: ''
+vault_transmission_password: ''
+
diff --git a/hosts.example b/hosts.example
index 03562a3..8a213bf 100644
--- a/hosts.example
+++ b/hosts.example
@@ -2,4 +2,4 @@
some_host ansible_host=some_ip ansible_user=some_root_user
[compute]
-some_local_host ansible_host= ansible_user= data_vol_ssd="/ssd" data_vol_hdd="/hdd" ansible_ssh_pass=
+some_local_host ansible_host="" ansible_user="" vol_media="/mnt/pool/media" vol_data="/mnt/pool/data" ansible_ssh_pass=""
diff --git a/hosts.vault b/hosts.vault
index c1f6198..733881a 100644
--- a/hosts.vault
+++ b/hosts.vault
@@ -1,26 +1,21 @@
$ANSIBLE_VAULT;1.1;AES256
-62633833343239643262636634646532636164643635323561623232313335396439363537376230
-3762303334616432393964353037316230623039356361660a383135343237376465376133353037
-62313363363736393832313230393039353732346462356636346334373666666464386433363934
-6132316665373234350a306363376465376464653237383938396331643064376437366339356362
-30396166643262353431396462333933396235353933326231333966653939663562653362613361
-30616330613633616539373136663832376531313532303364326435393963626436353262623534
-61353064366538623138323735633036353532343631656431636166333132643938376163326631
-66383431373330316365666437343064306436373339303663356532326561623238636634353436
-38616133353234363838613032636133393062333761643934353935653638633863343562643165
-38663562623035316662636461353538616164643130646637316231383439383831666636663664
-36353337363833353931636637623636363332393738366664313963653635313238633338623963
-66313932656236346533633266646433626431643635616664336234313962656230353266663336
-34326266313139633137396265373062333766323065393232386663383439383630356330366238
-38333164613134303337643365616464306537313762393336386661363662333865643135393566
-62346339393439613633383263326264653162303437336336626330613664666462663931356363
-30346532616239303138616138396366626232666534313535333932393063636436656136393034
-34666335653735373334643766393333633562643766636335666264376661653733316630616332
-62353935643439383236363133386366383730373539323932323333303731316236366235383665
-34316432313866343465633463353462313162333939663938353762613037386666643033636436
-30656130363764333463626266393932656432333333316263636431333366633461636439666361
-36343537663833323431393838396237623831383533373763353135626632373165356232656662
-32663563613335313737393237353133323064663930346532396664313036386435316261643537
-38383262336538303830613166363765393431363265333861383031333733663363623135373764
-36373635393138306138323165356265316337363033643735646333613361393266323061333163
-6236
+32666131663031323831373462366236646535653566656665643161356238376163653366303164
+6663653136646161306536353839346530336662623437330a643333363830613066663763383562
+32326465623430373333663866346534323639313738373861626538633839373736663137656266
+3531346530613438610a643364323934303936323132366662376664323135346137343062646531
+63643830656536313363653262396234393236323732393164663433336638356239306362613137
+32323466663664373132643537633030323862396439633431636339346537383035373636356439
+61396664323730383631393930323364636138366661656436396336353433666433633530373865
+31343431303866333066653039323538656432633465373331353265336235626366363835313635
+33633333323236336563333237356565616633373433336637633964633932386437383139396335
+34613435653537396563313662376665346662663664633666643832393063666465626130333662
+33386530613366306265663132303365373530333734653731373262316533653365356130323632
+63313362303835323739376634653261613031326533373933393439363538643834643962643562
+65316237303837316138353934623366353533623961646139613131396530646261366563363635
+39623936653335366635316261346537363765393463656165656531316330323065643337346430
+30376239393538333461376230623363656530363534313333313830656364333833323839663134
+61626537366231653763663532663462643166333762356132336132646666373665343337346566
+36666565626164656431653130373531613637376433663131616161643332656130623066613336
+39663161323432373037623761346638336438636533303261356231383664323435386539336365
+34323730306561326438393435366134303730653135353161316665376261633131643935343633
+39313964633564383064
diff --git a/playbooks/deploy.yaml b/playbooks/deploy.yaml
index 270416d..53c315a 100644
--- a/playbooks/deploy.yaml
+++ b/playbooks/deploy.yaml
@@ -1,9 +1,9 @@
# Usage:
-# ansible-playbook -i hosts playbooks/deploy.yaml --vault-id vaultid --tags base
+# ansible-playbook -i hosts playbooks/deploy.yaml --vault-id vaultid --tags []
#
# Tags:
-# base, ddclient, wireguard, nginx, website, samba
-# nextcloud, monitoring (these all depend on the nginx tag)
+# ddclient, wireguard, nginx, websites, samba
+# nextcloud, bitwarden, searxng, monitoring (these all depend on the nginx tag)
#
# Install:
# git submodule update --remote --merge
@@ -14,17 +14,15 @@
# ansible-galaxy install -r requirements.yml
# ansible-galaxy collection install -r requirements.yml
#
-# Assumptions:
-# Run apt update, upgrade
-# Run rpi-update
-# HD, SSD formatted appropriately.
---
+## Non Docker Services ##
- hosts: compute
- gather_facts: false
+ gather_facts: true
tags: 'ddclient'
become: true
+ become_method: 'doas'
roles:
- role: ddclient
vars:
@@ -34,16 +32,17 @@
ddclient_domain: '{{ vpn_domain }}'
- hosts: compute
- gather_facts: false
+ gather_facts: true
tags: 'wireguard'
become: true
+ become_method: 'doas'
roles:
- role: wireguard
vars:
wireguard_server_priv_key: '{{ vault_wireguard_server_priv_key }}'
wireguard_server_pub_key: 'iwsriL3AUn4dgKfsSNgJtj/G808k4jXvSC+mM70YnAw='
wireguard_server_listen_port: 51820
- wireguard_server_ip: '192.168.10.1/24'
+ wireguard_server_ip: '192.168.10.1/32'
wireguard_peers:
- peer_ip: '192.168.10.2/32' # my phone
peer_key: '/mFv6y9QA8dhX/A9fFn+mzg/SZq4BZPeNofm1w754y8='
@@ -54,185 +53,112 @@
- hosts: compute
gather_facts: false
- tags: 'nginx'
+ tags: 'websites'
+ become: false
+ roles:
+ - role: website
+ vars:
+ websites: '{{ nginx_websites }}'
+ git_user: '{{ vault_git_user }}'
+ git_pass: '{{ vault_git_password }}'
+ sites_data_root: '{{ vol_data }}/sites'
+
+# Access: http://art-jr/data
+- hosts: compute
+ gather_facts: true
+ tags: 'samba'
become: true
+ become_method: 'doas'
roles:
- - role: nginx
+ - role: samba
vars:
- nginx_website_domains: '{{ ["default"] + (nginx_websites | map(attribute="name") | list) }}'
- nginx_global_apps_domain: '{{ apps_domain }}'
- nginx_apps_confs: '{{ apps_conf_map | dict2items(key_name="app", value_name="conf") }}'
+ samba_user: '{{ vault_samba_user }}'
+ samba_user_pass: '{{ vault_samba_password }}'
+ samba_data_root: '{{ vol_media }}'
+
+
+## Docker Services ##
- hosts: compute
gather_facts: false
- tags: 'website'
- become: true
+ tags: 'nginx'
+ become: false
roles:
- - role: website
+ - role: nginx_docker
vars:
- websites: '{{ nginx_websites }}'
- git_user: '{{ vault_git_user }}'
- git_pass: '{{ vault_git_password }}'
+ nginx_website_domains: '{{ ["default"] + (nginx_websites | map(attribute="name") | list) }}'
+ nginx_global_apps_domain: '{{ apps_domain }}'
+ nginx_apps_confs: '{{ apps_conf_map | dict2items(key_name="app", value_name="conf") }}'
+ nginx_conf_root: '{{ vol_data }}/nginx'
+ nginx_static_html_root: '{{ vol_data }}/sites'
+ nginx_certs_root: '{{ vol_data }}/letsencrypt'
- hosts: compute
gather_facts: false
tags: 'nextcloud'
- become: true
+ become: false
roles:
- role: nextcloud
vars:
nextcloud_domain: '{{ apps_conf_map["nextcloud"]["access_domain"] }}'
nextcloud_host_port: '{{ apps_conf_map["nextcloud"]["port"] }}'
- nextcloud_data_root: '{{ data_vol_hdd }}/nextcloud'
+ nextcloud_data_root: '{{ vol_data }}/nextcloud'
nextcloud_postgres_password: '{{ vault_nextcloud_postgres_password }}'
- hosts: compute
gather_facts: false
tags: 'searxng'
- become: true
+ become: false
roles:
- role: searxng
vars:
searxng_domain: '{{ apps_conf_map["searxng"]["access_domain"] }}'
searxng_host_port: '{{ apps_conf_map["searxng"]["port"] }}'
- searxng_data_root: '{{ data_vol_hdd }}/searxng'
+ searxng_data_root: '{{ vol_data }}/searxng'
searxng_secret_key: '{{ vault_searxng_secret_key }}'
- hosts: compute
gather_facts: false
tags: 'bitwarden'
- become: true
+ become: false
roles:
- role: bitwarden
vars:
bitwarden_host_port: '{{ apps_conf_map["bitwarden"]["port"] }}'
- bitwarden_data_dir: '{{ data_vol_hdd }}/bitwarden'
+ bitwarden_data_dir: '{{ vol_data }}/bitwarden'
-# Access: http://art-jr/data
- hosts: compute
gather_facts: false
- tags: 'samba'
- become: true
+ tags: 'transmission'
+ become: false
roles:
- - role: samba
+ - role: transmission
vars:
- samba_user: '{{ vault_samba_user }}'
- samba_user_pass: '{{ vault_samba_password }}'
+ transmission_host_port: '{{ apps_conf_map["transmission"]["port"] }}'
+ transmission_user: '{{ vault_transmission_user }}'
+ transmission_password: '{{ vault_transmission_password }}'
+ transmission_root_dir: '{{ vol_media }}/transmission'
- hosts: compute
- become: true
- tags: 'monitoring'
+ gather_facts: false
+ tags: 'media_downloader'
+ become: false
roles:
- - role: 'cloudalchemy.node_exporter'
+ - role: media_downloader
vars:
- node_exporter_version: '1.2.2'
- node_exporter_web_listen_address: '0.0.0.0:9100'
- node_exporter_web_telemetry_path: '/metrics'
-
- # monitor cpu temp. stats for the rpi.
- - role: 'rpi_exporter'
-
- - role: 'cloudalchemy.prometheus'
- vars:
- prometheus_version: 'latest'
- prometheus_skip_install: false
- prometheus_db_dir: '{{ data_vol_hdd }}/prometheus'
- prometheus_web_listen_address: '0.0.0.0:{{ apps_conf_map["prometheus"]["port"] }}'
- prometheus_web_external_url: 'https://{{ apps_conf_map["prometheus"]["access_domain"] }}'
- prometheus_storage_retention: '15d'
- prometheus_global:
- scrape_interval: '30s'
- evaluation_interval: '30s'
- prometheus_targets:
- node:
- - targets:
- - localhost:9100
- - localhost:9243
- labels:
- env: prod
- prometheus_scrape_configs:
- - job_name: "prometheus"
- metrics_path: "{{ prometheus_metrics_path }}"
- static_configs:
- - targets:
- - "{{ ansible_fqdn | default(ansible_host) | default('localhost') }}:9090"
- - job_name: "node"
- file_sd_configs:
- - files:
- - "{{ prometheus_config_dir }}/file_sd/node.yml"
- - job_name: 'blackbox'
- metrics_path: /probe
- params:
- module: [http_2xx]
- static_configs:
- # all apps, nginx websites, prefixed with "https://"
- - targets: '{{ ["https://"] | product((apps_conf_map | dict2items(key_name="app", value_name="conf") | map(attribute="conf") | map(attribute="access_domain") | list)+(nginx_websites | map(attribute="name") | list)) | map("join") | list }}' # noqa yaml
- relabel_configs:
- - source_labels: [__address__]
- target_label: __param_target
- - source_labels: [__param_target]
- target_label: instance
- - target_label: __address__
- replacement: 127.0.0.1:9115 # Blackbox exporter.
-
- - role: 'cloudalchemy.blackbox-exporter'
- vars:
- blackbox_exporter_web_listen_address: '0.0.0.0:9115'
+ media_downloader_sonarr_host_port: '{{ apps_conf_map["sonarr"]["port"] }}'
+ media_downloader_radarr_host_port: '{{ apps_conf_map["radarr"]["port"] }}'
+ media_downloader_prowlarr_host_port: '{{ apps_conf_map["prowlarr"]["port"] }}'
+ media_downloader_bazarr_host_port: '{{ apps_conf_map["bazarr"]["port"] }}'
+ media_downloader_transmission_root_dir: '{{ vol_media }}/transmission'
+ media_downloader_media_root_dir: '{{ vol_media }}/media'
- hosts: compute
- become: true
- tags: 'base'
+ gather_facts: true
+ tags: 'monitoring'
roles:
- - role: geerlingguy.pip
+ - role: 'monitoring'
vars:
- pip_package: python3-pip
- pip_install_packages:
- - name: docker
- - name: pexpect
-
- - role: geerlingguy.docker_arm
- vars:
- docker_install_recommends: true
- docker_install_compose: true
- docker_users:
- - pi
- docker_pip_executable: pip3
- docker_version_armv7: 5:20.10.10~3-0~raspbian-bullseye
-
- - role: geerlingguy.nfs
- vars:
- nfs_exports:
- - '{{ data_vol_ssd }} *(rw,sync,no_root_squash)'
- - '{{ data_vol_hdd }} *(rw,sync,no_root_squash)'
- pre_tasks:
- - name: 'Install quality of life packages are present'
- apt:
- name:
- - 'git'
- - 'net-tools'
- - 'neofetch'
- - 'neovim'
- - 'nnn'
- - 'nmap'
- update_cache: true
-
- - name: 'Ensure that mount for data vol exists'
- mount:
- state: 'mounted'
- path: '{{ item.vol_path }}'
- src: 'UUID="{{ item.vol_uuid }}"'
- boot: true
- fstype: '{{ item.vol_fstype }}'
- opts: 'rw,user,exec'
- loop:
- - vol_path: '{{ data_vol_ssd }}'
- vol_uuid: '734d1190-b222-4979-91c8-0582e030fd1a'
- vol_fstype: 'ext4'
- - vol_path: '{{ data_vol_hdd }}'
- vol_uuid: 'aa392d86-bc93-4ad4-9e9e-c1274384bbfb'
- vol_fstype: 'ext4'
-
- - name: 'Set python3 as default python'
- alternatives:
- name: 'python'
- path: '/bin/python3'
+ monitoring_root_dir: '{{ vol_data }}/monitoring'
+ monitoring_apps_confs: '{{ apps_conf_map | dict2items(key_name="app", value_name="conf") }}'
+ monitoring_static_sites: '{{ nginx_websites }}'
diff --git a/requirements.yml b/requirements.yml
index 8aca51c..7301eb1 100644
--- a/requirements.yml
+++ b/requirements.yml
@@ -2,11 +2,3 @@
collections:
- name: community.docker
-roles:
- - name: cloudalchemy.blackbox-exporter
- - name: cloudalchemy.node_exporter
- - name: cloudalchemy.prometheus
- - name: geerlingguy.certbot
- - name: geerlingguy.docker_arm
- - name: geerlingguy.pip
- - name: geerlingguy.nfs
diff --git a/roles/bitwarden/tasks/main.yaml b/roles/bitwarden/tasks/main.yaml
index 5fd0ed4..0fd7b86 100644
--- a/roles/bitwarden/tasks/main.yaml
+++ b/roles/bitwarden/tasks/main.yaml
@@ -1,11 +1,18 @@
---
+- name: 'Ensure bitwarden data dir exists'
+ file:
+ path: "{{ bitwarden_data_dir }}"
+ state: "directory"
+ mode: '755'
+
- name: 'Make sure the Vaultwarden container is created and running'
docker_container:
name: '{{ bitwarden_container_name }}'
image: 'vaultwarden/server'
pull: true
state: 'started'
+ recreate: true
env:
WEBSOCKET_ENABLED: 'true'
INVITATIONS_ALLOWED: 'true'
diff --git a/roles/ddclient/handlers/main.yaml b/roles/ddclient/handlers/main.yaml
index be19365..a2b6ea4 100644
--- a/roles/ddclient/handlers/main.yaml
+++ b/roles/ddclient/handlers/main.yaml
@@ -1,7 +1,7 @@
---
- name: 'Restart ddclient'
- systemd:
+ service:
name: 'ddclient'
state: 'restarted'
listen: 'restart ddclient'
diff --git a/roles/ddclient/tasks/main.yaml b/roles/ddclient/tasks/main.yaml
index 8deffc2..d780a3f 100644
--- a/roles/ddclient/tasks/main.yaml
+++ b/roles/ddclient/tasks/main.yaml
@@ -1,22 +1,29 @@
-# https://notthebe.ee/raspi.html
+# https://wiki.alpinelinux.org/wiki/Ddclient
---
-- name: 'Install required apt packages'
+- name: 'Install ddclient for Alpine'
+ apk:
+ name: 'ddclient'
+ state: 'latest'
+ when: 'ansible_os_family == "Alpine"'
+
+- name: 'Install ddclient for Debian'
apt:
name:
- 'ddclient'
state: 'present'
update_cache: true
+ when: 'ansible_os_family == "Debian"'
- name: 'Update ddclient conf'
template:
- dest: '/etc/ddclient.conf'
+ dest: '/etc/ddclient/ddclient.conf'
src: 'ddclient.conf.j2'
mode: '644'
notify: 'restart ddclient'
-- name: 'Start ddclient'
- systemd:
+- name: 'Start and enable ddclient'
+ service:
name: 'ddclient'
state: 'started'
enabled: true
diff --git a/roles/media_downloader/defaults/main.yaml b/roles/media_downloader/defaults/main.yaml
new file mode 100644
index 0000000..8fffe70
--- /dev/null
+++ b/roles/media_downloader/defaults/main.yaml
@@ -0,0 +1,7 @@
+# Default Values
+---
+
+media_downloader_uid: "1000"
+media_downloader_gid: "1000"
+media_downloader_tz: 'America/Toronto'
+media_downloader_docker_network_name: 'media_downloader_network'
diff --git a/roles/media_downloader/handlers/main.yaml b/roles/media_downloader/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/media_downloader/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/media_downloader/tasks/main.yaml b/roles/media_downloader/tasks/main.yaml
new file mode 100644
index 0000000..d3840a5
--- /dev/null
+++ b/roles/media_downloader/tasks/main.yaml
@@ -0,0 +1,91 @@
+# https://wiki.servarr.com/
+# https://trash-guides.info/
+---
+
+- name: 'Create the media_downloader network'
+ community.docker.docker_network:
+ name: '{{ media_downloader_docker_network_name }}'
+ state: 'present'
+
+- name: 'Install radarr for movies'
+ community.docker.docker_container:
+ name: 'radarr'
+ image: 'lscr.io/linuxserver/radarr:4.1.0.6175-ls146'
+ pull: true
+ state: 'started'
+ recreate: false
+ env:
+ "PUID": '1000'
+ "PGID": '1000'
+ "TZ": 'America/Toronto'
+ networks:
+ - name: '{{ media_downloader_docker_network_name }}'
+ ports:
+ - '{{ media_downloader_radarr_host_port }}:7878'
+ volumes:
+ - radarr-config:/config
+ - '{{ media_downloader_transmission_root_dir }}/downloads:/downloads'
+ - '{{ media_downloader_media_root_dir }}/mov:/mov'
+ restart_policy: "unless-stopped"
+
+- name: 'Install sonarr for tv'
+ community.docker.docker_container:
+ name: 'sonarr'
+ image: 'lscr.io/linuxserver/sonarr:3.0.9.1549-ls154'
+ pull: true
+ state: 'started'
+ recreate: false
+ env:
+ "PUID": '1000'
+ "PGID": '1000'
+ "TZ": 'America/Toronto'
+ networks:
+ - name: '{{ media_downloader_docker_network_name }}'
+ ports:
+ - '{{ media_downloader_sonarr_host_port }}:8989'
+ volumes:
+ - sonarr-config:/config
+ - '{{ media_downloader_transmission_root_dir }}/downloads:/downloads'
+ - '{{ media_downloader_media_root_dir }}/tv:/tv'
+ restart_policy: "unless-stopped"
+
+- name: 'Install prowlarr for indexing sources'
+ community.docker.docker_container:
+ name: 'prowlarr'
+ image: 'linuxserver/prowlarr:develop-0.4.4.1947-ls65'
+ pull: true
+ state: 'started'
+ recreate: false
+ env:
+ "PUID": '1000'
+ "PGID": '1000'
+ "TZ": 'America/Toronto'
+ networks:
+ - name: '{{ media_downloader_docker_network_name }}'
+ ports:
+ - '{{ media_downloader_prowlarr_host_port }}:9696'
+ volumes:
+ - prowlarr-config:/config
+ restart_policy: "unless-stopped"
+
+- name: 'Install bazarr for subtitles'
+ community.docker.docker_container:
+ name: 'bazarr'
+ image: 'cr.hotio.dev/hotio/bazarr:release-1.1.0'
+ pull: true
+ state: 'started'
+ recreate: false
+ env:
+ "PUID": '1000'
+ "PGID": '1000'
+ "TZ": 'America/Toronto'
+ "UMASK": '002'
+ networks:
+ - name: '{{ media_downloader_docker_network_name }}'
+ ports:
+ - '{{ media_downloader_bazarr_host_port }}:6767'
+ volumes:
+ - bazaar-config:/config
+ - '{{ media_downloader_media_root_dir }}/tv:/tv'
+ - '{{ media_downloader_media_root_dir }}/mov:/mov'
+ restart_policy: "unless-stopped"
diff --git a/roles/monitoring/defaults/main.yaml b/roles/monitoring/defaults/main.yaml
new file mode 100644
index 0000000..cd11c66
--- /dev/null
+++ b/roles/monitoring/defaults/main.yaml
@@ -0,0 +1,17 @@
+# Default Values
+---
+
+nextcloud_uid: "1000"
+nextcloud_gid: "1000"
+nextcloud_tz: 'America/Toronto'
+nextcloud_data_root: ''
+nextcloud_host_port: ''
+
+nextcloud_docker_network_name: 'nextcloud_network'
+
+nextcloud_postgres_db: 'nextcloud_db'
+nextcloud_postgres_user: 'nextcloud'
+nextcloud_postgres_password: ''
+
+nextcloud_container_name: 'nextcloud'
+nextcloud_dashboard_url: 'https://{{ nextcloud_domain }}'
diff --git a/roles/monitoring/files/zfs-exporter b/roles/monitoring/files/zfs-exporter
new file mode 100644
index 0000000..7f5a09d
--- /dev/null
+++ b/roles/monitoring/files/zfs-exporter
@@ -0,0 +1,23 @@
+#!/sbin/openrc-run
+supervisor=supervise-daemon
+
+command="/usr/bin/zfs_exporter"
+command_args="$ARGS"
+command_background="yes"
+group="root"
+user="root"
+
+logdir="/var/log/prometheus"
+logfile="$logdir/${SVCNAME}.log"
+pidfile="/var/run/${SVCNAME}.pid"
+start_stop_daemon_args="--stderr $logfile --user $user --group $group"
+
+depend() {
+ need net
+ after firewall
+}
+
+start_pre() {
+ checkpath -d -o $user:$group -m755 $logdir
+ checkpath -f -o $user:$group -m644 $logfile
+}
diff --git a/roles/monitoring/handlers/main.yaml b/roles/monitoring/handlers/main.yaml
new file mode 100644
index 0000000..7613b54
--- /dev/null
+++ b/roles/monitoring/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- name: 'Restart nginx'
+ systemd:
+ name: 'nginx'
+ state: 'restarted'
+ listen: 'nginx_restart'
diff --git a/roles/monitoring/tasks/blackbox.yaml b/roles/monitoring/tasks/blackbox.yaml
new file mode 100644
index 0000000..932b457
--- /dev/null
+++ b/roles/monitoring/tasks/blackbox.yaml
@@ -0,0 +1,21 @@
+---
+
+# Blackbox Exporter for service level monitoring
+- name: 'Copy the blackbox.yml config file to conf dir'
+ template:
+ src: 'blackbox.yml.j2'
+ dest: '{{ monitoring_root_dir }}/blackbox.yml'
+ mode: '0644'
+
+- name: 'Make sure the blackbox exporter container is created and running'
+ docker_container:
+ name: 'blackbox-exporter'
+ image: 'prom/blackbox-exporter:v0.22.0'
+ pull: true
+ state: 'started'
+ recreate: true
+ command: '--config.file=/config/blackbox.yml'
+ volumes:
+ - "{{ monitoring_root_dir }}/blackbox.yml:/config/blackbox.yml"
+ network_mode: 'host'
+ restart_policy: unless-stopped
diff --git a/roles/monitoring/tasks/main.yaml b/roles/monitoring/tasks/main.yaml
new file mode 100644
index 0000000..268659b
--- /dev/null
+++ b/roles/monitoring/tasks/main.yaml
@@ -0,0 +1,19 @@
+---
+
+- name: 'Ensure monitoring root dir exists'
+ file:
+ path: '{{ monitoring_root_dir }}'
+ state: 'directory'
+ mode: '755'
+
+- name: 'Setup the Node Exporter'
+ import_tasks: 'node.yaml'
+
+- name: 'Setup the Blackbox Exporter'
+ import_tasks: 'blackbox.yaml'
+
+- name: 'Setup the ZFS Exporter'
+ import_tasks: 'zfs.yaml'
+
+- name: 'Setup Prometheus'
+ import_tasks: 'prometheus.yaml'
diff --git a/roles/monitoring/tasks/node.yaml b/roles/monitoring/tasks/node.yaml
new file mode 100644
index 0000000..5d38f1f
--- /dev/null
+++ b/roles/monitoring/tasks/node.yaml
@@ -0,0 +1,23 @@
+# https://www.robustperception.io/temperature-and-hardware-monitoring-metrics-from-the-node-exporter/
+---
+
+# Need to install lm-sensors lm-sensors-detect
+# Run sensors, for configurations.
+
+# Node Exporter for OS level monitoring is recommneded to be installed w/o Docker.
+- block:
+ - name: 'Install node-exporter'
+ become: true
+ become_method: 'doas'
+ package:
+ name: 'prometheus-node-exporter'
+ state: 'present'
+
+ - name: 'Start and enable node-exporter service'
+ become: true
+ become_method: 'doas'
+ service:
+ name: 'node-exporter'
+ state: 'started'
+ enabled: true
+ when: 'ansible_os_family == "Alpine"'
diff --git a/roles/monitoring/tasks/prometheus.yaml b/roles/monitoring/tasks/prometheus.yaml
new file mode 100644
index 0000000..0fbfd89
--- /dev/null
+++ b/roles/monitoring/tasks/prometheus.yaml
@@ -0,0 +1,23 @@
+---
+
+# Install Prometheus as TSDB for monitoring metrics
+- name: 'Copy the prometheus.yml config file to conf dir'
+ template:
+ src: 'prometheus.yml.j2'
+ dest: '{{ monitoring_root_dir }}/prometheus.yml'
+ mode: '0644'
+
+- name: 'Make sure prometheus container is created and running'
+ docker_container:
+ name: 'prometheus'
+ image: 'prom/prometheus:v2.37.0'
+ pull: true
+ state: 'started'
+ recreate: true
+ command: '--config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/data/prometheus'
+ user: 'root'
+ volumes:
+ - "{{ monitoring_root_dir }}/prometheus.yml:/etc/prometheus/prometheus.yml"
+ - "{{ monitoring_root_dir }}/prom_data:/data/prometheus"
+ network_mode: 'host'
+ restart_policy: unless-stopped
diff --git a/roles/monitoring/tasks/zfs.yaml b/roles/monitoring/tasks/zfs.yaml
new file mode 100644
index 0000000..2f18e32
--- /dev/null
+++ b/roles/monitoring/tasks/zfs.yaml
@@ -0,0 +1,49 @@
+# https://github.com/pdf/zfs_exporter
+
+---
+
+# ZFS Exporter for ZFS monitoring
+
+- name: 'Download zfs exporter tarball'
+ get_url:
+ url: 'https://github.com/pdf/zfs_exporter/releases/download/v2.2.5/zfs_exporter-2.2.5.linux-arm64.tar.gz'
+ dest: '{{ monitoring_root_dir }}/zfs_exporter.tar.gz'
+ mode: '644'
+
+- name: 'Ensure the zfs exporter dir exists'
+ file:
+ path: '{{ monitoring_root_dir }}/zfs_exporter-2.2.5.linux-arm64'
+ state: 'directory'
+ mode: '755'
+
+- name: 'Extract ZFS exporter to dir'
+ command: 'tar -xf zfs_exporter-2.2.5.linux-arm64.tar.gz'
+ args:
+ chdir: '{{ monitoring_root_dir }}'
+
+- name: 'Copy the executable to /usr/bin'
+ become: true
+ become_method: 'doas'
+ copy:
+ src: '{{ monitoring_root_dir }}/zfs_exporter-2.2.5.linux-arm64/zfs_exporter'
+ dest: '/usr/bin/zfs_exporter'
+ mode: '0755'
+ owner: 'root'
+ remote_src: true
+
+- name: 'Create service file to start zfs_exporter on boot'
+ become: true
+ become_method: 'doas'
+ copy:
+ src: 'zfs-exporter'
+ dest: '/etc/init.d/zfs-exporter'
+ mode: '0755'
+ owner: 'root'
+
+- name: 'Start and enable the zfs-exporter service'
+ become: true
+ become_method: 'doas'
+ service:
+ name: 'zfs-exporter'
+ state: 'started'
+ enabled: true
diff --git a/roles/monitoring/templates/blackbox.yml.j2 b/roles/monitoring/templates/blackbox.yml.j2
new file mode 100644
index 0000000..9dd359a
--- /dev/null
+++ b/roles/monitoring/templates/blackbox.yml.j2
@@ -0,0 +1,4 @@
+modules:
+ http_2xx:
+ prober: http
+ timeout: 5s
diff --git a/roles/monitoring/templates/prometheus.yml.j2 b/roles/monitoring/templates/prometheus.yml.j2
new file mode 100644
index 0000000..9bdbbe3
--- /dev/null
+++ b/roles/monitoring/templates/prometheus.yml.j2
@@ -0,0 +1,62 @@
+global:
+ scrape_interval: 15s
+ evaluation_interval: 30s
+
+scrape_configs:
+ - job_name: 'prometheus'
+ honor_labels: true
+ static_configs:
+ - targets: ["localhost:9090"]
+ labels:
+ env: prod
+
+ - job_name: 'node_exporter'
+ static_configs:
+ - targets: ["localhost:9100"]
+
+ - job_name: 'zfs_exporter'
+ metrics_path: /metrics
+ static_configs:
+ - targets: ["localhost:9134"]
+
+ - job_name: 'blackbox-service-status'
+ metrics_path: /probe
+ params:
+ module: [http_2xx]
+ static_configs:
+{% for t in monitoring_apps_confs %}
+{% if not t.conf.curl_requires_auth %}
+ - targets:
+{% if "access_domain" in t.conf %}
+ - 'https://{{ t.conf.access_domain }}{{ t.conf.status_endpoint }}'
+{% else %}
+ - 'http://0.0.0.0:{{ t.conf.port }}{{ t.conf.status_endpoint }}'
+{% endif %}
+ labels:
+ name: '{{ t.app }}'
+{% endif %}
+{% endfor %}
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: __param_target
+ - source_labels: [__param_target]
+ target_label: instance
+ - target_label: __address__
+ replacement: 127.0.0.1:9115 # Blackbox exporter.
+
+ - job_name: 'blackbox-ssl-sites'
+ metrics_path: /probe
+ params:
+ module: [http_2xx]
+ static_configs:
+ - targets:
+{% for t in monitoring_static_sites %}
+ - 'https://{{ t.name }}'
+{% endfor %}
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: __param_target
+ - source_labels: [__param_target]
+ target_label: instance
+ - target_label: __address__
+ replacement: 127.0.0.1:9115 # Blackbox exporter.
diff --git a/roles/nextcloud/tasks/main.yaml b/roles/nextcloud/tasks/main.yaml
index 593bfa3..c1d91aa 100644
--- a/roles/nextcloud/tasks/main.yaml
+++ b/roles/nextcloud/tasks/main.yaml
@@ -12,11 +12,7 @@
image: 'postgres:14.1-alpine'
pull: true
state: 'started'
- labels:
- "flame.type": "application"
- "flame.name": "{{ nextcloud_container_name | title }}"
- "flame.url": "{{ nextcloud_dashboard_url }}"
- "flame.icon": "custom"
+ recreate: true
env:
"PUID": '{{ nextcloud_uid }}'
"PGID": '{{ nextcloud_gid }}'
@@ -39,7 +35,7 @@
- name: 'Make sure the Nextcloud container is created and running'
community.docker.docker_container:
name: '{{ nextcloud_container_name }}'
- image: 'ghcr.io/linuxserver/nextcloud:php8'
+ image: 'ghcr.io/linuxserver/nextcloud:php8-24.0.4-ls81'
pull: true
state: 'started'
env:
diff --git a/roles/nginx_docker/defaults/main.yaml b/roles/nginx_docker/defaults/main.yaml
new file mode 100644
index 0000000..af90628
--- /dev/null
+++ b/roles/nginx_docker/defaults/main.yaml
@@ -0,0 +1,7 @@
+# Default Values
+---
+
+nginx_port: '80'
+nginx_website_domains: []
+nginx_global_apps_domain: ''
+nginx_apps_confs: {}
diff --git a/roles/nginx_docker/handlers/main.yaml b/roles/nginx_docker/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/nginx_docker/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/nginx_docker/tasks/main.yaml b/roles/nginx_docker/tasks/main.yaml
new file mode 100644
index 0000000..bda276e
--- /dev/null
+++ b/roles/nginx_docker/tasks/main.yaml
@@ -0,0 +1,43 @@
+---
+
+- name: 'Ensure conf dir exists'
+ file:
+ path: '{{ item }}'
+ state: 'directory'
+ mode: '755'
+ loop:
+ - '{{ nginx_conf_root }}'
+ - '{{ nginx_static_html_root }}'
+ - '{{ nginx_certs_root }}'
+
+- name: 'Copy the http nginx.conf files'
+ template:
+ src: 'http.nginx.conf.j2'
+ dest: '{{ nginx_conf_root }}/{{ item }}.conf'
+ mode: '644'
+ loop: '{{ nginx_website_domains }}'
+
+- name: 'Copy the http nginx.conf for apps'
+ template:
+ src: 'app.nginx.conf.j2'
+ dest: '{{ nginx_conf_root }}/{{ item.app }}.conf'
+ mode: '644'
+ when: 'item.conf.access_domain is defined'
+ loop: '{{ nginx_apps_confs }}'
+
+- name: 'Start the Nginx container'
+ community.docker.docker_container:
+ name: 'nginx'
+ image: 'nginx:alpine'
+ pull: true
+ state: 'started'
+ recreate: false
+ volumes:
+ # configs
+ - '{{ nginx_conf_root }}:/etc/nginx/conf.d/:ro'
+ # static pages html
+ - '{{ nginx_static_html_root }}:/var/www/:ro'
+ # ssl certs
+ - '{{ nginx_certs_root }}:/etc/letsencrypt/:ro'
+ network_mode: 'host'
+ restart_policy: 'unless-stopped'
diff --git a/roles/nginx_docker/templates/app.nginx.conf.j2 b/roles/nginx_docker/templates/app.nginx.conf.j2
new file mode 100644
index 0000000..82c3610
--- /dev/null
+++ b/roles/nginx_docker/templates/app.nginx.conf.j2
@@ -0,0 +1,25 @@
+server {
+ listen 443 ssl;
+ root _;
+ server_name {{ item.conf.access_domain }};
+ ssl_certificate /etc/letsencrypt/live/{{ nginx_global_apps_domain }}/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/{{ nginx_global_apps_domain }}/privkey.pem;
+ ssl_protocols TLSv1.1 TLSv1.2;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ location / {
+{% if item.app == "nextcloud" %} {# Nextcloud requires https internally #}
+ proxy_pass https://127.0.0.1:{{ item.conf.port }};
+{% else %}
+ proxy_pass http://127.0.0.1:{{ item.conf.port }};
+{% endif %}
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Host $server_name;
+ proxy_set_header X-Forwarded-Proto https;
+ proxy_read_timeout 1200s;
+ client_max_body_size 0;
+ error_log /var/log/nginx/{{ item.app }}.error.log;
+ }
+}
diff --git a/roles/nginx_docker/templates/http.nginx.conf.j2 b/roles/nginx_docker/templates/http.nginx.conf.j2
new file mode 100644
index 0000000..2d4c61b
--- /dev/null
+++ b/roles/nginx_docker/templates/http.nginx.conf.j2
@@ -0,0 +1,24 @@
+server {
+ {% if item == "default" %}
+ listen 80 default_server;
+ server_name _;
+ return 301 https://$host$request_uri;
+ {% else %}
+ listen 443 ssl;
+ root /var/www/{{ item }}/html;
+ server_name {{ item }} www.{{ item }};
+ ssl_certificate /etc/letsencrypt/live/{{ item }}/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/{{ item }}/privkey.pem;
+ ssl_protocols TLSv1.1 TLSv1.2;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+ index index.html index.htm index.nginx-debian.html;
+
+ location ~ /.well-known {
+ allow all;
+ }
+
+ location / {
+ try_files $uri $uri/ =404;
+ }
+ {% endif %}
+}
diff --git a/roles/samba/tasks/main.yaml b/roles/samba/tasks/main.yaml
index 5207ac5..c89d4bc 100644
--- a/roles/samba/tasks/main.yaml
+++ b/roles/samba/tasks/main.yaml
@@ -1,13 +1,19 @@
-# https://pimylifeup.com/raspberry-pi-samba/
---
-- name: 'Install required apt packages'
+- name: 'Install samba for Alpine'
+ apk:
+ name: 'samba'
+ state: 'latest'
+ when: 'ansible_os_family == "Alpine"'
+
+- name: 'Install samba for Debian'
apt:
name:
- 'samba'
- 'samba-common-bin'
state: 'present'
update_cache: true
+ when: 'ansible_os_family == "Debian"'
- name: 'Copy conf files'
template:
@@ -17,7 +23,7 @@
- name: 'Add Samba user'
expect:
- command: 'sudo smbpasswd -a {{ samba_user }}'
+ command: 'smbpasswd -a {{ samba_user }}'
responses:
(?i)password: "{{ samba_user_pass }}"
@@ -27,3 +33,11 @@
state: 'restarted'
loop:
- 'smbd'
+ when: 'ansible_os_family == "Debian"'
+
+- name: 'Start and enable samba'
+ service:
+ name: 'samba'
+ state: 'started'
+ enabled: true
+ when: 'ansible_os_family == "Alpine"'
diff --git a/roles/samba/templates/smb.conf b/roles/samba/templates/smb.conf
index eb5839a..5c1360a 100644
--- a/roles/samba/templates/smb.conf
+++ b/roles/samba/templates/smb.conf
@@ -1,5 +1,5 @@
[data]
-path = {{ data_vol_ssd }}
+path = {{ samba_data_root }}
writeable=Yes
create mask=0777
directory mask=0777
diff --git a/roles/transmission/defaults/main.yaml b/roles/transmission/defaults/main.yaml
new file mode 100644
index 0000000..cd11c66
--- /dev/null
+++ b/roles/transmission/defaults/main.yaml
@@ -0,0 +1,17 @@
+# Default Values
+---
+
+nextcloud_uid: "1000"
+nextcloud_gid: "1000"
+nextcloud_tz: 'America/Toronto'
+nextcloud_data_root: ''
+nextcloud_host_port: ''
+
+nextcloud_docker_network_name: 'nextcloud_network'
+
+nextcloud_postgres_db: 'nextcloud_db'
+nextcloud_postgres_user: 'nextcloud'
+nextcloud_postgres_password: ''
+
+nextcloud_container_name: 'nextcloud'
+nextcloud_dashboard_url: 'https://{{ nextcloud_domain }}'
diff --git a/roles/transmission/handlers/main.yaml b/roles/transmission/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/transmission/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/transmission/tasks/main.yaml b/roles/transmission/tasks/main.yaml
new file mode 100644
index 0000000..91d3971
--- /dev/null
+++ b/roles/transmission/tasks/main.yaml
@@ -0,0 +1,32 @@
+---
+
+- name: 'Ensure transmission root dir exists'
+ file:
+ path: '{{ transmission_root_dir }}'
+ state: 'directory'
+ mode: '755'
+
+- name: 'Install transmission'
+ community.docker.docker_container:
+ name: 'transmission'
+ image: 'lscr.io/linuxserver/transmission:latest'
+ pull: true
+ state: 'started'
+ recreate: true
+ env:
+ "PUID": '1000'
+ "PGID": '1000'
+ "TZ": 'America/Toronto'
+ USER: '{{ transmission_user }}'
+ PASS: '{{ transmission_password }}'
+ # WHITELIST: '127.0.0.1,192.168.*.*'
+ HOST_WHITELIST: 'kdvpn.crabdance.com'
+ volumes:
+ - '{{ transmission_root_dir }}/data:/config'
+ - '{{ transmission_root_dir }}/downloads:/downloads'
+ - '{{ transmission_root_dir }}/watch:/watch'
+ ports:
+ - '{{ transmission_host_port }}:9091'
+ - 51413:51413
+ - 51413:51413/udp
+ restart_policy: 'unless-stopped'
diff --git a/roles/website/tasks/main.yaml b/roles/website/tasks/main.yaml
index 6fdf7fa..9725f2d 100644
--- a/roles/website/tasks/main.yaml
+++ b/roles/website/tasks/main.yaml
@@ -1,13 +1,15 @@
---
- name: 'Install git'
+ become: true
+ become_method: 'doas'
package:
name: 'git'
state: 'present'
- name: 'Create domain level dir'
file:
- path: '/var/www/{{ item.name }}/html'
+ path: '{{ sites_data_root }}/{{ item.name }}/html'
state: 'directory'
mode: '0755'
loop: '{{ websites }}'
@@ -15,10 +17,11 @@
- name: 'Clone all the website project repos'
git:
repo: '{{ item.git_url }}'
- dest: '/var/www/{{ item.name }}/html'
+ dest: '{{ sites_data_root }}/{{ item.name }}/html'
depth: 1
update: true
force: true
version: '{{ item.git_version }}'
umask: '002'
+ when: 'item.git_url is defined'
loop: '{{ websites }}'
diff --git a/roles/wireguard/handlers/main.yaml b/roles/wireguard/handlers/main.yaml
index bd5fc0d..cd21505 100644
--- a/roles/wireguard/handlers/main.yaml
+++ b/roles/wireguard/handlers/main.yaml
@@ -1,7 +1,2 @@
---
-- name: 'Restart wireguard'
- systemd:
- name: 'wg-quick@wg0'
- state: 'restarted'
- listen: 'restart wireguard'
diff --git a/roles/wireguard/tasks/main.yaml b/roles/wireguard/tasks/main.yaml
index d7e1e51..c3f0942 100644
--- a/roles/wireguard/tasks/main.yaml
+++ b/roles/wireguard/tasks/main.yaml
@@ -1,20 +1,35 @@
# https://dev.to/tangramvision/exploring-ansible-via-setting-up-a-wireguard-vpn-3389
---
-- name: 'install wireguard package'
+- block:
+ - name: 'Install necessary pkgs for Alpine'
+ apk:
+ name: '{{ item }}'
+ state: 'latest'
+ loop:
+ - 'iptables'
+ - 'wireguard-tools'
+
+ - name: 'Enable iptables'
+ service:
+ name: 'iptables'
+ enabled: true
+ when: 'ansible_os_family == "Alpine"'
+
+- name: 'Install wireguard package for Debian'
apt:
name: 'wireguard'
state: 'present'
update_cache: true
+ when: 'ansible_os_family == "Debian"'
-- name: 'create server wireguard config'
+- name: 'Create server wireguard config'
template:
dest: '/etc/wireguard/wg0.conf'
src: 'wg0.conf.j2'
owner: 'root'
group: 'root'
mode: '600'
- notify: 'restart wireguard'
- name: 'Enable IP Forwarding'
sysctl:
@@ -31,8 +46,23 @@
- sysctl_key: 'net.ipv6.conf.all.forwarding'
sysctl_val: "1"
-- name: 'start wireguard and enable on boot'
+- name: 'Start wireguard and enable on boot in Debian'
systemd:
name: 'wg-quick@wg0'
state: 'started'
enabled: true
+ when: 'ansible_os_family == "Debian"'
+
+- name: 'Ensure that wireguard interface starts on boot in Alpine'
+ blockinfile:
+ path: '/etc/network/interfaces'
+ block: |
+ auto wg0
+ iface wg0 inet static
+ requires eth0
+ address 192.168.10.1
+ pre-up ip link add dev wg0 type wireguard
+ pre-up wg setconf wg0 <(wg-quick strip wg0)
+ post-up iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;iptables -A FORWARD -o wg0 -j ACCEPT
+ post-down iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE;iptables -D FORWARD -o wg0 -j ACCEPT
+ when: 'ansible_os_family == "Alpine"'
diff --git a/roles/wireguard/templates/wg0.conf.j2 b/roles/wireguard/templates/wg0.conf.j2
index 6e7bcc1..5201c32 100644
--- a/roles/wireguard/templates/wg0.conf.j2
+++ b/roles/wireguard/templates/wg0.conf.j2
@@ -1,12 +1,13 @@
# {{ ansible_managed }}
[Interface]
+{% if ansible_os_family == "Debian" %}
Address = {{ wireguard_server_ip }}
+{% endif %}
ListenPort = {{ wireguard_server_listen_port }}
PrivateKey = {{ wireguard_server_priv_key }}
-PostUp = iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT
-PostUp = iptables -w -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -w -t nat -A POSTROUTING -o eth0 -j MASQUERADE
-PostDown = iptables -w -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -w -t nat -D POSTROUTING -o eth0 -j MASQUERADE
+PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;iptables -A FORWARD -o %i -j ACCEPT
+PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE;iptables -D FORWARD -o %i -j ACCEPT
{% for peer in wireguard_peers %}