aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKumar <kumar@kumardamani.xyz>2021-11-23 14:59:08 +0000
committerKumar Damani <me@kumardamani.net>2022-03-25 19:45:25 +0000
commita857eb82ec9c4a79ad5e41462e2ab82c2660982e (patch)
tree9ca51ddfb551322bd4d2fa3f949fa8898032632d
initial commit
-rw-r--r--.gitignore6
-rw-r--r--.gitmodules0
-rw-r--r--README.md75
-rw-r--r--ansible.cfg13
-rw-r--r--architecture.pngbin0 -> 74525 bytes
-rw-r--r--architecture.xml1
-rw-r--r--group_vars/all/vars.yaml27
-rw-r--r--group_vars/all/vault.example16
-rw-r--r--hosts.example5
-rw-r--r--playbooks/deploy.yaml226
-rw-r--r--playbooks/vps.yaml26
-rw-r--r--requirements.yml12
-rw-r--r--roles/bitwarden/defaults/main.yaml6
-rw-r--r--roles/bitwarden/handlers/main.yaml2
-rw-r--r--roles/bitwarden/tasks/main.yaml17
-rw-r--r--roles/ddclient/defaults/main.yaml2
-rw-r--r--roles/ddclient/handlers/main.yaml7
-rw-r--r--roles/ddclient/tasks/main.yaml22
-rw-r--r--roles/ddclient/templates/ddclient.conf.j29
-rw-r--r--roles/jellyfin/README.md34
-rw-r--r--roles/jellyfin/defaults/main.yaml2
-rw-r--r--roles/jellyfin/handlers/main.yaml7
-rw-r--r--roles/jellyfin/tasks/main.yaml45
-rw-r--r--roles/navidrome/README.md31
-rw-r--r--roles/navidrome/defaults/main.yaml6
-rw-r--r--roles/navidrome/handlers/main.yaml7
-rw-r--r--roles/navidrome/tasks/main.yaml34
-rw-r--r--roles/navidrome/templates/docker-compose.yaml.j218
-rw-r--r--roles/nextcloud/defaults/main.yaml17
-rw-r--r--roles/nextcloud/handlers/main.yaml7
-rw-r--r--roles/nextcloud/tasks/main.yaml63
-rw-r--r--roles/nginx/defaults/main.yaml7
-rw-r--r--roles/nginx/handlers/main.yaml7
-rw-r--r--roles/nginx/tasks/main.yaml67
-rw-r--r--roles/nginx/templates/app.nginx.conf.j221
-rw-r--r--roles/nginx/templates/http.nginx.conf.j224
-rw-r--r--roles/rpi_exporter/defaults/main.yaml3
-rw-r--r--roles/rpi_exporter/tasks/main.yaml45
-rw-r--r--roles/samba/defaults/main.yaml4
-rw-r--r--roles/samba/tasks/main.yaml29
-rw-r--r--roles/samba/templates/smb.conf6
-rw-r--r--roles/seafile_docker/defaults/main.yaml14
-rw-r--r--roles/seafile_docker/files/ccnet.conf2
-rw-r--r--roles/seafile_docker/files/seafdav.conf6
-rw-r--r--roles/seafile_docker/files/seafile.service14
-rw-r--r--roles/seafile_docker/files/seahub.service13
-rw-r--r--roles/seafile_docker/tasks/main.yaml49
-rw-r--r--roles/seafile_docker/templates/docker-compose.yaml.j261
-rw-r--r--roles/seafile_non_docker/README.md60
-rw-r--r--roles/seafile_non_docker/defaults/main.yaml10
-rw-r--r--roles/seafile_non_docker/handlers/main.yaml19
-rw-r--r--roles/seafile_non_docker/tasks/main.yaml220
-rw-r--r--roles/seafile_non_docker/templates/ccnet.conf.j22
-rw-r--r--roles/seafile_non_docker/templates/seafdav.conf.j26
-rw-r--r--roles/seafile_non_docker/templates/seafile.service.j214
-rw-r--r--roles/seafile_non_docker/templates/seahub.service.j214
-rw-r--r--roles/website/defaults/main.yaml4
-rw-r--r--roles/website/tasks/main.yaml24
-rw-r--r--roles/wireguard/defaults/main.yaml2
-rw-r--r--roles/wireguard/handlers/main.yaml7
-rw-r--r--roles/wireguard/tasks/main.yaml38
-rw-r--r--roles/wireguard/templates/wg0.conf.j217
-rw-r--r--roles/wireguard_client/defaults/main.yaml2
-rw-r--r--roles/wireguard_client/handlers/main.yaml7
-rw-r--r--roles/wireguard_client/tasks/main.yaml36
-rw-r--r--roles/wireguard_client/templates/wg0.conf.j216
-rw-r--r--vaultid.example1
67 files changed, 1614 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f428a1f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+roles/*.*
+collections/
+hosts
+vault
+vaultid
+migration/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.gitmodules
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..10a7261
--- /dev/null
+++ b/README.md
@@ -0,0 +1,75 @@
+# My VPS Setup
+
+**This is still very much un-stable, and very much a work-in-progress.**
+
+So I decided to migrate *most* of my remote VPS to a self-hosted private server. There are 3 reasons for this:
+1. Cost savings. VPS SSD storage can get quite [expensive](https://racknerd.com/kvm-vps) as your storage demands increase. Meanwhile I have a few SSDs lying my house around not being utilized.
+2. Learning experience. There are many parts of the self-hosting stack that I'm not familiar with, and I am hoping to get more familiar with them as part of this exercise.
+3. I want to be able to be to reproduce all of the tooling I use, as quickly as possible in a "doomsday" scenario, so I need it automated.
+
+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: | 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/) |
+
+> 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.
+
+## Architecture
+![Architecture](./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.
+
+### Tradeoffs
+* I haven't factored in the cost of the hardware I'm putting to use or the cost of future replacement hardware, or the utility (power) cost of running these locally.
+* VPS service providers have certain uptime guarantees that factors into their end-user pricing, especially with extra storage. No such guarantees exist with this setup, but things can be done to get most of the way there (which has its own time/effort, and equipment costs).
+* Maintenance of these self-hosted services. But the way I see it, having it automated allows me to 1. minimize the time/effort spent on maintenance, and 2. to potentially turn this into a profitable venture for a growing privacy-minded audience - which at ~$13/mo would be a lot less profitable.
+
+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.
+
+## Monitoring
+![Dashboard](https://grafana.com/api/dashboards/15980/images/11892/image)
+You can get this dashboard [here](https://grafana.com/grafana/dashboards/15980).
+
+## Install
+1. Fork this repo.
+2. Clone you fork with `git clone`
+3. Change directory to this repo `cd vps`.
+4. Setup repo by running all of the following:
+```
+python3 -m venv ~/venv/vps
+source $HOME/venv/vps/bin/activate
+pip install --upgrade pip
+pip install 'ansible<2.10' 'jmespath'
+ansible-galaxy install -r requirements.yml
+ansible-galaxy collection install -r requirements.yml
+cp -a vaultid.example vaultid
+cp -a hosts.example hosts
+cp -a group_vars/all/vault.example group_vars/all/vault
+```
+
+## Develop
+1. Modify the [playbooks](./playbooks/) per your needs.
+2. Modify the vault per your needs: `ansible-vault edit group_vars/all/vault --vault-id vaultid`.
+3. Modify the [hosts](./hosts/) file per your needs.
+4. Modify the [vars](./group_vars/all/vars.yaml/) file per your needs.
+
+## Execute
+```
+ansible-playbook -i hosts playbooks/deploy.yaml --vault-id vaultid
+ansible-playbook -i hosts playbooks/vps.yaml --vault-id vaultid
+```
+
+## Future Plans
+1. Simplify install.
+2. Documentation for each role.
+3. Backups.
+4. Redundancy.
diff --git a/ansible.cfg b/ansible.cfg
new file mode 100644
index 0000000..006991b
--- /dev/null
+++ b/ansible.cfg
@@ -0,0 +1,13 @@
+[defaults]
+roles_path = ./roles
+playbook_dir = ./playbooks
+collections_paths = ./collections
+callback_whitelist = profile_tasks
+host_key_checking = False
+interpreter_python = /usr/bin/python3
+#strategy_plugins = ~/venvs/ansible/lib/python3.9/site-packages/ansible_mitogen/plugins/strategy
+#strategy = mitogen_linear
+
+
+[privilege_escalation]
+become_method=sudo
diff --git a/architecture.png b/architecture.png
new file mode 100644
index 0000000..e7a092d
--- /dev/null
+++ b/architecture.png
Binary files differ
diff --git a/architecture.xml b/architecture.xml
new file mode 100644
index 0000000..6a254c4
--- /dev/null
+++ b/architecture.xml
@@ -0,0 +1 @@
+<mxfile host="Electron" modified="2022-03-25T17:32:58.796Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.1.2 Chrome/96.0.4664.55 Electron/16.0.5 Safari/537.36" etag="ZWYLZcLEWb1IzxvfEjyp" version="16.1.2" type="device"><diagram id="7WZ78P3QGKG2k_Q4Ax3o" name="Page-1">7Vxbb+I6EP41kc55aJX75bEtvZxqz6otUs+efVkZYpJsQ8wmpkB//drgQMiYkm6BGLXSaptMHCf5vpnxeMZGsy6G0+scjeJ/SYhTzdTDqWZ1NNM0bNPU+D89nC0kpmN6C0mUJ6FotRJ0kxcshLqQjpMQF2sNKSEpTUbrwj7JMtynazKU52Sy3mxA0vWnjlCEgaDbRymU/peENBZSww1WF25wEsXi0X75fUNUNhZfUsQoJJOKyLrUrIucELo4Gk4vcMrRK3FZ3He14eryxXKc0SY3JMl9ej35ldwk9rfH6Yz27O/2iejlGaVj8cGPd13xvnRWgpCTcRZi3o+hWeeTOKG4O0J9fnXCeGeymA5TcfkZ5zRhAJ6lSZQxGSW8AXzb8tGsOZ5WROLtrzEZYprPWBNx1XcEkkKXTgzbdhaSyYoaXzSKK6R4ohkSyhAt+17hxQ4EZHL4XibRw4N3/fUkMrzH2+e7h+e75MQGUOGQqY84JTmNSUQylF6upOcrMHV2tmrzhXCg5hD+xJTOhC2gMSXrADME89k3fv+pU57+L7qbn3Sma2czcVZQlNMzbhNMkJEMl7KrhH+1uCOstWCSyvWNNBZknPfxK1AJR8CeF2G6XSM5jq8qRY5TRJPndTPdOcEmsI9/MorzjH0CYD5NmVOagxqjERf2UzIOtxvMLkzDqpuGU9pBxTQMU2IbZbvdQ+e2YRwDklFx0Whf6S2o9HKsvF1rvbj1jiTsnZd64pW3LPVEt2v8L95V3FdTgeWLvEMr/E+taKwVwWG0wtANoBbuYdXCAn72hvXJJF2cMzfIDv56uEv+VjQycY26+7UM6H4dS+J+jWBf/tcDkE6SHEdjlIea6abs+ec9Bqwb8aNCwLxxTNsCLSpGi+h7kEw5HcDidoGyW0fZlAxyjgRkZ18Ylywf1ptt815GJQZJk+zpXc7KCBp6q50PYe9ixn+L9vfTBGevRXQKaL/vOjXtt004+zmo9i916AOP5eXIudU8DFMp+ygTM5/cNeHOUos765O75tzZanHXSsroWLlzlOKufO9KUJFFSTZVPHCwbOXCZphWQ6MRE0gCCpWg9ECabTl9aw1KOHNeQJmpDaWvqwelDaCc4F7BoFJfM31PPTidV+BUXDsDWz04XQBnGGaF2jgaOtDL1gefsghSAbJAwx5SG8kgUA9ImGH8QvqI33fT6QA435Sq3cfg7Qen9RTKMs1dwdAzIIbW3jAMNmLY7aqHoe9vLBRUEZRo4d4QtKA5n+MByTEAj30jrSdSc/KEL0hKcm05yxmwKU5NhETBoI958VdSSRgmYZhu8hTrs7cqK3Z5Ll5SsqbjD1xujSHXhgy5h2SofH57U1679Smv1XTKa6mVJrTglFfJBRCmVXftrg7V/rALIGzvU+9Ldd6q97arlt7DDIW6C+NAVsJ2JKHhYavPduu1IQWUv+lCD0utHLVtfnLXnDu1ctR267WhY+JOrUHHbr02dEzcqbXexIJ5+COoDZlOvTZkmy1nlSyYhT+K2pABdidYVttQwgz8UdSGlltmFIISZt+PpjZkgtRx+3BKFqceS23IAstQ24cTrnY8G1DJet4PkgI1QHG5/SQodCDzhIKSaX4TrrSWrGffV5rfGAY/7JdvnXvvxXu86d+lUx9LNipCLwGC0gpK6xq4EaOt0WRDE3/njgzHr8dlbhmplZ0sImmwIaNBV7pe62p3ezuiEy//PinQz87k9jtyH7uDX7eSvR2AuqpDKrfJcp5CVMRL0pq7oDL/PJxGfFvy6WIjsLn4y7udb4k8dQN+zHHiRJxnhPZj8aycUMYfybbpyxuGDbCkQGZT+/JJUmJgpK1d6VpwpQW+5l82GDyaM5LjInlBvXlXHNARV7b59zjnmtPhfbGJaSHc2BvGpYr3s3ZUS1jVNCtVzmZL7eub6XZGFYzkS6oCzYfx50ehygbVTtNomSk4zn9Ebxf40IQO5+3Mi9unH8+T4mU07lyTbNrTu/eSCOJsftNo3EuTPjvofOXxGN8zn+CCXxADKSXsP1n1R0kr28CUhM/NqzzAhNGWrDUydQl75r7i53IbGqAvpnTEeuR/OGk0R4PBnM6IzFmkMQv9onj+7ssNYDodZxlOTxtQuo57iAdoPN89dsA50o5s0oG0SpzlsiR4EKM0t3vLQ2+o7KeoKJgGbd1TCecbmmwO8Wd5cDGj375FIpBz/s4JiGS3oV7TgaYTENevdwWWXOxuAiJVMjgB+fT8m1YSgN8RkSyj2ZXnZ6ernz9akL36FSnr8jc=</diagram></mxfile> \ No newline at end of file
diff --git a/group_vars/all/vars.yaml b/group_vars/all/vars.yaml
new file mode 100644
index 0000000..f5c2645
--- /dev/null
+++ b/group_vars/all/vars.yaml
@@ -0,0 +1,27 @@
+---
+
+# 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.
+apps_conf_map:
+ nextcloud:
+ port: 31900
+ access_domain: 'files.{{ apps_domain }}'
+ prometheus:
+ port: 9090
+ access_domain: 'metrics.{{ apps_domain }}'
+ bitwarden:
+ port: 31901
+ access_domain: 'vault.{{ apps_domain }}'
+
+# list all static websites you plan to host here.
+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.example b/group_vars/all/vault.example
new file mode 100644
index 0000000..8dc5545
--- /dev/null
+++ b/group_vars/all/vault.example
@@ -0,0 +1,16 @@
+$ANSIBLE_VAULT;1.1;AES256
+33646338366162383266356237656436666231633439663936303263333261386436653331656330
+3666623261626263366232646631633763303363356239640a656165643764393864353137323037
+37343237306361633834366236353539376162373262373161656236616533323633376230666239
+6337306438373536650a373330386330346665643936393839626561383933363031626564343066
+64363335613139323735653230633262396533623065356439356533663631613033356635366163
+65613632623933313734643765373966633231633838306339323461653533386134653239623966
+37393133613836653232613130366535616435333130333332313832363636623066373635626561
+39313238353264336435313735646363326330613538613664363436323362363730663433363833
+61323535306665316664643231306665663665626331356330623265353062353262356661653137
+66643565653934626161326261373934323162386562303265393834393238373566313566383164
+35343438353363326439613462343237303735346134613061323531663534346531356465323964
+61353630373336333131353135623165633365323135383932326562653135633566346165623137
+33306266326238303130393332306463363866656239666130313665333466653631626564346534
+33393434366135633039363935383333363461333835333933346536396364636138356266623965
+373233303165616238303463666635396164
diff --git a/hosts.example b/hosts.example
new file mode 100644
index 0000000..03562a3
--- /dev/null
+++ b/hosts.example
@@ -0,0 +1,5 @@
+[vps]
+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=
diff --git a/playbooks/deploy.yaml b/playbooks/deploy.yaml
new file mode 100644
index 0000000..9ba8c3b
--- /dev/null
+++ b/playbooks/deploy.yaml
@@ -0,0 +1,226 @@
+# Usage:
+# ansible-playbook -i hosts playbooks/deploy.yaml --vault-id vaultid --tags base
+#
+# Tags:
+# base, ddclient, wireguard, nginx, website, samba
+# nextcloud, monitoring (these all depend on the nginx tag)
+#
+# Install:
+# git submodule update --remote --merge
+# python3 -m venv ~/venv/ansible
+# source $HOME/venv/ansible/bin/activate
+# pip install --upgrade pip
+# pip install 'ansible<2.10' 'jmespath'
+# 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.
+---
+
+
+- hosts: compute
+ gather_facts: false
+ tags: 'ddclient'
+ become: true
+ roles:
+ - role: ddclient
+ vars:
+ ddclient_proto: 'freedns'
+ ddclient_user: '{{ vault_ddclient_user }}'
+ ddclient_password: '{{ vault_ddclient_password }}'
+ ddclient_domain: '{{ vpn_domain }}'
+
+- hosts: compute
+ gather_facts: false
+ tags: 'wireguard'
+ become: true
+ 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_peers:
+ - peer_ip: '192.168.10.2/32' # my phone
+ peer_key: '/mFv6y9QA8dhX/A9fFn+mzg/SZq4BZPeNofm1w754y8='
+ - peer_ip: '192.168.10.3/32' # personal laptop
+ peer_key: '6+t6FbEHSAOuzBtQwb0bDqfFa5Kvfkb2QIUGpRKA5Eg='
+ - peer_ip: '192.168.10.4/32' # vps
+ peer_key: 'oz2jxeSUWD4r5g3y7XuSItqSiqOOJz8vulYYVXAsKS8='
+
+- hosts: compute
+ gather_facts: false
+ tags: 'nginx'
+ become: true
+ roles:
+ - role: nginx
+ 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") }}'
+
+- hosts: compute
+ gather_facts: false
+ tags: 'website'
+ become: true
+ roles:
+ - role: website
+ vars:
+ websites: '{{ nginx_websites }}'
+ git_user: '{{ vault_git_user }}'
+ git_pass: '{{ vault_git_password }}'
+
+- hosts: compute
+ gather_facts: false
+ tags: 'nextcloud'
+ become: true
+ 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_postgres_password: '{{ vault_nextcloud_postgres_password }}'
+
+- hosts: compute
+ gather_facts: false
+ tags: 'bitwarden'
+ become: true
+ roles:
+ - role: bitwarden
+ vars:
+ bitwarden_host_port: '{{ apps_conf_map["bitwarden"]["port"] }}'
+ bitwarden_data_dir: '{{ data_vol_hdd }}/bitwarden'
+
+# Access: http://art-jr/data
+- hosts: compute
+ gather_facts: false
+ tags: 'samba'
+ become: true
+ roles:
+ - role: samba
+ vars:
+ samba_user: '{{ vault_samba_user }}'
+ samba_user_pass: '{{ vault_samba_password }}'
+
+- hosts: compute
+ become: true
+ tags: 'monitoring'
+ roles:
+ - role: 'cloudalchemy.node_exporter'
+ 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'
+
+- hosts: compute
+ become: true
+ tags: 'base'
+ roles:
+ - role: geerlingguy.pip
+ 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'
diff --git a/playbooks/vps.yaml b/playbooks/vps.yaml
new file mode 100644
index 0000000..67780d2
--- /dev/null
+++ b/playbooks/vps.yaml
@@ -0,0 +1,26 @@
+# Usage:
+# ansible-playbook -i hosts playbooks/vps.yaml --vault-id vaultid
+#
+# Install:
+# ansible-galaxy install -r requirements.yml
+# ansible-galaxy role install -r requirements.yml
+#
+---
+
+- hosts: vps
+ gather_facts: false
+ become: true
+ pre_tasks:
+ - name: 'Set python3 as default python' # noqa no-changed-when
+ command: 'update-alternatives --install /bin/python python /bin/python3 3'
+ roles:
+ - role: wireguard_client
+ vars:
+ wireguard_client_server_pub_key: 'iwsriL3AUn4dgKfsSNgJtj/G808k4jXvSC+mM70YnAw='
+ wireguard_client_server_endpoint: 'kdvpn.crabdance.com'
+ wireguard_client_server_allowed_ips: '192.168.10.0/24'
+ wireguard_client_peer_ip: '192.168.10.4/24'
+ wireguard_client_server_listen_port: 51820
+ wireguard_client_port_forwards:
+ - 80 # webserver
+ - 443 # webserver
diff --git a/requirements.yml b/requirements.yml
new file mode 100644
index 0000000..8aca51c
--- /dev/null
+++ b/requirements.yml
@@ -0,0 +1,12 @@
+---
+
+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/defaults/main.yaml b/roles/bitwarden/defaults/main.yaml
new file mode 100644
index 0000000..cc46411
--- /dev/null
+++ b/roles/bitwarden/defaults/main.yaml
@@ -0,0 +1,6 @@
+# Default Values
+---
+
+bitwarden_data_dir: ''
+bitwarden_host_port: ''
+bitwarden_container_name: 'bitwarden'
diff --git a/roles/bitwarden/handlers/main.yaml b/roles/bitwarden/handlers/main.yaml
new file mode 100644
index 0000000..cd21505
--- /dev/null
+++ b/roles/bitwarden/handlers/main.yaml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/bitwarden/tasks/main.yaml b/roles/bitwarden/tasks/main.yaml
new file mode 100644
index 0000000..5fd0ed4
--- /dev/null
+++ b/roles/bitwarden/tasks/main.yaml
@@ -0,0 +1,17 @@
+---
+
+- name: 'Make sure the Vaultwarden container is created and running'
+ docker_container:
+ name: '{{ bitwarden_container_name }}'
+ image: 'vaultwarden/server'
+ pull: true
+ state: 'started'
+ env:
+ WEBSOCKET_ENABLED: 'true'
+ INVITATIONS_ALLOWED: 'true'
+ SIGNUPS_ALLOWED: 'false'
+ volumes:
+ - "{{ bitwarden_data_dir }}:/data"
+ ports:
+ - '{{ bitwarden_host_port }}:80'
+ restart_policy: unless-stopped
diff --git a/roles/ddclient/defaults/main.yaml b/roles/ddclient/defaults/main.yaml
new file mode 100644
index 0000000..9a163d4
--- /dev/null
+++ b/roles/ddclient/defaults/main.yaml
@@ -0,0 +1,2 @@
+# Default Values
+---
diff --git a/roles/ddclient/handlers/main.yaml b/roles/ddclient/handlers/main.yaml
new file mode 100644
index 0000000..be19365
--- /dev/null
+++ b/roles/ddclient/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- name: 'Restart ddclient'
+ systemd:
+ name: 'ddclient'
+ state: 'restarted'
+ listen: 'restart ddclient'
diff --git a/roles/ddclient/tasks/main.yaml b/roles/ddclient/tasks/main.yaml
new file mode 100644
index 0000000..8deffc2
--- /dev/null
+++ b/roles/ddclient/tasks/main.yaml
@@ -0,0 +1,22 @@
+# https://notthebe.ee/raspi.html
+---
+
+- name: 'Install required apt packages'
+ apt:
+ name:
+ - 'ddclient'
+ state: 'present'
+ update_cache: true
+
+- name: 'Update ddclient conf'
+ template:
+ dest: '/etc/ddclient.conf'
+ src: 'ddclient.conf.j2'
+ mode: '644'
+ notify: 'restart ddclient'
+
+- name: 'Start ddclient'
+ systemd:
+ name: 'ddclient'
+ state: 'started'
+ enabled: true
diff --git a/roles/ddclient/templates/ddclient.conf.j2 b/roles/ddclient/templates/ddclient.conf.j2
new file mode 100644
index 0000000..99dab47
--- /dev/null
+++ b/roles/ddclient/templates/ddclient.conf.j2
@@ -0,0 +1,9 @@
+# {{ ansible_managed }}
+#
+# /etc/ddclient.conf
+
+protocol={{ ddclient_proto }} \
+use=web, web=https://freedns.afraid.org/dynamic/check.php \
+login={{ ddclient_user }} \
+password='{{ ddclient_password }}' \
+{{ ddclient_domain }}
diff --git a/roles/jellyfin/README.md b/roles/jellyfin/README.md
new file mode 100644
index 0000000..79d061e
--- /dev/null
+++ b/roles/jellyfin/README.md
@@ -0,0 +1,34 @@
+# Ansible - Jellyfin
+
+## Example Playbook
+```
+# Direct Access: http://art-jr:8096/
+# Domain Access: http://kumardamani.xyz/media
+# Create login from GUI.
+# While doing initial setup set the base url to '/media' in Networking settings.
+- hosts: compute
+ gather_facts: false
+ tags: 'jellyfin'
+ become: true
+ roles:
+ - role: jellyfin
+ vars:
+ jellyfin_domain: 'kumardamani.xyz'
+```
+
+## Nginx Conf
+```
+ location /media/ {
+ proxy_pass http://127.0.0.1:8096/media/;
+ proxy_pass_request_headers on;
+ 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-Proto $scheme;
+ proxy_set_header X-Forwarded-Host $http_host;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $http_connection;
+ # Disable buffering when the nginx proxy gets very resource heavy upon streaming
+ proxy_buffering off;
+ }
+```
diff --git a/roles/jellyfin/defaults/main.yaml b/roles/jellyfin/defaults/main.yaml
new file mode 100644
index 0000000..9a163d4
--- /dev/null
+++ b/roles/jellyfin/defaults/main.yaml
@@ -0,0 +1,2 @@
+# Default Values
+---
diff --git a/roles/jellyfin/handlers/main.yaml b/roles/jellyfin/handlers/main.yaml
new file mode 100644
index 0000000..7613b54
--- /dev/null
+++ b/roles/jellyfin/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- name: 'Restart nginx'
+ systemd:
+ name: 'nginx'
+ state: 'restarted'
+ listen: 'nginx_restart'
diff --git a/roles/jellyfin/tasks/main.yaml b/roles/jellyfin/tasks/main.yaml
new file mode 100644
index 0000000..647c1f1
--- /dev/null
+++ b/roles/jellyfin/tasks/main.yaml
@@ -0,0 +1,45 @@
+# https://jellyfin.org/docs/general/administration/installing.html
+# https://jellyfin.org/docs/general/networking/nginx.html
+---
+
+- name: 'Install required apt packages'
+ apt:
+ name:
+ - 'apt-transport-https'
+ - 'gnupg'
+ - 'lsb-release'
+ state: 'present'
+ update_cache: true
+
+- name: Add an Apt signing key, uses whichever key is at the URL
+ apt_key:
+ url: https://repo.jellyfin.org/debian/jellyfin_team.gpg.key
+ state: present
+
+- name: Add specified repository into sources list
+ apt_repository:
+ repo: deb [arch=armhf] https://repo.jellyfin.org/debian bullseye main
+ state: present
+ filename: jellyfin
+
+- name: 'Install Jellyfin'
+ apt:
+ name:
+ - 'jellyfin'
+ state: 'present'
+ update_cache: true
+
+- name: 'Add jellyfin user to video group'
+ user:
+ name: 'jellyfin'
+ groups: 'video'
+ append: true
+ state: 'present'
+
+- name: 'Start Jellyfin'
+ systemd:
+ name: '{{ item }}'
+ state: 'started'
+ enabled: true
+ loop:
+ - 'jellyfin'
diff --git a/roles/navidrome/README.md b/roles/navidrome/README.md
new file mode 100644
index 0000000..755d428
--- /dev/null
+++ b/roles/navidrome/README.md
@@ -0,0 +1,31 @@
+# Ansible - Navidrome
+
+## Example Playbook
+```
+# Access: http://art-jr:4533/music/
+# Domain Access: http://kumardamani.xyz/music
+# Create login from GUI
+- hosts: compute
+ gather_facts: false
+ tags: 'navidrome'
+ become: true
+ roles:
+ - role: navidrome
+ vars:
+ navidrome_domain: 'kumardamani.xyz'
+ navidrome_data_root: '{{ data_vol_ssd }}/music'
+```
+
+## Nginx Conf
+```
+ location /music/ {
+ proxy_pass http://127.0.0.1:4533/music/;
+ 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-Proto $scheme;
+ proxy_set_header X-Forwarded-Protocol $scheme;
+ proxy_set_header X-Forwarded-Host $http_host;
+ proxy_buffering off;
+ }
+```
diff --git a/roles/navidrome/defaults/main.yaml b/roles/navidrome/defaults/main.yaml
new file mode 100644
index 0000000..a7c9858
--- /dev/null
+++ b/roles/navidrome/defaults/main.yaml
@@ -0,0 +1,6 @@
+# Default Values
+---
+
+navidrome_home_root: '/opt/navidrome'
+navidrome_home_db: '/opt/navidrome/db'
+navidrome_data_root: ''
diff --git a/roles/navidrome/handlers/main.yaml b/roles/navidrome/handlers/main.yaml
new file mode 100644
index 0000000..7613b54
--- /dev/null
+++ b/roles/navidrome/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- name: 'Restart nginx'
+ systemd:
+ name: 'nginx'
+ state: 'restarted'
+ listen: 'nginx_restart'
diff --git a/roles/navidrome/tasks/main.yaml b/roles/navidrome/tasks/main.yaml
new file mode 100644
index 0000000..72982c2
--- /dev/null
+++ b/roles/navidrome/tasks/main.yaml
@@ -0,0 +1,34 @@
+# https://www.navidrome.org/docs/installation/docker/
+---
+
+- name: 'Ensure required vars exist'
+ assert:
+ that: item | mandatory
+ loop:
+ - '{{ navidrome_data_root }}'
+ no_log: true
+
+- name: 'Ensure Navidrome dirs exists'
+ file:
+ path: '{{ item }}'
+ state: 'directory'
+ owner: '{{ ansible_user }}'
+ group: '{{ ansible_user }}'
+ mode: '755'
+ loop:
+ - '{{ navidrome_home_root }}'
+ - '{{ navidrome_home_db }}'
+ - '{{ navidrome_data_root }}'
+
+- name: 'Copy Navidrome docker compose config to home dir'
+ become_user: '{{ ansible_user }}'
+ template:
+ dest: '{{ navidrome_home_root }}/docker-compose.yaml'
+ src: 'docker-compose.yaml.j2'
+ mode: '644'
+
+- name: 'Create and start services'
+ become_user: '{{ ansible_user }}'
+ community.docker.docker_compose:
+ project_src: '{{ navidrome_home_root }}'
+ state: 'present'
diff --git a/roles/navidrome/templates/docker-compose.yaml.j2 b/roles/navidrome/templates/docker-compose.yaml.j2
new file mode 100644
index 0000000..cc9cf59
--- /dev/null
+++ b/roles/navidrome/templates/docker-compose.yaml.j2
@@ -0,0 +1,18 @@
+version: "3"
+services:
+ navidrome:
+ image: deluan/navidrome:latest
+ user: 1000:1000
+ ports:
+ - "4533:4533"
+ restart: unless-stopped
+ environment:
+ # Optional: put your config options customization here. Examples:
+ ND_SCANSCHEDULE: 1h
+ ND_LOGLEVEL: info
+ ND_SESSIONTIMEOUT: 24h
+ ND_BASEURL: "/music"
+ volumes:
+ - "{{ navidrome_home_db }}:/data"
+ - "{{ navidrome_data_root }}:/music:ro"
+
diff --git a/roles/nextcloud/defaults/main.yaml b/roles/nextcloud/defaults/main.yaml
new file mode 100644
index 0000000..cd11c66
--- /dev/null
+++ b/roles/nextcloud/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/nextcloud/handlers/main.yaml b/roles/nextcloud/handlers/main.yaml
new file mode 100644
index 0000000..7613b54
--- /dev/null
+++ b/roles/nextcloud/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- name: 'Restart nginx'
+ systemd:
+ name: 'nginx'
+ state: 'restarted'
+ listen: 'nginx_restart'
diff --git a/roles/nextcloud/tasks/main.yaml b/roles/nextcloud/tasks/main.yaml
new file mode 100644
index 0000000..593bfa3
--- /dev/null
+++ b/roles/nextcloud/tasks/main.yaml
@@ -0,0 +1,63 @@
+# https://docs.nextcloud.com/server/19/admin_manual/configuration_server/config_sample_php_parameters.html#default-parameters
+# https://docs.nextcloud.com/server/19/admin_manual/configuration_server/caching_configuration.html#id2
+---
+
+- name: 'Create the nextcloud network'
+ community.docker.docker_network:
+ name: '{{ nextcloud_docker_network_name }}'
+
+- name: Make sure the Postgres container is created and running
+ community.docker.docker_container:
+ name: 'nextcloud-postgres'
+ 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"
+ env:
+ "PUID": '{{ nextcloud_uid }}'
+ "PGID": '{{ nextcloud_gid }}'
+ "TZ": '{{ nextcloud_tz }}'
+ "POSTGRES_DB": "{{ nextcloud_postgres_db }}"
+ "POSTGRES_USER": "{{ nextcloud_postgres_user }}"
+ "POSTGRES_PASSWORD": "{{ nextcloud_postgres_password }}"
+ volumes:
+ - '{{ nextcloud_data_root }}/postgres:/var/lib/postgresql/data'
+ restart_policy: 'unless-stopped'
+
+- name: 'Make sure the Redis container is created and running'
+ community.docker.docker_container:
+ name: 'nextcloud-redis'
+ image: 'redis:alpine'
+ pull: true
+ state: 'started'
+ restart_policy: 'unless-stopped'
+
+- name: 'Make sure the Nextcloud container is created and running'
+ community.docker.docker_container:
+ name: '{{ nextcloud_container_name }}'
+ image: 'ghcr.io/linuxserver/nextcloud:php8'
+ pull: true
+ state: 'started'
+ env:
+ "PUID": '{{ nextcloud_uid }}'
+ "PGID": '{{ nextcloud_gid }}'
+ "TZ": '{{ nextcloud_tz }}'
+ volumes:
+ - '{{ nextcloud_data_root }}/config:/config'
+ - '{{ nextcloud_data_root }}/data:/data'
+ ports:
+ - '{{ nextcloud_host_port }}:443'
+ restart_policy: unless-stopped
+
+- name: 'Add {{ nextcloud_container_name }} to the docker network'
+ community.docker.docker_network:
+ name: '{{ nextcloud_docker_network_name }}'
+ connected:
+ - '{{ nextcloud_container_name }}'
+ - '{{ nextcloud_container_name }}-postgres'
+ - '{{ nextcloud_container_name }}-redis'
+ appends: true
diff --git a/roles/nginx/defaults/main.yaml b/roles/nginx/defaults/main.yaml
new file mode 100644
index 0000000..af90628
--- /dev/null
+++ b/roles/nginx/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/handlers/main.yaml b/roles/nginx/handlers/main.yaml
new file mode 100644
index 0000000..7613b54
--- /dev/null
+++ b/roles/nginx/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- name: 'Restart nginx'
+ systemd:
+ name: 'nginx'
+ state: 'restarted'
+ listen: 'nginx_restart'
diff --git a/roles/nginx/tasks/main.yaml b/roles/nginx/tasks/main.yaml
new file mode 100644
index 0000000..91fd8a5
--- /dev/null
+++ b/roles/nginx/tasks/main.yaml
@@ -0,0 +1,67 @@
+# References
+# https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-debian-10
+
+---
+
+- name: 'Install nginx'
+ apt:
+ name:
+ - 'nginx'
+ state: 'present'
+ update_cache: true
+ notify:
+ - 'nginx_restart'
+
+- name: 'Copy the http nginx.conf files'
+ template:
+ src: 'http.nginx.conf.j2'
+ dest: '/etc/nginx/sites-available/{{ item }}'
+ mode: '644'
+ loop:
+ - 'default'
+ - 'kumardamani.xyz'
+ - 'amayastuff.com'
+ register: '_config_copy'
+ notify:
+ - 'nginx_restart'
+
+- name: 'Remove the old symbolic link'
+ file:
+ path: '/etc/nginx/sites-enabled/{{ item }}'
+ state: 'absent'
+ loop: '{{ nginx_website_domains }}'
+
+- name: 'Create a http symbolic link'
+ file:
+ src: '/etc/nginx/sites-available/{{ item }}'
+ dest: '/etc/nginx/sites-enabled/{{ item }}'
+ state: 'link'
+ loop: '{{ nginx_website_domains }}'
+
+- name: 'Check nginx config' # noqa no-changed-when
+ command: 'nginx -t'
+
+- name: 'Copy the http nginx.conf for apps'
+ template:
+ src: 'app.nginx.conf.j2'
+ dest: '/etc/nginx/sites-available/{{ item.app }}'
+ mode: '644'
+ loop: '{{ nginx_apps_confs }}'
+ notify:
+ - 'nginx_restart'
+
+- name: 'Remove the old symbolic link for apps'
+ file:
+ path: '/etc/nginx/sites-enabled/{{ item.app }}'
+ state: 'absent'
+ loop: '{{ nginx_apps_confs }}'
+
+- name: 'Create a http symbolic link for apps'
+ file:
+ src: '/etc/nginx/sites-available/{{ item.app }}'
+ dest: '/etc/nginx/sites-enabled/{{ item.app }}'
+ state: 'link'
+ loop: '{{ nginx_apps_confs }}'
+
+- name: 'Check nginx config' # noqa no-changed-when
+ command: 'nginx -t'
diff --git a/roles/nginx/templates/app.nginx.conf.j2 b/roles/nginx/templates/app.nginx.conf.j2
new file mode 100644
index 0000000..c87fe29
--- /dev/null
+++ b/roles/nginx/templates/app.nginx.conf.j2
@@ -0,0 +1,21 @@
+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 / {
+ proxy_pass http://127.0.0.1:{{ item.conf.port }};
+ 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/templates/http.nginx.conf.j2 b/roles/nginx/templates/http.nginx.conf.j2
new file mode 100644
index 0000000..2d4c61b
--- /dev/null
+++ b/roles/nginx/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/rpi_exporter/defaults/main.yaml b/roles/rpi_exporter/defaults/main.yaml
new file mode 100644
index 0000000..8a446ec
--- /dev/null
+++ b/roles/rpi_exporter/defaults/main.yaml
@@ -0,0 +1,3 @@
+# Default Values
+---
+
diff --git a/roles/rpi_exporter/tasks/main.yaml b/roles/rpi_exporter/tasks/main.yaml
new file mode 100644
index 0000000..9cf3052
--- /dev/null
+++ b/roles/rpi_exporter/tasks/main.yaml
@@ -0,0 +1,45 @@
+# https://github.com/lukasmalkmus/rpi_exporter
+---
+
+- name: 'download rpi_exporter binary package to local folder'
+ become: false
+ get_url:
+ url: "https://github.com/lukasmalkmus/rpi_exporter/releases/download/v0.8.0/rpi_exporter-0.8.0.linux-armv7.tar.gz"
+ dest: "/tmp/rpi_exporter.tar.gz"
+ register: _download_archive
+ until: _download_archive is succeeded
+ retries: 5
+ delay: 2
+ delegate_to: localhost
+ check_mode: false
+
+- name: 'unpack prometheus binaries'
+ become: false
+ unarchive:
+ src: "/tmp/rpi_exporter.tar.gz"
+ dest: "/tmp"
+ creates: "/tmp/rpi_exporter/rpi_exporter"
+ delegate_to: localhost
+ check_mode: false
+
+- name: 'propagate rpi_exporter bin'
+ copy:
+ src: "/tmp/rpi_exporter/rpi_exporter"
+ dest: "/usr/local/bin/rpi_exporter"
+ mode: 0755
+ owner: root
+ group: root
+
+- name: 'propagate rpi_exporter service'
+ copy:
+ src: "/tmp/rpi_exporter/rpi_exporter.service"
+ dest: "/etc/systemd/system/rpi_exporter.service"
+ mode: 0755
+ owner: root
+ group: root
+
+- name: 'Start rpi_exporter'
+ systemd:
+ name: 'rpi_exporter'
+ state: 'started'
+ enabled: true
diff --git a/roles/samba/defaults/main.yaml b/roles/samba/defaults/main.yaml
new file mode 100644
index 0000000..971a9c5
--- /dev/null
+++ b/roles/samba/defaults/main.yaml
@@ -0,0 +1,4 @@
+# Default Values
+---
+
+samba_user_pass: ''
diff --git a/roles/samba/tasks/main.yaml b/roles/samba/tasks/main.yaml
new file mode 100644
index 0000000..5207ac5
--- /dev/null
+++ b/roles/samba/tasks/main.yaml
@@ -0,0 +1,29 @@
+# https://pimylifeup.com/raspberry-pi-samba/
+---
+
+- name: 'Install required apt packages'
+ apt:
+ name:
+ - 'samba'
+ - 'samba-common-bin'
+ state: 'present'
+ update_cache: true
+
+- name: 'Copy conf files'
+ template:
+ src: 'smb.conf'
+ dest: '/etc/samba/smb.conf'
+ mode: '644'
+
+- name: 'Add Samba user'
+ expect:
+ command: 'sudo smbpasswd -a {{ samba_user }}'
+ responses:
+ (?i)password: "{{ samba_user_pass }}"
+
+- name: 'Restart Samba'
+ systemd:
+ name: '{{ item }}'
+ state: 'restarted'
+ loop:
+ - 'smbd'
diff --git a/roles/samba/templates/smb.conf b/roles/samba/templates/smb.conf
new file mode 100644
index 0000000..eb5839a
--- /dev/null
+++ b/roles/samba/templates/smb.conf
@@ -0,0 +1,6 @@
+[data]
+path = {{ data_vol_ssd }}
+writeable=Yes
+create mask=0777
+directory mask=0777
+public=no
diff --git a/roles/seafile_docker/defaults/main.yaml b/roles/seafile_docker/defaults/main.yaml
new file mode 100644
index 0000000..ed7cad3
--- /dev/null
+++ b/roles/seafile_docker/defaults/main.yaml
@@ -0,0 +1,14 @@
+# Default Values
+---
+
+seafile_image_repo: 'docker.seadrive.org'
+seafile_image_name: '{{ seafile_image_repo }}/seafileltd/seafile-pro-mc'
+seafile_image_tag: 'latest'
+seafile_image_user: 'seafile'
+seafile_image_password: ''
+seafile_data_root: '{{ data_vol_path }}/seafile'
+seafile_mysql_root_password: ''
+seafile_timezone: 'America/Toronto'
+seafile_admin_email: ''
+seafile_admin_password: ''
+seafile_listen_port: ''
diff --git a/roles/seafile_docker/files/ccnet.conf b/roles/seafile_docker/files/ccnet.conf
new file mode 100644
index 0000000..b1b35fd
--- /dev/null
+++ b/roles/seafile_docker/files/ccnet.conf
@@ -0,0 +1,2 @@
+[General]
+SERVICE_URL = http://{{ inventory_hostname }}/seafile
diff --git a/roles/seafile_docker/files/seafdav.conf b/roles/seafile_docker/files/seafdav.conf
new file mode 100644
index 0000000..8ce50cf
--- /dev/null
+++ b/roles/seafile_docker/files/seafdav.conf
@@ -0,0 +1,6 @@
+[WEBDAV]
+enabled = true
+port = 8080
+fastcgi = false
+host = 0.0.0.0
+share_name = /seafdav
diff --git a/roles/seafile_docker/files/seafile.service b/roles/seafile_docker/files/seafile.service
new file mode 100644
index 0000000..593ae64
--- /dev/null
+++ b/roles/seafile_docker/files/seafile.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Seafile
+After=network.target
+
+[Service]
+Type=forking
+ExecStart=/opt/seafile/seafile-server-latest/seafile.sh start
+ExecStop=/opt/seafile/seafile-server-latest/seafile.sh stop
+LimitNOFILE=infinity
+User=seafserver
+Group=seafserver
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/seafile_docker/files/seahub.service b/roles/seafile_docker/files/seahub.service
new file mode 100644
index 0000000..83afd48
--- /dev/null
+++ b/roles/seafile_docker/files/seahub.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Seahub
+After=network.target seafile.service
+
+[Service]
+Type=forking
+ExecStart=/opt/seafile/seafile-server-latest/seahub.sh start
+ExecStop=/opt/seafile/seafile-server-latest/seahub.sh stop
+User=seafserver
+Group=seafserver
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/seafile_docker/tasks/main.yaml b/roles/seafile_docker/tasks/main.yaml
new file mode 100644
index 0000000..b40e2fc
--- /dev/null
+++ b/roles/seafile_docker/tasks/main.yaml
@@ -0,0 +1,49 @@
+# https://manual.seafile.com/docker/pro-edition/deploy_seafile_pro_with_docker/
+---
+
+- name: 'Ensure required vars exist'
+ assert:
+ that: item | mandatory
+ loop:
+ - '{{ data_vol_path }}'
+ - '{{ seafile_image_repo }}'
+ - '{{ seafile_image_name }}'
+ - '{{ seafile_image_tag }}'
+ - '{{ seafile_image_user }}'
+ - '{{ seafile_image_password }}'
+ - '{{ seafile_data_root }}'
+ - '{{ seafile_mysql_root_password }}'
+ - '{{ seafile_timezone }}'
+ - '{{ seafile_admin_email }}'
+ - '{{ seafile_admin_password }}'
+ - '{{ seafile_listen_port }}'
+ no_log: true
+
+- name: 'Log into DockerHub'
+ community.docker.docker_login:
+ registry_url: '{{ seafile_image_repo }}'
+ username: '{{ seafile_image_user }}'
+ password: '{{ seafile_image_password }}'
+
+- name: 'Pull Seafile Pro image'
+ community.docker.docker_image:
+ name: '{{ seafile_image_name }}'
+ tag: '{{ seafile_image_tag }}'
+ state: 'present'
+ source: 'pull'
+
+- name: 'Ensure Seafile data dir exists'
+ file:
+ path: '{{ seafile_data_root }}'
+ state: 'directory'
+ mode: '755'
+
+- name: 'Copy Seafile docker compose config to seafile dir'
+ template:
+ dest: '{{ seafile_data_root }}/docker-compose.yaml'
+ src: 'docker-compose.yaml.j2'
+ mode: '644'
+
+- name: 'Create and start services'
+ community.docker.docker_compose:
+ project_src: '{{ seafile_data_root }}'
diff --git a/roles/seafile_docker/templates/docker-compose.yaml.j2 b/roles/seafile_docker/templates/docker-compose.yaml.j2
new file mode 100644
index 0000000..3dd34b3
--- /dev/null
+++ b/roles/seafile_docker/templates/docker-compose.yaml.j2
@@ -0,0 +1,61 @@
+version: '2.0'
+services:
+ db:
+ image: mariadb:10.5
+ container_name: seafile-mysql
+ environment:
+ - MYSQL_ROOT_PASSWORD={{ seafile_mysql_root_password }}
+ - MYSQL_LOG_CONSOLE=true
+ volumes:
+ - {{ seafile_data_root }}/seafile-mysql/db:/var/lib/mysql
+ networks:
+ - seafile-net
+
+ memcached:
+ image: memcached:1.5.6
+ container_name: seafile-memcached
+ entrypoint: memcached -m 256
+ networks:
+ - seafile-net
+
+ elasticsearch:
+ image: seafileltd/elasticsearch-with-ik:5.6.16
+ container_name: seafile-elasticsearch
+ environment:
+ - discovery.type=single-node
+ - bootstrap.memory_lock=true
+ - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ mem_limit: 2g
+ volumes:
+ - {{ seafile_data_root }}/seafile-elasticsearch/data:/usr/share/elasticsearch/data
+ networks:
+ - seafile-net
+
+ seafile:
+ image: {{ seafile_image_name }}:{{ seafile_image_tag }}
+ container_name: seafile
+ ports:
+ - "{{ seafile_listen_port }}:80"
+ volumes:
+ - {{ seafile_data_root }}/seafile-data:/shared
+ environment:
+ - DB_HOST=db
+ - DB_ROOT_PASSWD={{ seafile_mysql_root_password }}
+ - TIME_ZONE={{ seafile_timezone }}
+ - SEAFILE_ADMIN_EMAIL={{ seafile_admin_email }}
+ - SEAFILE_ADMIN_PASSWORD={{ seafile_admin_password }}
+ - SEAFILE_SERVER_LETSENCRYPT=false
+ #- SEAFILE_SERVER_HOSTNAME=example.seafile.com # Specifies your host name if https is enabled
+ depends_on:
+ - db
+ - memcached
+ - elasticsearch
+ networks:
+ - seafile-net
+
+networks:
+ seafile-net:
diff --git a/roles/seafile_non_docker/README.md b/roles/seafile_non_docker/README.md
new file mode 100644
index 0000000..e806c13
--- /dev/null
+++ b/roles/seafile_non_docker/README.md
@@ -0,0 +1,60 @@
+# Ansible - Seafile
+
+## Example Playbook
+```
+# Direct Access: http://art-jr:8000/
+# Domain Access: http://kumardamani.xyz/files
+- hosts: compute
+ gather_facts: false
+ tags: 'seafile'
+ become: true
+ roles:
+ - role: seafile_non_docker
+ vars:
+ seafile_user_email: 'kumar@kumardamani.xyz'
+ seafile_user_password: '{{ vault_seafile_user_password }}'
+ seafile_domain: 'kumardamani.xyz'
+ seafile_data_dir: '{{ data_vol_hdd }}/seafile'
+```
+
+## Nginx Conf
+```
+ location /files/ {
+ proxy_pass http://127.0.0.1:8000;
+ 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;
+ # used for view/edit office file via Office Online Server
+ client_max_body_size 0;
+ error_log /var/log/nginx/seahub.error.log;
+ }
+ location /seafhttp/ {
+ rewrite ^/seafhttp(.*)$ $1 break;
+ proxy_pass http://127.0.0.1:8082;
+ client_max_body_size 0;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_connect_timeout 36000s;
+ proxy_read_timeout 36000s;
+ proxy_send_timeout 36000s;
+ send_timeout 36000s;
+ error_log /var/log/nginx/seafhttp.error.log;
+ }
+ location /seafmedia/ {
+ rewrite ^/seafmedia(.*)$ /media$1 break;
+ root /opt/seafile/seafile-server-latest/seahub;
+ }
+ location /seafdav/ {
+ proxy_pass http://127.0.0.1:8080;
+ 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 $scheme;
+ proxy_read_timeout 1200s;
+ client_max_body_size 0;
+ error_log /var/log/nginx/seafdav.error.log;
+ }
+```
diff --git a/roles/seafile_non_docker/defaults/main.yaml b/roles/seafile_non_docker/defaults/main.yaml
new file mode 100644
index 0000000..9df3048
--- /dev/null
+++ b/roles/seafile_non_docker/defaults/main.yaml
@@ -0,0 +1,10 @@
+# Default Values
+---
+
+# https://github.com/haiwen/seafile-rpi/releases
+seafile_version: '8.0.7'
+seafile_download_url: 'https://github.com/haiwen/seafile-rpi/releases/download/v{{ seafile_version }}/seafile-server-{{ seafile_version }}-buster-armv7l.tar.gz'
+
+seafile_install_dir: '/opt/seafile'
+seafile_data_dir: ''
+seafile_user_grp: '{{ ansible_user }}'
diff --git a/roles/seafile_non_docker/handlers/main.yaml b/roles/seafile_non_docker/handlers/main.yaml
new file mode 100644
index 0000000..73f755f
--- /dev/null
+++ b/roles/seafile_non_docker/handlers/main.yaml
@@ -0,0 +1,19 @@
+---
+
+- name: 'Restart nginx'
+ systemd:
+ name: 'nginx'
+ state: 'restarted'
+ listen: 'nginx_restart'
+
+- name: 'Restart Seafile'
+ systemd:
+ name: 'seafile'
+ state: 'restarted'
+ listen: 'seafile restart'
+
+- name: 'Restart Seahub'
+ systemd:
+ name: 'seahub'
+ state: 'restarted'
+ listen: 'seahub restart'
diff --git a/roles/seafile_non_docker/tasks/main.yaml b/roles/seafile_non_docker/tasks/main.yaml
new file mode 100644
index 0000000..597c389
--- /dev/null
+++ b/roles/seafile_non_docker/tasks/main.yaml
@@ -0,0 +1,220 @@
+# https://seafile.readthedocs.io/en/latest/config/seafile/seadav/#seafdav-configuration
+# https://manual.seafile.com/deploy/using_sqlite/
+# https://manual.seafile.com/deploy/using_sqlite/#setup-in-non-interactive-way
+# https://manual.seafile.com/deploy/deploy_with_nginx
+# https://manual.seafile.com/deploy/deploy_seahub_at_non-root_domain/
+# https://seafile.readthedocs.io/en/latest/installation/seafile/#enable-seafile-server-autostart-systemd
+---
+
+- name: 'install required apt packages'
+ apt:
+ name:
+ - 'libmemcached-dev'
+ - 'memcached'
+ - 'pwgen'
+ - 'python3'
+ - 'python3-setuptools'
+ - 'python3-pip'
+ - 'sqlite3'
+ - 'libopenjp2-7'
+ - 'libtiff5'
+ state: 'present'
+ update_cache: true
+
+- name: 'install required pip packages'
+ become_user: '{{ seafile_user_grp }}'
+ pip:
+ name:
+ - 'captcha'
+ - 'django==2.2.*'
+ - 'django-pylibmc'
+ - 'django-simple-captcha'
+ - 'future'
+ - 'jinja2'
+ - 'Pillow'
+ - 'psd-tools'
+ - 'pylibmc'
+ - 'pexpect'
+ state: 'present'
+
+- name: 'create seafile installation and data directories'
+ file:
+ path: '{{ item.path }}'
+ state: 'directory'
+ owner: '{{ item.owner }}'
+ group: '{{ item.group }}'
+ mode: '{{ item.mode }}'
+ loop:
+ - {path: '{{ seafile_install_dir }}/installed', owner: '{{ seafile_user_grp }}', group: '{{ seafile_user_grp }}', mode: '775'}
+ - {path: '{{ seafile_data_dir }}', owner: '{{ ansible_user }}', group: '{{ ansible_user }}', mode: '755'}
+
+- name: 'download seafile package to local folder'
+ become_user: '{{ seafile_user_grp }}'
+ get_url:
+ url: '{{ seafile_download_url }}'
+ dest: '{{ seafile_install_dir }}/installed/seafile-{{ seafile_version }}.tar.gz'
+ mode: '644'
+ register: '_download_archive'
+ until: '_download_archive is succeeded'
+ retries: 5
+ delay: 2
+ check_mode: false
+
+- name: 'unpack seafile binaries'
+ become_user: '{{ seafile_user_grp }}'
+ unarchive:
+ src: '{{ seafile_install_dir }}/installed/seafile-{{ seafile_version }}.tar.gz'
+ dest: '{{ seafile_install_dir }}'
+ remote_src: true
+ creates: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}'
+ check_mode: false
+
+# this hack is needed for this version only
+- name: 'Remove old PIL dir'
+ become_user: '{{ seafile_user_grp }}'
+ file:
+ path: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}/seahub/thirdpart/PIL'
+ state: 'absent'
+ when: '"buster" in seafile_download_url'
+
+# RUN NON-INTERACTIVELY
+- name: 'Run setup script' # noqa no-changed-when command-instead-of-shell
+ become_user: '{{ seafile_user_grp }}'
+ shell: './setup-seafile.sh auto -n "{{ inventory_hostname }}" -i "0.0.0.0"'
+ args:
+ executable: '/bin/bash'
+ chdir: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}'
+ creates: '{{ seafile_install_dir }}/conf/ccnet.conf'
+
+- name: 'Get stats of the data object'
+ stat:
+ path: '{{ seafile_install_dir }}/seafile-data'
+ register: sym
+
+- block:
+ - name: 'Ensure Seafile is not running yet' # noqa command-instead-of-shell
+ become_user: '{{ seafile_user_grp }}'
+ shell: './seafile.sh stop'
+ args:
+ executable: '/bin/bash'
+ chdir: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}'
+
+ - name: 'Move old data to new data' # noqa risky-file-permissions
+ become_user: '{{ seafile_user_grp }}'
+ copy:
+ src: '{{ seafile_install_dir }}/seafile-data/'
+ dest: '{{ seafile_data_dir }}'
+ remote_src: true
+
+ - name: 'Delete old data dir'
+ become_user: '{{ seafile_user_grp }}'
+ file:
+ path: '{{ seafile_install_dir }}/seafile-data'
+ state: 'absent'
+
+ - name: 'Create symlink to new data dir'
+ become_user: '{{ seafile_user_grp }}'
+ file:
+ src: '{{ seafile_data_dir }}'
+ dest: '{{ seafile_install_dir }}/seafile-data'
+ state: 'link'
+ when: sym.stat.islnk is defined and (not sym.stat.islnk) # => first time setup
+
+- name: 'Copy conf files'
+ become_user: '{{ seafile_user_grp }}'
+ template:
+ src: '{{ item }}.j2'
+ dest: '{{ seafile_install_dir }}/conf/{{ item }}'
+ mode: '644'
+ loop:
+ - 'ccnet.conf'
+ - 'seafdav.conf'
+ notify:
+ - 'seafile restart'
+ - 'seahub restart'
+
+- name: 'Update gunicorn conf'
+ lineinfile:
+ path: '{{ seafile_install_dir }}/conf/gunicorn.conf.py'
+ regexp: '^bind'
+ line: 'bind = "127.0.0.1:8000"'
+ notify:
+ - 'seahub restart'
+
+# some stuff needed for nginx based install
+- name: 'Update seahub_settings.py'
+ become_user: '{{ seafile_user_grp }}'
+ blockinfile:
+ path: '{{ seafile_install_dir }}/conf/seahub_settings.py'
+ insertafter: '^SECRET_KEY'
+ block: |
+ DEBUG = False
+ FILE_SERVER_ROOT = 'https://{{ seafile_domain }}/seafhttp'
+ SERVE_STATIC = False
+ MEDIA_URL = '/seafmedia/'
+ COMPRESS_URL = MEDIA_URL
+ STATIC_URL = MEDIA_URL + 'assets/'
+ SITE_ROOT = '/files/'
+ LOGIN_URL = '/files/accounts/login/'
+ notify:
+ - 'seahub restart'
+
+- block:
+ - name: 'Run Seafile start script' # noqa command-instead-of-shell
+ become_user: '{{ seafile_user_grp }}'
+ shell: './seafile.sh start'
+ args:
+ executable: '/bin/bash'
+ chdir: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}'
+
+ - name: 'Init Seahub with a user'
+ become_user: '{{ seafile_user_grp }}'
+ expect:
+ command: './seahub.sh start'
+ chdir: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}'
+ responses:
+ (?i)email: "{{ seafile_user_email }}"
+ (?i)password: "{{ seafile_user_password }}"
+
+ when: sym.stat.islnk is defined and (not sym.stat.islnk) # => first time setup
+
+- name: 'Create systemd services'
+ template:
+ src: '{{ item }}.j2'
+ dest: '/etc/systemd/system/{{ item }}'
+ mode: '644'
+ loop:
+ - 'seafile.service'
+ - 'seahub.service'
+ notify:
+ - 'seafile restart'
+ - 'seahub restart'
+
+- name: 'Reload systemd units'
+ systemd:
+ daemon_reload: true
+
+- block:
+ - name: 'Run Seahub start script' # noqa command-instead-of-shell
+ become_user: '{{ seafile_user_grp }}'
+ shell: './seahub.sh stop'
+ args:
+ executable: '/bin/bash'
+ chdir: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}'
+
+ - name: 'Run Seafile stop script' # noqa command-instead-of-shell
+ become_user: '{{ seafile_user_grp }}'
+ shell: './seafile.sh stop'
+ args:
+ executable: '/bin/bash'
+ chdir: '{{ seafile_install_dir }}/seafile-server-{{ seafile_version }}'
+ when: sym.stat.islnk is defined and (not sym.stat.islnk) # => first time setup
+
+- name: 'Start Seafile and Seahub'
+ systemd:
+ name: '{{ item }}'
+ state: 'started'
+ enabled: true
+ loop:
+ - 'seafile'
+ - 'seahub'
diff --git a/roles/seafile_non_docker/templates/ccnet.conf.j2 b/roles/seafile_non_docker/templates/ccnet.conf.j2
new file mode 100644
index 0000000..d6d69cb
--- /dev/null
+++ b/roles/seafile_non_docker/templates/ccnet.conf.j2
@@ -0,0 +1,2 @@
+[General]
+SERVICE_URL = https://{{ seafile_domain }}/files
diff --git a/roles/seafile_non_docker/templates/seafdav.conf.j2 b/roles/seafile_non_docker/templates/seafdav.conf.j2
new file mode 100644
index 0000000..54712a1
--- /dev/null
+++ b/roles/seafile_non_docker/templates/seafdav.conf.j2
@@ -0,0 +1,6 @@
+[WEBDAV]
+enabled = true
+port = 8080
+fastcgi = false
+host = 127.0.0.1
+share_name = /seafdav
diff --git a/roles/seafile_non_docker/templates/seafile.service.j2 b/roles/seafile_non_docker/templates/seafile.service.j2
new file mode 100644
index 0000000..8e4c94f
--- /dev/null
+++ b/roles/seafile_non_docker/templates/seafile.service.j2
@@ -0,0 +1,14 @@
+[Unit]
+Description=Seafile
+After=network.target
+
+[Service]
+Type=forking
+ExecStart={{ seafile_install_dir }}/seafile-server-latest/seafile.sh start
+ExecStop={{ seafile_install_dir }}/seafile-server-latest/seafile.sh stop
+LimitNOFILE=infinity
+User={{ seafile_user_grp }}
+Group={{ seafile_user_grp }}
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/seafile_non_docker/templates/seahub.service.j2 b/roles/seafile_non_docker/templates/seahub.service.j2
new file mode 100644
index 0000000..aa61a83
--- /dev/null
+++ b/roles/seafile_non_docker/templates/seahub.service.j2
@@ -0,0 +1,14 @@
+[Unit]
+Description=Seahub
+After=network.target seafile.service
+
+[Service]
+Type=forking
+ExecStart={{ seafile_install_dir }}/seafile-server-latest/seahub.sh start
+ExecStop={{ seafile_install_dir }}/seafile-server-latest/seahub.sh stop
+LimitNOFILE=infinity
+User={{ seafile_user_grp }}
+Group={{ seafile_user_grp }}
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/website/defaults/main.yaml b/roles/website/defaults/main.yaml
new file mode 100644
index 0000000..47cf58c
--- /dev/null
+++ b/roles/website/defaults/main.yaml
@@ -0,0 +1,4 @@
+# Default Values
+---
+
+websites: []
diff --git a/roles/website/tasks/main.yaml b/roles/website/tasks/main.yaml
new file mode 100644
index 0000000..6fdf7fa
--- /dev/null
+++ b/roles/website/tasks/main.yaml
@@ -0,0 +1,24 @@
+---
+
+- name: 'Install git'
+ package:
+ name: 'git'
+ state: 'present'
+
+- name: 'Create domain level dir'
+ file:
+ path: '/var/www/{{ item.name }}/html'
+ state: 'directory'
+ mode: '0755'
+ loop: '{{ websites }}'
+
+- name: 'Clone all the website project repos'
+ git:
+ repo: '{{ item.git_url }}'
+ dest: '/var/www/{{ item.name }}/html'
+ depth: 1
+ update: true
+ force: true
+ version: '{{ item.git_version }}'
+ umask: '002'
+ loop: '{{ websites }}'
diff --git a/roles/wireguard/defaults/main.yaml b/roles/wireguard/defaults/main.yaml
new file mode 100644
index 0000000..9a163d4
--- /dev/null
+++ b/roles/wireguard/defaults/main.yaml
@@ -0,0 +1,2 @@
+# Default Values
+---
diff --git a/roles/wireguard/handlers/main.yaml b/roles/wireguard/handlers/main.yaml
new file mode 100644
index 0000000..bd5fc0d
--- /dev/null
+++ b/roles/wireguard/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- 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
new file mode 100644
index 0000000..d7e1e51
--- /dev/null
+++ b/roles/wireguard/tasks/main.yaml
@@ -0,0 +1,38 @@
+# https://dev.to/tangramvision/exploring-ansible-via-setting-up-a-wireguard-vpn-3389
+---
+
+- name: 'install wireguard package'
+ apt:
+ name: 'wireguard'
+ state: 'present'
+ update_cache: true
+
+- 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:
+ name: '{{ item.sysctl_key }}'
+ reload: true
+ state: 'present'
+ sysctl_set: true
+ value: '{{ item.sysctl_val }}'
+ loop:
+ - sysctl_key: 'net.ipv4.ip_forward'
+ sysctl_val: "1"
+ - sysctl_key: 'net.ipv6.conf.all.disable_ipv6'
+ sysctl_val: "0"
+ - sysctl_key: 'net.ipv6.conf.all.forwarding'
+ sysctl_val: "1"
+
+- name: 'start wireguard and enable on boot'
+ systemd:
+ name: 'wg-quick@wg0'
+ state: 'started'
+ enabled: true
diff --git a/roles/wireguard/templates/wg0.conf.j2 b/roles/wireguard/templates/wg0.conf.j2
new file mode 100644
index 0000000..6e7bcc1
--- /dev/null
+++ b/roles/wireguard/templates/wg0.conf.j2
@@ -0,0 +1,17 @@
+# {{ ansible_managed }}
+
+[Interface]
+Address = {{ wireguard_server_ip }}
+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
+
+
+{% for peer in wireguard_peers %}
+[Peer]
+PublicKey = {{ peer.peer_key }}
+AllowedIPs = {{ peer.peer_ip}}
+
+{% endfor %}
diff --git a/roles/wireguard_client/defaults/main.yaml b/roles/wireguard_client/defaults/main.yaml
new file mode 100644
index 0000000..9a163d4
--- /dev/null
+++ b/roles/wireguard_client/defaults/main.yaml
@@ -0,0 +1,2 @@
+# Default Values
+---
diff --git a/roles/wireguard_client/handlers/main.yaml b/roles/wireguard_client/handlers/main.yaml
new file mode 100644
index 0000000..bd5fc0d
--- /dev/null
+++ b/roles/wireguard_client/handlers/main.yaml
@@ -0,0 +1,7 @@
+---
+
+- name: 'Restart wireguard'
+ systemd:
+ name: 'wg-quick@wg0'
+ state: 'restarted'
+ listen: 'restart wireguard'
diff --git a/roles/wireguard_client/tasks/main.yaml b/roles/wireguard_client/tasks/main.yaml
new file mode 100644
index 0000000..04814ba
--- /dev/null
+++ b/roles/wireguard_client/tasks/main.yaml
@@ -0,0 +1,36 @@
+# https://dev.to/tangramvision/exploring-ansible-via-setting-up-a-wireguard-vpn-3389
+---
+
+- name: 'Enable Debian 10 buster backports repo'
+ shell:
+ cmd: 'echo "deb http://deb.debian.org/debian buster-backports main contrib non-free" > /etc/apt/sources.list.d/buster-backports.list'
+ creates: '/etc/apt/sources.list.d/buster-backports.list'
+
+- name: 'Install Wireguard'
+ apt:
+ name: 'wireguard'
+ state: 'present'
+ update_cache: true
+
+- name: 'enable and persist ip forwarding'
+ sysctl:
+ name: 'net.ipv4.ip_forward'
+ value: "1"
+ state: 'present'
+ sysctl_set: true
+ reload: true
+
+- name: 'generate private key'
+ shell:
+ cmd: 'umask 077 && wg genkey | tee privatekey | wg pubkey > publickey'
+ chdir: '/etc/wireguard'
+ creates: '/etc/wireguard/publickey'
+
+- name: 'create client wireguard config'
+ template:
+ dest: '/etc/wireguard/wg0.conf'
+ src: 'wg0.conf.j2'
+ owner: 'root'
+ group: 'root'
+ mode: '600'
+ notify: 'restart wireguard'
diff --git a/roles/wireguard_client/templates/wg0.conf.j2 b/roles/wireguard_client/templates/wg0.conf.j2
new file mode 100644
index 0000000..d667d8a
--- /dev/null
+++ b/roles/wireguard_client/templates/wg0.conf.j2
@@ -0,0 +1,16 @@
+# {{ ansible_managed }}
+
+[Interface]
+Address = {{ wireguard_client_peer_ip }}
+PostUp = wg set %i private-key /etc/wireguard/privatekey
+PostUp = ping -c1 192.168.10.1
+{% for port in wireguard_client_port_forwards %}
+PostUp = iptables -t nat -A PREROUTING -p tcp --dport {{ port }} -j DNAT --to-destination 192.168.10.1:{{ port }}
+{% endfor %}
+PostUp = iptables -t nat -A POSTROUTING -j MASQUERADE
+
+[Peer]
+PublicKey = {{ wireguard_client_server_pub_key }}
+AllowedIPs = {{ wireguard_client_server_allowed_ips }}
+Endpoint = {{ wireguard_client_server_endpoint }}:{{ wireguard_client_server_listen_port }}
+PersistentKeepalive = 20
diff --git a/vaultid.example b/vaultid.example
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/vaultid.example
@@ -0,0 +1 @@
+test