From c85806e3289b5e207d51d382f8dc75edad04404d Mon Sep 17 00:00:00 2001 From: Kumar Damani Date: Tue, 23 Aug 2022 12:02:28 -0400 Subject: switched to alpine initial commit --- README.md | 128 ++++++++++++-- group_vars/all/vars.yaml | 45 ++++- group_vars/all/vault | 50 +++--- group_vars/all/vault.example | 36 ++-- hosts.example | 2 +- hosts.vault | 45 +++-- playbooks/deploy.yaml | 212 ++++++++---------------- requirements.yml | 8 - roles/bitwarden/tasks/main.yaml | 7 + roles/ddclient/handlers/main.yaml | 2 +- roles/ddclient/tasks/main.yaml | 17 +- roles/media_downloader/defaults/main.yaml | 7 + roles/media_downloader/handlers/main.yaml | 2 + roles/media_downloader/tasks/main.yaml | 91 ++++++++++ roles/monitoring/defaults/main.yaml | 17 ++ roles/monitoring/files/zfs-exporter | 23 +++ roles/monitoring/handlers/main.yaml | 7 + roles/monitoring/tasks/blackbox.yaml | 21 +++ roles/monitoring/tasks/main.yaml | 19 +++ roles/monitoring/tasks/node.yaml | 23 +++ roles/monitoring/tasks/prometheus.yaml | 23 +++ roles/monitoring/tasks/zfs.yaml | 49 ++++++ roles/monitoring/templates/blackbox.yml.j2 | 4 + roles/monitoring/templates/prometheus.yml.j2 | 62 +++++++ roles/nextcloud/tasks/main.yaml | 8 +- roles/nginx_docker/defaults/main.yaml | 7 + roles/nginx_docker/handlers/main.yaml | 2 + roles/nginx_docker/tasks/main.yaml | 43 +++++ roles/nginx_docker/templates/app.nginx.conf.j2 | 25 +++ roles/nginx_docker/templates/http.nginx.conf.j2 | 24 +++ roles/samba/tasks/main.yaml | 20 ++- roles/samba/templates/smb.conf | 2 +- roles/transmission/defaults/main.yaml | 17 ++ roles/transmission/handlers/main.yaml | 2 + roles/transmission/tasks/main.yaml | 32 ++++ roles/website/tasks/main.yaml | 7 +- roles/wireguard/handlers/main.yaml | 5 - roles/wireguard/tasks/main.yaml | 38 ++++- roles/wireguard/templates/wg0.conf.j2 | 7 +- 39 files changed, 874 insertions(+), 265 deletions(-) create mode 100644 roles/media_downloader/defaults/main.yaml create mode 100644 roles/media_downloader/handlers/main.yaml create mode 100644 roles/media_downloader/tasks/main.yaml create mode 100644 roles/monitoring/defaults/main.yaml create mode 100644 roles/monitoring/files/zfs-exporter create mode 100644 roles/monitoring/handlers/main.yaml create mode 100644 roles/monitoring/tasks/blackbox.yaml create mode 100644 roles/monitoring/tasks/main.yaml create mode 100644 roles/monitoring/tasks/node.yaml create mode 100644 roles/monitoring/tasks/prometheus.yaml create mode 100644 roles/monitoring/tasks/zfs.yaml create mode 100644 roles/monitoring/templates/blackbox.yml.j2 create mode 100644 roles/monitoring/templates/prometheus.yml.j2 create mode 100644 roles/nginx_docker/defaults/main.yaml create mode 100644 roles/nginx_docker/handlers/main.yaml create mode 100644 roles/nginx_docker/tasks/main.yaml create mode 100644 roles/nginx_docker/templates/app.nginx.conf.j2 create mode 100644 roles/nginx_docker/templates/http.nginx.conf.j2 create mode 100644 roles/transmission/defaults/main.yaml create mode 100644 roles/transmission/handlers/main.yaml create mode 100644 roles/transmission/tasks/main.yaml 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 %} -- cgit v1.2.3