aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md111
-rw-r--r--group_vars/all/vars.yaml24
-rw-r--r--group_vars/all/vault60
-rw-r--r--group_vars/all/vault.example5
-rw-r--r--pix/architecture.pngbin0 -> 74525 bytes
-rw-r--r--pix/architecture.xml (renamed from architecture.xml)0
-rw-r--r--pix/board.pngbin0 -> 391836 bytes
-rw-r--r--pix/case.pngbin0 -> 25664 bytes
-rw-r--r--pix/pcie_sata.pngbin0 -> 35151 bytes
-rw-r--r--pix/psu.pngbin0 -> 32136 bytes
-rw-r--r--pix/sata_power.pngbin0 -> 46595 bytes
-rw-r--r--pix/wd.pngbin0 -> 48808 bytes
-rw-r--r--playbooks/deploy.yaml65
-rw-r--r--roles/adguard/defaults/main.yaml4
-rw-r--r--roles/adguard/handlers/main.yaml2
-rw-r--r--roles/adguard/tasks/main.yaml38
-rw-r--r--roles/base/defaults/main.yaml2
-rw-r--r--roles/base/handlers/main.yaml2
-rw-r--r--roles/base/tasks/base_alpine.yaml1
-rw-r--r--roles/base/tasks/base_debian.yaml62
-rw-r--r--roles/base/tasks/main.yaml9
-rw-r--r--roles/ddclient/tasks/main.yaml9
-rw-r--r--roles/media_downloader/tasks/main.yaml16
-rw-r--r--roles/monitoring/files/zfs-exporter.service13
-rw-r--r--roles/monitoring/tasks/node.yaml15
-rw-r--r--roles/monitoring/tasks/zfs.yaml31
-rw-r--r--roles/nextcloud/defaults/main.yaml4
-rw-r--r--roles/nextcloud/tasks/main.yaml2
-rw-r--r--roles/nginx_docker/templates/app.nginx.conf.j28
-rw-r--r--roles/photoprism/defaults/main.yaml4
-rw-r--r--roles/photoprism/handlers/main.yaml2
-rw-r--r--roles/photoprism/tasks/main.yaml52
-rw-r--r--roles/plex/defaults/main.yaml4
-rw-r--r--roles/plex/handlers/main.yaml2
-rw-r--r--roles/plex/tasks/main.yaml22
-rw-r--r--roles/transmission/tasks/main.yaml4
-rw-r--r--roles/website/tasks/main.yaml17
-rw-r--r--roles/wireguard/tasks/main.yaml1
38 files changed, 480 insertions, 111 deletions
diff --git a/README.md b/README.md
index 718cbf6..1d7c194 100644
--- a/README.md
+++ b/README.md
@@ -14,13 +14,14 @@ My requirements are as follows:
| | Email | n/a |
| :heavy_check_mark: | Syncing/Sharing files, calender, contacts, 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: | Media (pictures, tv, movies) Server | [Plex](https://plex.tv) or [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: | Photo sharing | [Photoprism](https://photoprism.app) |
| :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.
@@ -32,7 +33,7 @@ I don't want it to have much of an impact on my utility (power) bill, which of c
so much heat that it requires advanced cooling.
## Architecture
-![Architecture](./architecture.png)
+![Architecture](./pix/architecture.png)
Notice that this setup requires a very small VPS since we are just running a wireguard client on it. All storage, and compute is being done by the Home Server. This means that my cost went from ~ $13/mo to ~ $1/mo for the VPS service, *while* increasing my SSD storage capacity from 50GB to 2TB (or whatever you have lying around)! And this does not incude the cost savings from self-hosting many of these services in the first place.
@@ -46,71 +47,87 @@ There are many cheap VPS providers out there. I use Racknerd now. I have used Vu
## 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.
+> The equipment I use reflect my current priorities and have changed since this project started and will
+continue to change in the future.
+
+A [ROCKPro64](https://wiki.pine64.org/wiki/ROCKPro64) 4G model.
+Alternatively, an RPi4 or similar would also work if you can get your hands on it.
+![ROCKPro64](./pix/board.png)
+
+There are many reasons why this board is awesome:
+1. In Stock.
+2. Similar price/performance/energy usage as the RPi4.
+3. PCIe slot!!
+
+My main reason for switching to this board is the final point above :)
+
+Speaking of the PCIe slot, we can get a PCIe SATA adapter to connect to two SATA drives.
+![Dual SATA Adapter](./pix/pcie_sata.png)
+
+To power the drives, Pine64 all sells power cables:
+![SATA power cables](./pix/sata_power.png)
+
+The drives themselves are 4 TiB 3.5in 5400 RPM CMR such as:
+![Drive 1](./pix/wd.png)
+
+> 7200 RPM drives are more expensive and I won't be pushing this hard enough to notice the benefits.
+> Note there will be cheaper drives using SMR, but I'd recommend CMR is worth the extra cost.
+
+Remember to buy drives that are not made as part of the same batch, so that the probabity of them
+dying together is the lowest. You can also do this by buying different brands.
+
+Also remember to buy an extra set so that you save yourself some panic during recovery.
+
+When using the dual SATA adapter, Pine64 recommends a beefier 12V, 3A power-supply:
+![PSU](./pix/psu.png)
+
+Since this is basically a NAS build, I opted to house all of this in:
+![NAS Case](./pix/case.png)
+Which comes included with a fan, and the SATA power-cables.
+
+Optional, but recommended: an external usb SSD or HDD as a backup drive.
+
+An finally, a very cheap VPS (Virtual Private Server) - I use Racknerd.
+This will give you access to a reliable static IP.
### 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
-# TODO: Make these tasks part of an Ansible role.
-echo "dtoverlay=gpio-fan,gpiopin=14,temp=70000" > /boot/usercfg.txt
-
-# 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.
+I have switched to using DietPi images (from Alpine) as they support my hardware, as well as RPis.
+
+1. Follow instructions from [DietPi wiki](https://dietpi.com/docs/install/) to create a bootable SD card and boot up.
+2. On first boot, I recommend you change your `root` password, and change the SSH server to use OpenSSH (from Dropbear).
+This makes running automation against it easier.
+3. Then you can run our playbook with the `base` tag to install all pre-requisite software.
+4. You should then setup your drives according to your needs. If you are doing ZFS, the section below might be useful.
### NAS Setup
-As a minimum, I recommend setting up two of the external usb drives as a ZFS mirrored pool.
+I recommend setting up the two 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 #
+# Install zfs (the base role will do this for you if using a rockpro64)
+# Otherwise there are usually two steps:
+# 1. Install the kernel headers for your kernel.
+# 2. Install the zfs-dkms, and zfsutils-linux packages.
+
# 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
+# get the ids -> /dev/sdX mapping of your disks by
+ls -al /dev/disk/by-id/
+# using ids is recommened because then zpool status will instantly tell you
+# which disk in reality is problematic, rather than sda,sdb etc.
+zpool create yourpool mirror /dev/disk/by-id/yourdisk1 /dev/disk/by-id/yourdisk2
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
+zpool scrub yourpool
zfs get mountpoint
zfs mount -l yourpool/data
zfs mount -l yourpool/media
diff --git a/group_vars/all/vars.yaml b/group_vars/all/vars.yaml
index 12fd063..7b27440 100644
--- a/group_vars/all/vars.yaml
+++ b/group_vars/all/vars.yaml
@@ -1,9 +1,21 @@
+# The value in this file correspond to MY SETUP.
+# You will need to change these to reflect yours.
---
+# This is the secondary user you want to setup.
+# Passwords go in the Vault.
+username: 'kdam0'
+
+# This is pretty much only used for the ZFS install step.
+# sbc: Currently supported ones are:
+ # - Rockchip: rockchip64
+# If you don't care about installing ZFS from here, leave this blank.
+hardware: 'rockchip64'
+
# the wildcard domain under which all apps will be hosted.
apps_domain: 'kumardamani.net'
-# list all the app configs you want to host here.
+# list of all the apps you want to run behind nginx.
# port: the host port that this service will be available on.
# access_domain: external (nginx) domain.
# Only include when applicable.
@@ -52,6 +64,16 @@ apps_conf_map:
port: 31907
status_endpoint: '/system/status'
curl_requires_auth: false
+ photoprism:
+ port: 31908
+ access_domain: 'photos.{{ apps_domain }}'
+ status_endpoint: ''
+ curl_requires_auth: false
+ # adguard:
+ # port: 31909
+ # access_domain: 'adguard.{{ apps_domain }}'
+ # status_endpoint: ''
+ # curl_requires_auth: false
# list all static websites you plan to host here.
# name: the root domain name of the static website.
diff --git a/group_vars/all/vault b/group_vars/all/vault
index b7497af..328c155 100644
--- a/group_vars/all/vault
+++ b/group_vars/all/vault
@@ -1,28 +1,34 @@
$ANSIBLE_VAULT;1.1;AES256
-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
+61373432623236353766373265633331353163393733366637363333383935386137336464313864
+6165363331303839363837396331353866373264376464660a363364666661613738336536333138
+37383833663765366135366139323531353966663333313938636163643636666638383863353265
+6638363065323261350a343063343932633066313962323763623366333232316262383662393562
+63656138336339373431333033643264393937306137356466343161396362353537323363643834
+64326264326665636633636361386336316235386433326536613263666234363932323766316538
+64306362353236316334653839303636373963343434303435343132326638613162323334663232
+37663932646132613935333030386633343833323532343864616136393737303864343139643366
+61316666346439613762376534663162643030356630646661623037643063306632343861636336
+31663435323362663163616335383264656534363739366461373239396337623234616164366239
+63306530616163633735633062666134393430633733333235373134663763666637323930346130
+66373663653734356665313464633966313835303838323266613331313535353064663431396133
+65616135376163653532356438313331396138653164356362313633633935623435383430663538
+32316162643436333933343537373233343731383164363634373964653537613265633934643235
+65656636643133333735346164373862383161363061306638363763363333653562653334323536
+62323066653462346362323737626436303966393932633132636264623032633530653763636434
+33393966306436396564356563666635666630626661313762336134643232646631353234393864
+63613165396362643963303632636531653939333134363032313533663735613337386236313034
+62653139633861383662356530396638333837613338666563343835346236653036313964643330
+30353063356636643331396635633438313335396133356431613232326630363864393939663962
+38313861356163646665346163613932626662623636333165386535613863363264613666636432
+39326665323563613033663930636631616264626236656265616337383737616466643530653463
+63346538316231313365373866373430623131366561326137653535663437623935626636636338
+38303463666639646166323834353334383831376465363532616330313737393262656666393566
+65336239653861313433386661636339356532623862306238653366373531333833323237623731
+63356466323637343830356164393833323633343234376262313564613861303535613864336531
+37643536333339633366363264303638316266316163343039376537373634626361393163326565
+65373539643461383066306363313165616435633836363336313336396666336232626136636331
+34623434343431646134353734373733343338346432343333316132366566633861373934326434
+65333130633463626364386561636232383138313632626639653063303163646137323336396635
+61363066663465613731373936663337666563616662626234643239396335376363393431306638
+36323665633236376465663662643230313564386561386462326337323533613762663435363763
+33383135636437353363313030663561393235363366323030383166393939333332
diff --git a/group_vars/all/vault.example b/group_vars/all/vault.example
index 8ca22bf..e053dda 100644
--- a/group_vars/all/vault.example
+++ b/group_vars/all/vault.example
@@ -1,5 +1,7 @@
---
+vault_user_password: ''
+
vault_wireguard_server_priv_key: ''
vault_ddclient_user: ''
@@ -18,3 +20,6 @@ vault_searxng_secret_key: ''
vault_transmission_user: ''
vault_transmission_password: ''
+vault_photoprism_admin_password: ''
+
+vault_plex_claim: ''
diff --git a/pix/architecture.png b/pix/architecture.png
new file mode 100644
index 0000000..e7a092d
--- /dev/null
+++ b/pix/architecture.png
Binary files differ
diff --git a/architecture.xml b/pix/architecture.xml
index 6a254c4..6a254c4 100644
--- a/architecture.xml
+++ b/pix/architecture.xml
diff --git a/pix/board.png b/pix/board.png
new file mode 100644
index 0000000..b02b9f8
--- /dev/null
+++ b/pix/board.png
Binary files differ
diff --git a/pix/case.png b/pix/case.png
new file mode 100644
index 0000000..122172e
--- /dev/null
+++ b/pix/case.png
Binary files differ
diff --git a/pix/pcie_sata.png b/pix/pcie_sata.png
new file mode 100644
index 0000000..a7cfba9
--- /dev/null
+++ b/pix/pcie_sata.png
Binary files differ
diff --git a/pix/psu.png b/pix/psu.png
new file mode 100644
index 0000000..7143f87
--- /dev/null
+++ b/pix/psu.png
Binary files differ
diff --git a/pix/sata_power.png b/pix/sata_power.png
new file mode 100644
index 0000000..cc5450f
--- /dev/null
+++ b/pix/sata_power.png
Binary files differ
diff --git a/pix/wd.png b/pix/wd.png
new file mode 100644
index 0000000..1583750
--- /dev/null
+++ b/pix/wd.png
Binary files differ
diff --git a/playbooks/deploy.yaml b/playbooks/deploy.yaml
index 08af211..e1e0970 100644
--- a/playbooks/deploy.yaml
+++ b/playbooks/deploy.yaml
@@ -5,26 +5,33 @@
# make dry-run file=playbooks/deploy.yaml tags=""
#
# Available tags:
-# ddclient, wireguard, nginx, websites,
-# samba, nextcloud, bitwarden, searxng,
+# base, ddclient, wireguard, websites samba,
+# nginx, nextcloud, bitwarden, searxng,
# monitoring, transmission, media_downloader
+# photoprism, plex
#
# Install:
# make install
#
-# ASSUMPTIONS:
-# You should already have docker installed.
-# See the README.md for base image setup section.
-#
---
## Non Docker Services ##
- hosts: compute
gather_facts: true
+ tags: 'base'
+ become: true
+ roles:
+ - role: base
+ vars:
+ base_user: '{{ username }}'
+ base_user_password: '{{ vault_user_password }}'
+ base_hardware: '{{ hardware }}'
+
+- hosts: compute
+ gather_facts: true
tags: 'ddclient'
become: true
- become_method: 'doas'
roles:
- role: ddclient
vars:
@@ -37,7 +44,6 @@
gather_facts: true
tags: 'wireguard'
become: true
- become_method: 'doas'
roles:
- role: wireguard
vars:
@@ -47,9 +53,9 @@
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='
+ peer_key: 'QUirl0QsXC3P6D5t5VPlvDgfji1ZI5e0XhppBFLW9TY='
- peer_ip: '192.168.10.3/32' # personal laptop
- peer_key: '6+t6FbEHSAOuzBtQwb0bDqfFa5Kvfkb2QIUGpRKA5Eg='
+ peer_key: 'pzqY/UxffV8O01K982jlgP1xJQphnglOdqVhOM2IUSc='
- peer_ip: '192.168.10.4/32' # vps
peer_key: 'oz2jxeSUWD4r5g3y7XuSItqSiqOOJz8vulYYVXAsKS8='
@@ -70,7 +76,6 @@
gather_facts: true
tags: 'samba'
become: true
- become_method: 'doas'
roles:
- role: samba
vars:
@@ -94,6 +99,17 @@
nginx_static_html_root: '{{ vol_data }}/sites'
nginx_certs_root: '{{ vol_data }}/letsencrypt'
+# - hosts: compute
+# gather_facts: false
+# tags: 'adguard'
+# become: false
+# roles:
+# - role: adguard
+# vars:
+# adguard_domain: '{{ apps_conf_map["adguard"]["access_domain"] }}'
+# adguard_host_port: '{{ apps_conf_map["adguard"]["port"] }}'
+# adguard_data_root: '{{ vol_data }}/adguard'
+
- hosts: compute
gather_facts: false
tags: 'nextcloud'
@@ -163,3 +179,30 @@
monitoring_root_dir: '{{ vol_data }}/monitoring'
monitoring_apps_confs: '{{ apps_conf_map | dict2items(key_name="app", value_name="conf") }}'
monitoring_static_sites: '{{ nginx_websites }}'
+
+- hosts: compute
+ gather_facts: false
+ tags: 'photoprism'
+ become: false
+ roles:
+ - role: photoprism
+ vars:
+ photoprism_host_port: '{{ apps_conf_map["photoprism"]["port"] }}'
+ photoprism_admin_password: '{{ vault_photoprism_admin_password }}'
+ photoprism_data_dir: '{{ vol_data }}/photoprism'
+ photoprism_pics_root_dir: '{{ vol_media }}/pics'
+
+- hosts: compute
+ gather_facts: false
+ tags: 'plex'
+ become: false
+ roles:
+ - role: plex
+ vars:
+ plex_host_port: '{{ apps_conf_map["plex"]["port"] }}'
+ plex_claim: '{{ vault_plex_claim }}'
+ plex_library_dir: '{{ vol_media }}/plex'
+ plex_tv_dir: '{{ vol_media }}/media/tv'
+ plex_mov_dir: '{{ vol_media }}/media/mov'
+ plex_pic_dir: '{{ vol_media }}/pics'
+ plex_music_dir: '{{ vol_media }}/music'
diff --git a/roles/adguard/defaults/main.yaml b/roles/adguard/defaults/main.yaml
new file mode 100644
index 0000000..91abefa
--- /dev/null
+++ b/roles/adguard/defaults/main.yaml
@@ -0,0 +1,4 @@
+# Default Values
+---
+
+adguard_docker_network_name: 'adguard_network'
diff --git a/roles/adguard/handlers/main.yaml b/roles/adguard/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/adguard/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/adguard/tasks/main.yaml b/roles/adguard/tasks/main.yaml
new file mode 100644
index 0000000..018b067
--- /dev/null
+++ b/roles/adguard/tasks/main.yaml
@@ -0,0 +1,38 @@
+# https://docs.photoprism.app/getting-started/docker-compose/
+---
+
+- name: 'Create the AdGuard network'
+ community.docker.docker_network:
+ name: '{{ adguard_docker_network_name }}'
+ state: 'present'
+
+- name: 'Create the required dirs'
+ file:
+ state: 'directory'
+ path: '{{ item }}'
+ mode: '755'
+ loop:
+ - '{{ adguard_data_root }}'
+ - '{{ adguard_data_root }}/data'
+ - '{{ adguard_data_root }}/conf'
+
+- name: 'Start the AdGuard container'
+ community.docker.docker_container:
+ name: 'adguard'
+ image: 'adguard/adguardhome'
+ pull: true
+ state: 'started'
+ recreate: false
+ networks:
+ - name: '{{ adguard_docker_network_name }}'
+ ports:
+ # DNS
+ - '53:53/tcp'
+ - '53:53/udp'
+ # Web
+ - '{{ adguard_host_port }}:3000'
+ volumes:
+ - '{{ adguard_data_root }}/data:/opt/adguardhome/work'
+ - '{{ adguard_data_root }}/conf:/opt/adguardhome/conf'
+ # restart_policy: 'unless-stopped'
+ restart_policy: 'no'
diff --git a/roles/base/defaults/main.yaml b/roles/base/defaults/main.yaml
new file mode 100644
index 0000000..9a163d4
--- /dev/null
+++ b/roles/base/defaults/main.yaml
@@ -0,0 +1,2 @@
+# Default Values
+---
diff --git a/roles/base/handlers/main.yaml b/roles/base/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/base/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/base/tasks/base_alpine.yaml b/roles/base/tasks/base_alpine.yaml
new file mode 100644
index 0000000..ed97d53
--- /dev/null
+++ b/roles/base/tasks/base_alpine.yaml
@@ -0,0 +1 @@
+---
diff --git a/roles/base/tasks/base_debian.yaml b/roles/base/tasks/base_debian.yaml
new file mode 100644
index 0000000..9d25ea6
--- /dev/null
+++ b/roles/base/tasks/base_debian.yaml
@@ -0,0 +1,62 @@
+---
+
+- name: 'Install base packages for Debian'
+ apt:
+ name:
+ - '{{ item }}'
+ state: 'present'
+ update_cache: true
+ loop:
+ - 'less'
+ - 'vim'
+ - 'tmux'
+ - 'neofetch'
+ - 'iotop-c'
+ - 'tcpdump'
+ - 'rsync'
+ - 'python3-pip'
+ - 'docker.io'
+ - 'docker-compose'
+
+- name: 'Install base packages for Python'
+ pip:
+ name: '{{ item }}'
+ loop:
+ - 'docker'
+ - 'pexpect'
+
+- name: "Create the user '{{ base_user }}'"
+ user:
+ name: '{{ base_user }}'
+ state: 'present'
+ shell: '/bin/bash'
+ uid: 1001
+ password: '{{ base_user_password | password_hash("sha512") }}'
+ create_home: true
+ generate_ssh_key: true
+ groups: 'sudo, docker'
+ append: true
+
+- name: 'Allow passwordless sudo for this {{ base_user }}'
+ lineinfile:
+ path: '/etc/sudoers'
+ state: 'present'
+ regexp: '^%{{ base_user }}\s+ALL='
+ line: '%{{ base_user }} ALL=(ALL) NOPASSWD: ALL'
+ validate: '/usr/sbin/visudo -cf %s'
+
+- block:
+ - name: 'Install kernel headers for currently installed kernel'
+ apt:
+ name: 'linux-headers-current-rockchip64'
+ state: 'present'
+
+ - name: 'Install zfs modules and package'
+ apt:
+ name: '{{ item }}'
+ state: 'present'
+ default_release: 'bullseye-backports'
+ loop:
+ - 'zfs-dkms'
+ - 'zfsutils-linux'
+ when: 'base_hardware == "rockchip64"'
diff --git a/roles/base/tasks/main.yaml b/roles/base/tasks/main.yaml
new file mode 100644
index 0000000..4930d10
--- /dev/null
+++ b/roles/base/tasks/main.yaml
@@ -0,0 +1,9 @@
+---
+
+- name: 'Run base install for Alpine'
+ import_tasks: 'base_alpine.yaml'
+ when: 'ansible_os_family == "Alpine"'
+
+- name: 'Run base install for Debian'
+ import_tasks: 'base_debian.yaml'
+ when: 'ansible_os_family == "Debian"'
diff --git a/roles/ddclient/tasks/main.yaml b/roles/ddclient/tasks/main.yaml
index d780a3f..defcef8 100644
--- a/roles/ddclient/tasks/main.yaml
+++ b/roles/ddclient/tasks/main.yaml
@@ -15,9 +15,16 @@
update_cache: true
when: 'ansible_os_family == "Debian"'
+# - name: 'Update ddclient conf'
+# template:
+# dest: '/etc/ddclient/ddclient.conf'
+# src: 'ddclient.conf.j2'
+# mode: '644'
+# notify: 'restart ddclient'
+
- name: 'Update ddclient conf'
template:
- dest: '/etc/ddclient/ddclient.conf'
+ dest: '/etc/ddclient.conf'
src: 'ddclient.conf.j2'
mode: '644'
notify: 'restart ddclient'
diff --git a/roles/media_downloader/tasks/main.yaml b/roles/media_downloader/tasks/main.yaml
index d3840a5..5f6c8c8 100644
--- a/roles/media_downloader/tasks/main.yaml
+++ b/roles/media_downloader/tasks/main.yaml
@@ -15,8 +15,8 @@
state: 'started'
recreate: false
env:
- "PUID": '1000'
- "PGID": '1000'
+ "PUID": '1001'
+ "PGID": '1001'
"TZ": 'America/Toronto'
networks:
- name: '{{ media_downloader_docker_network_name }}'
@@ -36,8 +36,8 @@
state: 'started'
recreate: false
env:
- "PUID": '1000'
- "PGID": '1000'
+ "PUID": '1001'
+ "PGID": '1001'
"TZ": 'America/Toronto'
networks:
- name: '{{ media_downloader_docker_network_name }}'
@@ -57,8 +57,8 @@
state: 'started'
recreate: false
env:
- "PUID": '1000'
- "PGID": '1000'
+ "PUID": '1001'
+ "PGID": '1001'
"TZ": 'America/Toronto'
networks:
- name: '{{ media_downloader_docker_network_name }}'
@@ -76,8 +76,8 @@
state: 'started'
recreate: false
env:
- "PUID": '1000'
- "PGID": '1000'
+ "PUID": '1001'
+ "PGID": '1001'
"TZ": 'America/Toronto'
"UMASK": '002'
networks:
diff --git a/roles/monitoring/files/zfs-exporter.service b/roles/monitoring/files/zfs-exporter.service
new file mode 100644
index 0000000..8982723
--- /dev/null
+++ b/roles/monitoring/files/zfs-exporter.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=ZFS Exporter
+After=network.target
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/zfs_exporter
+LimitNOFILE=infinity
+User=root
+Group=root
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/monitoring/tasks/node.yaml b/roles/monitoring/tasks/node.yaml
index 5d38f1f..632ceb8 100644
--- a/roles/monitoring/tasks/node.yaml
+++ b/roles/monitoring/tasks/node.yaml
@@ -21,3 +21,18 @@
state: 'started'
enabled: true
when: 'ansible_os_family == "Alpine"'
+
+- block:
+ - name: 'Install node-exporter'
+ become: true
+ package:
+ name: 'prometheus-node-exporter'
+ state: 'present'
+
+ - name: 'Start and enable node-exporter service'
+ become: true
+ service:
+ name: 'prometheus-node-exporter'
+ state: 'started'
+ enabled: true
+ when: 'ansible_os_family == "Debian"'
diff --git a/roles/monitoring/tasks/zfs.yaml b/roles/monitoring/tasks/zfs.yaml
index 2f18e32..a30a7ac 100644
--- a/roles/monitoring/tasks/zfs.yaml
+++ b/roles/monitoring/tasks/zfs.yaml
@@ -17,13 +17,13 @@
mode: '755'
- name: 'Extract ZFS exporter to dir'
- command: 'tar -xf zfs_exporter-2.2.5.linux-arm64.tar.gz'
+ command: 'tar -xf zfs_exporter.tar.gz'
args:
chdir: '{{ monitoring_root_dir }}'
- name: 'Copy the executable to /usr/bin'
become: true
- become_method: 'doas'
+ # become_method: 'doas'
copy:
src: '{{ monitoring_root_dir }}/zfs_exporter-2.2.5.linux-arm64/zfs_exporter'
dest: '/usr/bin/zfs_exporter'
@@ -31,18 +31,31 @@
owner: 'root'
remote_src: true
-- name: 'Create service file to start zfs_exporter on boot'
+# - 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: 'Create systemd services'
become: true
- become_method: 'doas'
copy:
- src: 'zfs-exporter'
- dest: '/etc/init.d/zfs-exporter'
- mode: '0755'
- owner: 'root'
+ src: 'zfs-exporter.service'
+ dest: '/etc/systemd/system/zfs-exporter.service'
+ mode: '644'
+ # notify:
+ # - 'zfs-exporter restart'
+
+- name: 'Reload systemd units'
+ become: true
+ systemd:
+ daemon_reload: true
- name: 'Start and enable the zfs-exporter service'
become: true
- become_method: 'doas'
service:
name: 'zfs-exporter'
state: 'started'
diff --git a/roles/nextcloud/defaults/main.yaml b/roles/nextcloud/defaults/main.yaml
index cd11c66..b0c20f3 100644
--- a/roles/nextcloud/defaults/main.yaml
+++ b/roles/nextcloud/defaults/main.yaml
@@ -1,8 +1,8 @@
# Default Values
---
-nextcloud_uid: "1000"
-nextcloud_gid: "1000"
+nextcloud_uid: "1001"
+nextcloud_gid: "1001"
nextcloud_tz: 'America/Toronto'
nextcloud_data_root: ''
nextcloud_host_port: ''
diff --git a/roles/nextcloud/tasks/main.yaml b/roles/nextcloud/tasks/main.yaml
index c1d91aa..2354d4b 100644
--- a/roles/nextcloud/tasks/main.yaml
+++ b/roles/nextcloud/tasks/main.yaml
@@ -35,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-24.0.4-ls81'
+ image: 'lscr.io/linuxserver/nextcloud:25.0.2'
pull: true
state: 'started'
env:
diff --git a/roles/nginx_docker/templates/app.nginx.conf.j2 b/roles/nginx_docker/templates/app.nginx.conf.j2
index 82c3610..f6f92de 100644
--- a/roles/nginx_docker/templates/app.nginx.conf.j2
+++ b/roles/nginx_docker/templates/app.nginx.conf.j2
@@ -1,5 +1,6 @@
server {
listen 443 ssl;
+ client_max_body_size 500M;
root _;
server_name {{ item.conf.access_domain }};
ssl_certificate /etc/letsencrypt/live/{{ nginx_global_apps_domain }}/fullchain.pem;
@@ -18,8 +19,13 @@ server {
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;
+{% if item.app == "photoprism" %} {# Photoprism requires websockets #}
+ proxy_buffering off;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+{% endif %}
proxy_read_timeout 1200s;
- client_max_body_size 0;
error_log /var/log/nginx/{{ item.app }}.error.log;
}
}
diff --git a/roles/photoprism/defaults/main.yaml b/roles/photoprism/defaults/main.yaml
new file mode 100644
index 0000000..29e3605
--- /dev/null
+++ b/roles/photoprism/defaults/main.yaml
@@ -0,0 +1,4 @@
+# Default Values
+---
+
+photoprism_docker_network_name: 'photoprism_network'
diff --git a/roles/photoprism/handlers/main.yaml b/roles/photoprism/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/photoprism/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/photoprism/tasks/main.yaml b/roles/photoprism/tasks/main.yaml
new file mode 100644
index 0000000..73d807c
--- /dev/null
+++ b/roles/photoprism/tasks/main.yaml
@@ -0,0 +1,52 @@
+# https://docs.photoprism.app/getting-started/docker-compose/
+---
+
+- name: 'Create the photoprism network'
+ community.docker.docker_network:
+ name: '{{ photoprism_docker_network_name }}'
+ state: 'present'
+
+- name: 'Install Photoprism'
+ community.docker.docker_container:
+ name: 'photoprism'
+ image: 'photoprism/photoprism:latest'
+ pull: true
+ state: 'started'
+ recreate: false
+ security_opts:
+ - 'seccomp:unconfined'
+ - 'apparmor:unconfined'
+ env:
+ PHOTOPRISM_ADMIN_PASSWORD: "{{ photoprism_admin_password }}" # INITIAL PASSWORD FOR "admin" USER, MINIMUM 8 CHARACTERS
+ PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password)
+ PHOTOPRISM_SITE_URL: "https://photos.kumardamani.net/" # public server URL incl http:// or https:// and /path, :port is optional
+ PHOTOPRISM_ORIGINALS_LIMIT: "5000" # file size limit for originals in MB (increase for high-res video)
+ PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip)
+ PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic
+ PHOTOPRISM_READONLY: "true" # do not modify originals directory (reduced functionality)
+ PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features
+ PHOTOPRISM_DISABLE_CHOWN: "true" # disables updating storage permissions via chmod and chown on startup
+ PHOTOPRISM_DISABLE_WEBDAV: "true" # disables built-in WebDAV server
+ PHOTOPRISM_DISABLE_SETTINGS: "false" # disables settings UI and API
+ PHOTOPRISM_DISABLE_TENSORFLOW: "true" # disables all features depending on TensorFlow
+ PHOTOPRISM_DISABLE_FACES: "true" # disables face detection and recognition (requires TensorFlow)
+ PHOTOPRISM_DISABLE_CLASSIFICATION: "true" # disables image classification (requires TensorFlow)
+ PHOTOPRISM_DISABLE_RAW: "true" # disables indexing and conversion of RAW files
+ PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW files (reduces performance)
+ PHOTOPRISM_JPEG_QUALITY: "85" # a higher value increases the quality and file size of JPEG images and thumbnails (25-100)
+ PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
+ PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
+ PHOTOPRISM_DATABASE_DRIVER: "sqlite" # SQLite is an embedded database that doesn't require a server
+ PHOTOPRISM_SITE_CAPTION: "Photos App"
+ PHOTOPRISM_SITE_DESCRIPTION: "Some of our pics" # meta site description
+ PHOTOPRISM_SITE_AUTHOR: "Kumar" # meta site author
+ PHOTOPRISM_INIT: "gpu tensorflow"
+ working_dir: "/photoprism"
+ networks:
+ - name: '{{ photoprism_docker_network_name }}'
+ ports:
+ - '{{ photoprism_host_port }}:2342'
+ volumes:
+ - '{{ photoprism_pics_root_dir }}:/photoprism/originals:ro'
+ - '{{ photoprism_data_dir }}:/photoprism/storage'
+ restart_policy: "unless-stopped"
diff --git a/roles/plex/defaults/main.yaml b/roles/plex/defaults/main.yaml
new file mode 100644
index 0000000..57e1fc7
--- /dev/null
+++ b/roles/plex/defaults/main.yaml
@@ -0,0 +1,4 @@
+# Default Values
+---
+
+plex_docker_network_name: 'plex_network'
diff --git a/roles/plex/handlers/main.yaml b/roles/plex/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/plex/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/plex/tasks/main.yaml b/roles/plex/tasks/main.yaml
new file mode 100644
index 0000000..7cbb531
--- /dev/null
+++ b/roles/plex/tasks/main.yaml
@@ -0,0 +1,22 @@
+---
+
+- name: 'Install Plex'
+ community.docker.docker_container:
+ name: 'plex'
+ image: 'lscr.io/linuxserver/plex:latest'
+ pull: true
+ state: 'started'
+ recreate: false
+ env:
+ PUID: "1001"
+ PGID: "1001"
+ VERSION: "docker"
+ PLEX_CLAIM: "{{ plex_claim }}"
+ network_mode: 'host' # will use 32400
+ volumes:
+ - '{{ plex_library_dir }}:/config'
+ - '{{ plex_tv_dir }}:/tv'
+ - '{{ plex_mov_dir }}:/movies'
+ - '{{ plex_pic_dir }}:/pics'
+ - '{{ plex_music_dir }}:/music'
+ restart_policy: "unless-stopped"
diff --git a/roles/transmission/tasks/main.yaml b/roles/transmission/tasks/main.yaml
index 91d3971..229184f 100644
--- a/roles/transmission/tasks/main.yaml
+++ b/roles/transmission/tasks/main.yaml
@@ -14,8 +14,8 @@
state: 'started'
recreate: true
env:
- "PUID": '1000'
- "PGID": '1000'
+ "PUID": '1001'
+ "PGID": '1001'
"TZ": 'America/Toronto'
USER: '{{ transmission_user }}'
PASS: '{{ transmission_password }}'
diff --git a/roles/website/tasks/main.yaml b/roles/website/tasks/main.yaml
index 66bc955..07780b5 100644
--- a/roles/website/tasks/main.yaml
+++ b/roles/website/tasks/main.yaml
@@ -2,11 +2,19 @@
- name: 'Install git'
become: true
- become_method: 'doas'
+ # become_method: 'doas'
package:
name: 'git'
state: 'present'
+- name: 'Remove domain level dir'
+ file:
+ path: '{{ sites_data_root }}/{{ item.name }}/html'
+ state: 'absent'
+ when: 'item.git_url is defined'
+ loop: '{{ websites }}'
+
+
- name: 'Create domain level dir'
file:
path: '{{ sites_data_root }}/{{ item.name }}/html'
@@ -33,3 +41,10 @@
remote_src: true
when: 'item.git_url is defined'
loop: '{{ websites }}'
+
+- name: 'Remove git checkout'
+ file:
+ path: '/home/{{ ansible_user }}/{{ item.name }}'
+ state: 'absent'
+ when: 'item.git_url is defined'
+ loop: '{{ websites }}'
diff --git a/roles/wireguard/tasks/main.yaml b/roles/wireguard/tasks/main.yaml
index c3f0942..aa8b20d 100644
--- a/roles/wireguard/tasks/main.yaml
+++ b/roles/wireguard/tasks/main.yaml
@@ -9,6 +9,7 @@
loop:
- 'iptables'
- 'wireguard-tools'
+ - 'libqrencode'
- name: 'Enable iptables'
service: