Compare commits
	
		
			79 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d8eba3b7be | |||
| 01e8e22c01 | |||
| a31bf233dc | |||
| 60fafed9cd | |||
| 2c00858590 | |||
| be80681485 | |||
| a2e60972c7 | |||
| 598359854f | |||
| ef812c1877 | |||
| 385e60aee5 | |||
| 5633468f41 | |||
| 7f91b24adb | |||
| 5b09029239 | |||
| 7adb5f10e9 | |||
| c3b4321667 | |||
| d05c5d3086 | |||
| ac412f16ef | |||
| 2354a8fb8c | |||
| 251a7c0dd5 | |||
| 1d8ae8a0b6 | |||
| 6b2feaee5e | |||
| 31e0538b84 | |||
| a65c4b9cf6 | |||
| 7ee6e4810d | |||
| 87aa7ecf8b | |||
| 0377a5e642 | |||
| 2e02efcbb7 | |||
| 8fed63792b | |||
| 2c4fcbacc3 | |||
| b81372c07a | |||
| 9b5be29a1a | |||
| ef5aacdbbd | |||
| a635c7aa48 | |||
| 56aee460ad | |||
| 027ba46f6b | |||
| 48216db8f9 | |||
| fa1dc4acb7 | |||
| 228cd5795b | |||
| 74a559f1f6 | |||
| 4c2a1550c4 | |||
| f02cf7b0cc | |||
| 9142254a57 | |||
| dfd93dd5f8 | |||
| 81d2ea447a | |||
| 9512212b84 | |||
| c67a39982e | |||
| f68f57d0cf | |||
| b9f9b0bf3c | |||
| 4f4a341b05 | |||
| cab6ab2d8e | |||
| 95f54b7f0a | |||
| 7522c333da | |||
| 344b79e97f | |||
| e4fed78193 | |||
| 85a6c3894a | |||
| 7677bc25fa | |||
| b255680a7a | |||
| 9eefad0e87 | |||
| 8362230eb4 | |||
| 82df91305a | |||
| dd9f84d498 | |||
| b52ccabd22 | |||
| eccd6b7874 | |||
| 3a92921932 | |||
| 330f2b5a91 | |||
| 45465ad26b | |||
| d7838563a1 | |||
| 03a57d2531 | |||
| e346180b13 | |||
| be6e1596c5 | |||
| dc520a09e9 | |||
| c0be314268 | |||
| 9aca035f2d | |||
| 209ff57a4a | |||
| 9a4aece442 | |||
| acd2cefb1e | |||
| cd11567164 | |||
| 1c321f6ef7 | |||
| ed9100bc8f | 
							
								
								
									
										39
									
								
								.github/workflows/vagrant.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								.github/workflows/vagrant.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| name: homelab-ci | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - main | ||||
|       - testing | ||||
|  | ||||
| jobs: | ||||
|   homelab-ci: | ||||
|     runs-on: macos-latest | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Cache Vagrant boxes | ||||
|         uses: actions/cache@v3 | ||||
|         with: | ||||
|           path: ~/.vagrant.d/boxes | ||||
|           key: ${{ runner.os }}-vagrant-${{ hashFiles('Vagrantfile') }} | ||||
|           restore-keys: | | ||||
|             ${{ runner.os }}-vagrant- | ||||
|  | ||||
|       - name: Install Ansible | ||||
|         run: brew install ansible@7 | ||||
|  | ||||
|       - name: Software Versions | ||||
|         run: | | ||||
|           printf "VirtualBox " | ||||
|           vboxmanage --version | ||||
|           vagrant --version | ||||
|           export PATH="/usr/local/opt/ansible@7/bin:$PATH" | ||||
|           ansible --version | ||||
|  | ||||
|       - name: Vagrant Up with Dockerbox Playbook | ||||
|         run: | | ||||
|           export PATH="/usr/local/opt/ansible@7/bin:$PATH" | ||||
|           PLAYBOOK=dockerbox vagrant up | ||||
|           vagrant ssh -c "docker ps" | ||||
							
								
								
									
										13
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,13 +1,4 @@ | ||||
| .vagrant | ||||
| .vscode | ||||
| .playbook | ||||
| /*.yml | ||||
| /*.yaml | ||||
| !backup.yml | ||||
| !moxie.yml | ||||
| !docker.yml | ||||
| !dockerbox.yml | ||||
| !hypervisor.yml | ||||
| !minecraft.yml | ||||
| !unifi.yml | ||||
| .vagrant* | ||||
| .vscode | ||||
| /environments/ | ||||
							
								
								
									
										10
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| .PHONY: clean install | ||||
|  | ||||
| all: install | ||||
|  | ||||
| install: | ||||
| 	vagrant up --no-destroy-on-error | ||||
| 	sudo ./forward-ssh.sh | ||||
|  | ||||
| clean: | ||||
| 	vagrant destroy -f && rm -rf .vagrant | ||||
							
								
								
									
										69
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,41 +1,76 @@ | ||||
| # Project Moxie | ||||
| # Homelab | ||||
|  | ||||
| Project Moxie is a personal IT homelab project written in Ansible and executed by Jenkins. It is a growing collection of infrastructure as code (IaC) I write out of curiosity and for reference purposes, keeping a handful of beneficial projects managed and secured. | ||||
| This project is my personal IT homelab initiative for self-hosting and | ||||
| exploring Free and Open Source Software (FOSS) infrastructure. As a technology | ||||
| enthusiast and professional, this project is primarily a practical tool for | ||||
| hosting services. It serves as a playground for engaging with systems | ||||
| technology in functional, intriguing, and gratifying ways. Self-hosting | ||||
| empowers individuals to govern their digital space, ensuring that their online | ||||
| environments reflect personal ethics rather than centralized entities' opaque | ||||
| policies. | ||||
|  | ||||
| Built on Debian Stable, this project utilizes Ansible and Vagrant, providing | ||||
| relatively easy-to-use reproducible ephemeral environments to test | ||||
| infrastructure automation before pushing to live systems. | ||||
|  | ||||
| ## Quick Start | ||||
|  | ||||
| To configure a local virtual machine for testing, follow these simple steps. | ||||
|  | ||||
| ### Prerequisites | ||||
|  | ||||
| Vagrant and VirtualBox are used to develop Project Moxie. You will need to install these before continuing. | ||||
|  | ||||
| ### Installation | ||||
|  | ||||
| 1. Clone this repository | ||||
|    ``` | ||||
|    git clone https://github.com/krislamo/moxie | ||||
|    git clone https://git.krislamo.org/kris/homelab | ||||
|    ``` | ||||
|    Optionally clone from the GitHub mirror instead: | ||||
|    ``` | ||||
|    git clone https://github.com/krislamo/homelab | ||||
|    ``` | ||||
| 2. Set the `PLAYBOOK` environmental variable to a development playbook name in the `dev/` directory | ||||
|  | ||||
|    The following `PLAYBOOK` names are available: `dockerbox`, `hypervisor`, `minecraft`, `bitwarden`, `nextcloud`, `nginx` | ||||
|  | ||||
|    To list available options in the `dev/` directory and choose a suitable PLAYBOOK, run: | ||||
|    ``` | ||||
|    ls dev/*.yml | xargs -n 1 basename -s .yml | ||||
|    ``` | ||||
|    Export the `PLAYBOOK` variable | ||||
|    ``` | ||||
|    export PLAYBOOK=dockerbox | ||||
|    ``` | ||||
| 3. Bring the Vagrant box up | ||||
| 3. Clean up any previous provision and build the VM | ||||
|    ``` | ||||
|    vagrant up | ||||
|    make clean && make | ||||
|    ``` | ||||
|  | ||||
| #### Copyright and License | ||||
| Copyright (C) 2020-2021  Kris Lamoureux | ||||
| ## Vagrant Settings | ||||
| The Vagrantfile configures the environment based on settings from `.vagrant.yml`, | ||||
| with default values including: | ||||
|  | ||||
| - PLAYBOOK: `default` | ||||
|    - Runs a `default` playbook that does nothing. | ||||
|    - You can set this by an environmental variable with the same name. | ||||
| - VAGRANT_BOX: `debian/bookworm64` | ||||
|    - Current Debian Stable codename | ||||
| - VAGRANT_CPUS: `2` | ||||
|    - Threads or cores per node, depending on CPU architecture | ||||
| - VAGRANT_MEM: `2048` | ||||
|    - Specifies the amount of memory (in MB) allocated | ||||
| - SSH_FORWARD: `false` | ||||
|    - Enable this if you need to forward SSH agents to the Vagrant machine | ||||
|  | ||||
|  | ||||
| ## Copyright and License | ||||
| Copyright (C) 2019-2023  Kris Lamoureux | ||||
|  | ||||
| [](https://www.gnu.org/licenses/gpl-3.0) | ||||
|  | ||||
| This program is free software: you can redistribute it and/or modify it under | ||||
| the terms of the GNU General Public License as published by the Free Software | ||||
| Foundation, version 3 of the License. | ||||
|  | ||||
| This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. | ||||
| This program is distributed in the hope that it will be useful, but WITHOUT ANY | ||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||||
| PARTICULAR PURPOSE.  See the GNU General Public License for more details. | ||||
|  | ||||
| This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details. | ||||
|  | ||||
| You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| You should have received a copy of the GNU General Public License along with | ||||
| this program. If not, see <https://www.gnu.org/licenses/>. | ||||
|   | ||||
							
								
								
									
										49
									
								
								Vagrantfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								Vagrantfile
									
									
									
									
										vendored
									
									
								
							| @@ -1,42 +1,41 @@ | ||||
| # -*- mode: ruby -*- | ||||
| # vi: set ft=ruby : | ||||
|  | ||||
| SSH_FORWARD=ENV["SSH_FORWARD"] | ||||
| if !(SSH_FORWARD == "true") | ||||
|   SSH_FORWARD = false | ||||
| require 'yaml' | ||||
| settings_path = '.vagrant.yml' | ||||
| settings = {} | ||||
|  | ||||
| if File.exist?(settings_path) | ||||
|   settings = YAML.load_file(settings_path) | ||||
| end | ||||
|  | ||||
| PLAYBOOK=ENV["PLAYBOOK"] | ||||
| if !PLAYBOOK | ||||
|   if File.exist?('.playbook') | ||||
|     PLAYBOOK = IO.read('.playbook').split("\n")[0] | ||||
|   end | ||||
| VAGRANT_BOX  = settings['VAGRANT_BOX']  || 'debian/bookworm64' | ||||
| VAGRANT_CPUS = settings['VAGRANT_CPUS'] || 2 | ||||
| VAGRANT_MEM  = settings['VAGRANT_MEM']  || 2048 | ||||
| SSH_FORWARD  = settings['SSH_FORWARD']  || false | ||||
|  | ||||
|   if !PLAYBOOK || PLAYBOOK.empty? | ||||
|     PLAYBOOK = "\nERROR: Set env PLAYBOOK" | ||||
|   end | ||||
| else | ||||
|   File.write(".playbook", PLAYBOOK) | ||||
| # Default to shell environment variable: PLAYBOOK (priority #1) | ||||
| PLAYBOOK=ENV["PLAYBOOK"] | ||||
| if !PLAYBOOK || PLAYBOOK.empty? | ||||
|   # PLAYBOOK setting in .vagrant.yml (priority #2) | ||||
|   PLAYBOOK = settings['PLAYBOOK'] || 'default' | ||||
| end | ||||
|  | ||||
| Vagrant.configure("2") do |config| | ||||
|   config.vm.box = "debian/contrib-buster64" | ||||
|   config.vm.box = VAGRANT_BOX | ||||
|   config.vm.network "private_network", type: "dhcp" | ||||
|   config.vm.synced_folder ".", "/vagrant", disabled: true | ||||
|   config.vm.synced_folder "./scratch", "/vagrant/scratch" | ||||
|   config.ssh.forward_agent = SSH_FORWARD | ||||
|  | ||||
|   # Machine Name | ||||
|   config.vm.define :moxie do |moxie| # | ||||
|   end | ||||
|  | ||||
|   # Disable Machine Name Prefix | ||||
|   # Libvrit provider | ||||
|   config.vm.provider :libvirt do |libvirt| | ||||
|     libvirt.default_prefix = "" | ||||
|     libvirt.cpus   = VAGRANT_CPUS | ||||
|     libvirt.memory = VAGRANT_MEM | ||||
|   end | ||||
|  | ||||
|   config.vm.provider "virtualbox" do |vbox| | ||||
|     vbox.memory = 4096 | ||||
|   # Virtualbox provider | ||||
|   config.vm.provider :virtualbox do |vbox| | ||||
|     vbox.cpus   = VAGRANT_CPUS | ||||
|     vbox.memory = VAGRANT_MEM | ||||
|   end | ||||
|  | ||||
|   # Provision with Ansible | ||||
| @@ -44,6 +43,6 @@ Vagrant.configure("2") do |config| | ||||
|     ENV['ANSIBLE_ROLES_PATH'] = File.dirname(__FILE__) + "/roles" | ||||
|     ansible.compatibility_mode = "2.0" | ||||
|     ansible.playbook = "dev/" + PLAYBOOK + ".yml" | ||||
|     ansible.raw_arguments = ["--diff"] | ||||
|   end | ||||
|  | ||||
| end | ||||
|   | ||||
| @@ -1,3 +1,7 @@ | ||||
| [defaults] | ||||
| inventory = ./environments/development | ||||
| interpreter_python = /usr/bin/python3 | ||||
| roles_path = ./roles | ||||
|  | ||||
| [connection] | ||||
| pipelining = true | ||||
|   | ||||
							
								
								
									
										4
									
								
								dev/default.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								dev/default.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| - name: Install 'default' aka nothing | ||||
|   hosts: all | ||||
|   become: true | ||||
|   tasks: [] | ||||
							
								
								
									
										8
									
								
								dev/docker.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								dev/docker.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| - name: Install Docker Server | ||||
|   hosts: all | ||||
|   become: true | ||||
|   vars_files: | ||||
|     - host_vars/docker.yml | ||||
|   roles: | ||||
|     - base | ||||
|     - docker | ||||
| @@ -1,4 +1,4 @@ | ||||
| - name: Install Docker Box Server | ||||
| - name: Install Dockerbox Server | ||||
|   hosts: all | ||||
|   become: true | ||||
|   vars_files: | ||||
| @@ -8,7 +8,6 @@ | ||||
|     - docker | ||||
|     - traefik | ||||
|     - nextcloud | ||||
|     - gitea | ||||
|     - jenkins | ||||
|     - prometheus | ||||
|     - nginx | ||||
|   | ||||
							
								
								
									
										10
									
								
								dev/gitea.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								dev/gitea.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| - name: Install Gitea Server | ||||
|   hosts: all | ||||
|   become: true | ||||
|   vars_files: | ||||
|     - host_vars/gitea.yml | ||||
|   roles: | ||||
|     - base | ||||
|     - docker | ||||
|     - mariadb | ||||
|     - gitea | ||||
| @@ -9,14 +9,14 @@ docker_users: | ||||
| # traefik | ||||
| traefik_version: latest | ||||
| traefik_dashboard: true | ||||
| traefik_domain: traefik.vm.krislamo.org | ||||
| traefik_domain: traefik.local.krislamo.org | ||||
| traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
| #traefik_acme_email: realemail@example.com # Let's Encrypt settings | ||||
| #traefik_production: true | ||||
|  | ||||
| # bitwarden | ||||
| # Get Installation ID & Key at https://bitwarden.com/host/ | ||||
| bitwarden_domain: vault.vm.krislamo.org | ||||
| bitwarden_domain: vault.local.krislamo.org | ||||
| bitwarden_dbpass: password | ||||
| bitwarden_install_id: 4ea840a3-532e-4cb6-a472-abd900728b23 | ||||
| bitwarden_install_key: 1yB3Z2gRI0KnnH90C6p | ||||
|   | ||||
							
								
								
									
										48
									
								
								dev/host_vars/docker.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								dev/host_vars/docker.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| # base | ||||
| allow_reboot: false | ||||
| manage_network: false | ||||
|  | ||||
| # Import my GPG key for git signature verification | ||||
| root_gpgkeys: | ||||
|   - name: kris@lamoureux.io | ||||
|     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|  | ||||
| # docker | ||||
| docker_users: | ||||
|   - vagrant | ||||
|  | ||||
| #docker_login_url: https://myregistry.example.com | ||||
| #docker_login_user: myuser | ||||
| #docker_login_pass: YOUR_PASSWD | ||||
|  | ||||
| docker_compose_env_nolog: false # dev only setting | ||||
| docker_compose_deploy: | ||||
|   # Traefik | ||||
|   - name: traefik | ||||
|     url: https://github.com/krislamo/traefik | ||||
|     version: 31ee724feebc1d5f91cb17ffd6892c352537f194 | ||||
|     enabled: true | ||||
|     accept_newhostkey: true # Consider verifying manually instead | ||||
|     trusted_keys: | ||||
|       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|     env: | ||||
|       ENABLE: true | ||||
|  | ||||
|   # Traefik 2 (no other external compose to test currently) | ||||
|   - name: traefik2 | ||||
|     url: https://github.com/krislamo/traefik | ||||
|     version: 31ee724feebc1d5f91cb17ffd6892c352537f194 | ||||
|     enabled: true | ||||
|     accept_newhostkey: true # Consider verifying manually instead | ||||
|     trusted_keys: | ||||
|       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|     env: | ||||
|       ENABLE: true | ||||
|       VERSION: "2.10" | ||||
|       DOMAIN: traefik2.local.krislamo.org | ||||
|       NAME: traefik2 | ||||
|       ROUTER: traefik2 | ||||
|       NETWORK: traefik2 | ||||
|       WEB_PORT: 127.0.0.1:8000:80 | ||||
|       WEBSECURE_PORT: 127.0.0.1:4443:443 | ||||
|       LOCAL_PORT: 127.0.0.1:8444:8443 | ||||
| @@ -9,39 +9,36 @@ docker_users: | ||||
| # traefik | ||||
| traefik_version: latest | ||||
| traefik_dashboard: true | ||||
| traefik_domain: traefik.vm.krislamo.org | ||||
| traefik_domain: traefik.local.krislamo.org | ||||
| traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
| traefik_web_entry: 0.0.0.0:80 | ||||
| traefik_websecure_entry: 0.0.0.0:443 | ||||
| #traefik_acme_email: realemail@example.com # Let's Encrypt settings | ||||
| #traefik_production: true | ||||
| #traefik_http_only: true # if behind reverse-proxy | ||||
|  | ||||
| # nextcloud | ||||
| nextcloud_version: stable | ||||
| nextcloud_admin: admin | ||||
| nextcloud_pass: password | ||||
| nextcloud_domain: cloud.vm.krislamo.org | ||||
| nextcloud_domain: cloud.local.krislamo.org | ||||
|  | ||||
| nextcloud_dbversion: latest | ||||
| nextcloud_dbpass: password | ||||
|  | ||||
| # gitea | ||||
| gitea_domain: git.vm.krislamo.org | ||||
| gitea_version: 1 | ||||
| gitea_dbversion: latest | ||||
| gitea_dbpass: password | ||||
|  | ||||
| # jenkins | ||||
| jenkins_version: lts | ||||
| jenkins_domain: jenkins.vm.krislamo.org | ||||
| jenkins_domain: jenkins.local.krislamo.org | ||||
|  | ||||
| # prometheus (includes grafana) | ||||
| prom_version: latest | ||||
| prom_domain: prom.vm.krislamo.org | ||||
| prom_domain: prom.local.krislamo.org | ||||
| grafana_version: latest | ||||
| grafana_domain: grafana.vm.krislamo.org | ||||
| grafana_domain: grafana.local.krislamo.org | ||||
| prom_targets: "['10.0.2.15:9100']" | ||||
|  | ||||
| # nginx | ||||
| nginx_domain: nginx.vm.krislamo.org | ||||
| nginx_domain: nginx.local.krislamo.org | ||||
| nginx_name: staticsite | ||||
| nginx_repo_url: https://git.krislamo.org/kris/example-website/ | ||||
| nginx_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
|   | ||||
							
								
								
									
										50
									
								
								dev/host_vars/gitea.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								dev/host_vars/gitea.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| # base | ||||
| allow_reboot: false | ||||
| manage_network: false | ||||
|  | ||||
| users: | ||||
|   git: | ||||
|     uid: 1001 | ||||
|     gid: 1001 | ||||
|     home: true | ||||
|     system: true | ||||
|  | ||||
| # Import my GPG key for git signature verification | ||||
| root_gpgkeys: | ||||
|   - name: kris@lamoureux.io | ||||
|     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|  | ||||
| # docker | ||||
| docker_official: true # docker's apt repos | ||||
| docker_users: | ||||
|   - vagrant | ||||
|  | ||||
| docker_compose_env_nolog: false # dev only setting | ||||
| docker_compose_deploy: | ||||
|   # Traefik | ||||
|   - name: traefik | ||||
|     url: https://github.com/krislamo/traefik | ||||
|     version: 398eb48d311db78b86abf783f903af4a1658d773 | ||||
|     enabled: true | ||||
|     accept_newhostkey: true | ||||
|     trusted_keys: | ||||
|       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|     env: | ||||
|       ENABLE: true | ||||
|   # Gitea | ||||
|   - name: gitea | ||||
|     url: https://github.com/krislamo/gitea | ||||
|     version: b0ce66f6a1ab074172eed79eeeb36d7e9011ef8f | ||||
|     enabled: true | ||||
|     trusted_keys: | ||||
|       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|     env: | ||||
|       USER_UID: "{{ users.git.uid }}" | ||||
|       USER_GID: "{{ users.git.gid }}" | ||||
|       DB_PASSWD: "{{ gitea.DB_PASSWD }}" | ||||
|  | ||||
| # gitea | ||||
| gitea: | ||||
|   DB_NAME: gitea | ||||
|   DB_USER: gitea | ||||
|   DB_PASSWD: password | ||||
							
								
								
									
										61
									
								
								dev/host_vars/mediaserver.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								dev/host_vars/mediaserver.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| base_domain: local.krislamo.org | ||||
|  | ||||
| # base | ||||
| allow_reboot: false | ||||
| manage_network: false | ||||
|  | ||||
| users: | ||||
|   jellyfin: | ||||
|     uid: 1001 | ||||
|     gid: 1001 | ||||
|     shell: /usr/sbin/nologin | ||||
|     home: false | ||||
|     system: true | ||||
|  | ||||
| samba: | ||||
|   users: | ||||
|     - name: jellyfin | ||||
|       password: jellyfin | ||||
|   shares: | ||||
|     - name: jellyfin | ||||
|       path: /srv/jellyfin | ||||
|       owner: jellyfin | ||||
|       group: jellyfin | ||||
|       valid_users: jellyfin | ||||
|   firewall: | ||||
|     - 10.0.0.0/8 | ||||
|     - 172.16.0.0/12 | ||||
|     - 192.168.0.0/16 | ||||
|  | ||||
| # proxy | ||||
| proxy: | ||||
|   #production: true | ||||
|   dns_cloudflare: | ||||
|     opts: --test-cert | ||||
|     #email: realemail@example.com | ||||
|     #api_token: CLOUDFLARE_DNS01_API_TOKEN | ||||
|     wildcard_domains: | ||||
|       - "{{ base_domain }}" | ||||
|   servers: | ||||
|     - domain: "{{ traefik_domain }}" | ||||
|       proxy_pass: "http://127.0.0.1:8000" | ||||
|     - domain: "{{ jellyfin_domain }}" | ||||
|       proxy_pass: "http://127.0.0.1:8000" | ||||
|  | ||||
| # docker | ||||
| docker_users: | ||||
|   - vagrant | ||||
|  | ||||
| # traefik | ||||
| traefik_version: latest | ||||
| traefik_dashboard: true | ||||
| traefik_domain: "traefik.{{ base_domain }}" | ||||
| traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
| #traefik_acme_email: realemail@example.com # Let's Encrypt settings | ||||
| #traefik_production: true | ||||
| traefik_http_only: true # if behind reverse-proxy | ||||
|  | ||||
| # jellyfin | ||||
| jellyfin_domain: "jellyfin.{{ base_domain }}" | ||||
| jellyfin_version: latest | ||||
| jellyfin_media: /srv/jellyfin | ||||
| @@ -5,14 +5,14 @@ docker_users: | ||||
| # traefik | ||||
| traefik_version: latest | ||||
| traefik_dashboard: true | ||||
| traefik_domain: traefik.vm.krislamo.org | ||||
| traefik_domain: traefik.local.krislamo.org | ||||
| traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
|  | ||||
| # container settings | ||||
| nextcloud_version: stable | ||||
| nextcloud_admin: admin | ||||
| nextcloud_pass: password | ||||
| nextcloud_domain: cloud.vm.krislamo.org | ||||
| nextcloud_domain: cloud.local.krislamo.org | ||||
|  | ||||
| # database settings | ||||
| nextcloud_dbversion: latest | ||||
|   | ||||
| @@ -9,13 +9,13 @@ docker_users: | ||||
| # traefik | ||||
| traefik_version: latest | ||||
| traefik_dashboard: true | ||||
| traefik_domain: traefik.vm.krislamo.org | ||||
| traefik_domain: traefik.local.krislamo.org | ||||
| traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
| #traefik_acme_email: realemail@example.com # Let's Encrypt settings | ||||
| #traefik_production: true | ||||
|  | ||||
| # nginx | ||||
| nginx_domain: nginx.vm.krislamo.org | ||||
| nginx_domain: nginx.local.krislamo.org | ||||
| nginx_name: staticsite | ||||
| nginx_repo_url: https://git.krislamo.org/kris/example-website/ | ||||
| nginx_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
|   | ||||
							
								
								
									
										79
									
								
								dev/host_vars/proxy.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								dev/host_vars/proxy.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| base_domain: local.krislamo.org | ||||
|  | ||||
| # base | ||||
| allow_reboot: false | ||||
| manage_network: false | ||||
|  | ||||
| users: | ||||
|   git: | ||||
|     uid: 1001 | ||||
|     gid: 1001 | ||||
|     home: true | ||||
|     system: true | ||||
|  | ||||
| # Import my GPG key for git signature verification | ||||
| root_gpgkeys: | ||||
|   - name: kris@lamoureux.io | ||||
|     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|  | ||||
| # proxy | ||||
| proxy: | ||||
|   #production: true | ||||
|   dns_cloudflare: | ||||
|     opts: --test-cert | ||||
|     #email: realemail@example.com | ||||
|     #api_token: CLOUDFLARE_DNS01_API_TOKEN | ||||
|     wildcard_domains: | ||||
|       - "{{ base_domain }}" | ||||
|   servers: | ||||
|     - domain: "{{ bitwarden_domain }}" | ||||
|       proxy_pass: "http://127.0.0.1" | ||||
|     - domain: "{{ gitea_domain }}" | ||||
|       proxy_pass: "http://127.0.0.1" | ||||
|  | ||||
| # docker | ||||
| docker_official: true # docker's apt repos | ||||
| docker_users: | ||||
|   - vagrant | ||||
|  | ||||
| docker_compose_env_nolog: false # dev only setting | ||||
| docker_compose_deploy: | ||||
|   # Traefik | ||||
|   - name: traefik | ||||
|     url: https://github.com/krislamo/traefik | ||||
|     version: e97db75e2e214582fac5f5e495687ab5cdf855ad | ||||
|     path: docker-compose.web.yml | ||||
|     enabled: true | ||||
|     accept_newhostkey: true | ||||
|     trusted_keys: | ||||
|       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|     env: | ||||
|       ENABLE: true | ||||
|   # Gitea | ||||
|   - name: gitea | ||||
|     url: https://github.com/krislamo/gitea | ||||
|     version: b0ce66f6a1ab074172eed79eeeb36d7e9011ef8f | ||||
|     enabled: true | ||||
|     trusted_keys: | ||||
|       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||
|     env: | ||||
|       ENTRYPOINT: web | ||||
|       ENABLE_TLS: false | ||||
|       USER_UID: "{{ users.git.uid }}" | ||||
|       USER_GID: "{{ users.git.gid }}" | ||||
|       DB_PASSWD: "{{ gitea.DB_PASSWD }}" | ||||
|  | ||||
| # gitea | ||||
| gitea_domain: "git.{{ base_domain }}" | ||||
| gitea: | ||||
|   DB_NAME: gitea | ||||
|   DB_USER: gitea | ||||
|   DB_PASSWD: password | ||||
|  | ||||
| # bitwarden | ||||
| # Get Installation ID & Key at https://bitwarden.com/host/ | ||||
| bitwarden_domain: "vault.{{ base_domain }}" | ||||
| bitwarden_dbpass: password | ||||
| bitwarden_install_id: 4ea840a3-532e-4cb6-a472-abd900728b23 | ||||
| bitwarden_install_key: 1yB3Z2gRI0KnnH90C6p | ||||
| #bitwarden_prodution: true | ||||
| @@ -9,14 +9,14 @@ docker_users: | ||||
| # traefik | ||||
| traefik_version: latest | ||||
| traefik_dashboard: true | ||||
| traefik_domain: traefik.vm.krislamo.org | ||||
| traefik_domain: traefik.local.krislamo.org | ||||
| traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin | ||||
| #traefik_acme_email: realemail@example.com # Let's Encrypt settings | ||||
| #traefik_production: true | ||||
|  | ||||
| # container settings | ||||
| wordpress_version: latest | ||||
| wordpress_domain: wordpress.vm.krislamo.org | ||||
| wordpress_domain: wordpress.local.krislamo.org | ||||
| wordpress_multisite: true | ||||
|  | ||||
| # database settings | ||||
|   | ||||
							
								
								
									
										11
									
								
								dev/mediaserver.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								dev/mediaserver.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| - name: Install Media Server | ||||
|   hosts: all | ||||
|   become: true | ||||
|   vars_files: | ||||
|     - host_vars/mediaserver.yml | ||||
|   roles: | ||||
|     - base | ||||
|     - proxy | ||||
|     - docker | ||||
|     - traefik | ||||
|     - jellyfin | ||||
							
								
								
									
										12
									
								
								dev/proxy.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								dev/proxy.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| - name: Install Proxy Server | ||||
|   hosts: all | ||||
|   become: true | ||||
|   vars_files: | ||||
|     - host_vars/proxy.yml | ||||
|   roles: | ||||
|     - base | ||||
|     - proxy | ||||
|     - docker | ||||
|     - mariadb | ||||
|     - gitea | ||||
|     - bitwarden | ||||
							
								
								
									
										21
									
								
								docker.yml
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								docker.yml
									
									
									
									
									
								
							| @@ -1,21 +0,0 @@ | ||||
| # Copyright (C) 2020  Kris Lamoureux | ||||
| # | ||||
| # This program is free software: you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation, version 3 of the License. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| - name: Install Docker Server | ||||
|   hosts: dockerhosts | ||||
|   become: true | ||||
|   roles: | ||||
|     - base | ||||
|     - docker | ||||
|     - jenkins | ||||
| @@ -1,26 +0,0 @@ | ||||
| # Copyright (C) 2020  Kris Lamoureux | ||||
| # | ||||
| # This program is free software: you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation, version 3 of the License. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| - name: Install Docker Box Server | ||||
|   hosts: dockerhosts | ||||
|   become: true | ||||
|   roles: | ||||
|     - base | ||||
|     - docker | ||||
|     - traefik | ||||
|     - nextcloud | ||||
| #    - gitea | ||||
|     - jenkins | ||||
|     - prometheus | ||||
|     - nginx | ||||
							
								
								
									
										129
									
								
								forward-ssh.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										129
									
								
								forward-ssh.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| # Finds the SSH private key under ./.vagrant and connects to | ||||
| # the Vagrant box, port forwarding localhost ports: 8443, 443, 80, 22 | ||||
| # | ||||
| # Download the latest script: | ||||
| # https://git.krislamo.org/kris/homelab/raw/branch/main/forward-ssh.sh | ||||
| # | ||||
| # Copyright (C) 2023  Kris Lamoureux | ||||
| # | ||||
| # This program is free software: you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation, version 3 of the License. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| # Root check | ||||
| if [ "$EUID" -ne 0 ]; then | ||||
|   echo "[ERROR]: Please run this script as root" | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| # Clean environment | ||||
| unset PRIVATE_KEY | ||||
| unset MATCH_PATTERN | ||||
| unset PKILL_ANSWER | ||||
|  | ||||
| # Function to create the SSH tunnel | ||||
| function ssh_connect { | ||||
|   read -rp "Start a new vagrant SSH tunnel? [y/N] " PSTART_ANSWER | ||||
|   echo | ||||
|   case "$PSTART_ANSWER" in | ||||
|     [yY]) | ||||
|       printf "[INFO]: Starting new vagrant SSH tunnel on PID " | ||||
|       sudo -u "$USER" ssh -fNT -i "$PRIVATE_KEY" \ | ||||
|         -L 22:localhost:22 \ | ||||
|         -L 80:"$HOST_IP":80 \ | ||||
|         -L 443:"$HOST_IP":443 \ | ||||
|         -L 8443:localhost:8443 \ | ||||
|         -o UserKnownHostsFile=/dev/null \ | ||||
|         -o StrictHostKeyChecking=no \ | ||||
|         vagrant@"$HOST_IP" 2>/dev/null | ||||
|       sleep 2 | ||||
|       pgrep -f "$MATCH_PATTERN" | ||||
|       ;; | ||||
|     *) | ||||
|       echo "[INFO]: Declined to start a new vagrant SSH tunnel" | ||||
|       exit 0 | ||||
|       ;; | ||||
|   esac | ||||
| } | ||||
|  | ||||
| # Check for valid PRIVATE_KEY location | ||||
| PRIVATE_KEY="$(find .vagrant -name "private_key" 2>/dev/null | sort)" | ||||
|  | ||||
| # Single vagrant machine or multiple | ||||
| if [ "$(echo "$PRIVATE_KEY" | wc -l)" -gt 1 ]; then | ||||
|   while IFS= read -r KEYFILE; do | ||||
|     if ! ssh-keygen -l -f "$KEYFILE" &>/dev/null; then | ||||
|       echo "[ERROR]: The SSH key '$KEYFILE' is not valid. Are your virtual machines running?" | ||||
|       exit 1 | ||||
|     fi | ||||
|     echo "[CHECK]: Valid key at $KEYFILE" | ||||
|   done < <(echo "$PRIVATE_KEY") | ||||
|   PRIVATE_KEY="$(echo "$PRIVATE_KEY" | grep -m1 "${1:-default}")" | ||||
| elif ! ssh-keygen -l -f "$PRIVATE_KEY" &>/dev/null; then | ||||
|   echo "[ERROR]: The SSH key '$PRIVATE_KEY' is not valid. Is your virtual machine running?" | ||||
|   exit 1 | ||||
| else | ||||
|   echo "[CHECK]: Valid key at $PRIVATE_KEY" | ||||
| fi | ||||
|  | ||||
| # Grab first IP or use whatever HOST_IP_FIELD is set to and check that the guest is up | ||||
| if [ -z "$HOST_IP" ]; then | ||||
|   HOST_IP="$(sudo -u "$SUDO_USER" vagrant ssh -c "hostname -I | cut -d' ' -f${HOST_IP_FIELD:-1}" "${1:-default}" 2>/dev/null)" | ||||
|  | ||||
|   if [ -z "$HOST_IP" ]; then | ||||
|     echo "[ERROR]: Failed to find ${1:-default}'s IP" | ||||
|     exit 1 | ||||
|   fi | ||||
|   HOST_IP="${HOST_IP::-1}" # trim | ||||
| else | ||||
|   echo "[INFO]: HOST_IP configured by the shell environment" | ||||
| fi | ||||
|  | ||||
| if ! ping -c 1 "$HOST_IP" &>/dev/null; then | ||||
|   echo "[ERROR]: Cannot ping the host IP '$HOST_IP'" | ||||
|   exit 1 | ||||
| fi | ||||
| echo "[CHECK]: Host at $HOST_IP (${1:-default}) is up" | ||||
|  | ||||
| # Pattern for matching processes running | ||||
| MATCH_PATTERN="ssh -fNT -i ${PRIVATE_KEY}.*vagrant@" | ||||
|  | ||||
| # Check amount of processes that match the pattern | ||||
| if [ "$(pgrep -afc "$MATCH_PATTERN")" -eq 0 ]; then | ||||
|   ssh_connect | ||||
| else | ||||
|   # Processes found, so prompt to kill remaining ones then start tunnel | ||||
|   printf "\n[WARNING]: Found processes running:\n" | ||||
|   pgrep -fa "$MATCH_PATTERN" | ||||
|   printf '\n' | ||||
|   read -rp "Would you like to kill these processes? [y/N] " PKILL_ANSWER | ||||
|   echo | ||||
|   case "$PKILL_ANSWER" in | ||||
|     [yY]) | ||||
|       echo "[WARNING]: Killing old vagrant SSH tunnel(s): " | ||||
|       pgrep -f "$MATCH_PATTERN" | tee >(xargs kill -15) | ||||
|       echo | ||||
|       if [ "$(pgrep -afc "$MATCH_PATTERN")" -eq 0 ]; then | ||||
|         ssh_connect | ||||
|       else | ||||
|         echo "[ERROR]: Unable to kill processes:" | ||||
|         pgrep -f "$MATCH_PATTERN" | ||||
|         exit 1 | ||||
|       fi | ||||
|       ;; | ||||
|     *) | ||||
|       echo "[INFO]: Declined to kill existing processes" | ||||
|       exit 0 | ||||
|       ;; | ||||
|   esac | ||||
| fi | ||||
							
								
								
									
										7
									
								
								playbooks/docker.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								playbooks/docker.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| - name: Install Docker Server | ||||
|   hosts: "{{ PLAYBOOK_HOST | default('none') }}" | ||||
|   become: true | ||||
|   roles: | ||||
|     - base | ||||
|     - jenkins | ||||
|     - docker | ||||
							
								
								
									
										11
									
								
								playbooks/dockerbox.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								playbooks/dockerbox.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| - name: Install Dockerbox Server | ||||
|   hosts: "{{ PLAYBOOK_HOST | default('none') }}" | ||||
|   become: true | ||||
|   roles: | ||||
|     - base | ||||
|     - docker | ||||
|     - traefik | ||||
|     - nextcloud | ||||
|     - jenkins | ||||
|     - prometheus | ||||
|     - nginx | ||||
							
								
								
									
										10
									
								
								playbooks/mediaserver.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								playbooks/mediaserver.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| - name: Install Media Server | ||||
|   hosts: "{{ PLAYBOOK_HOST | default('none') }}" | ||||
|   become: true | ||||
|   roles: | ||||
|     - base | ||||
|     - jenkins | ||||
|     - proxy | ||||
|     - docker | ||||
|     - traefik | ||||
|     - jellyfin | ||||
							
								
								
									
										11
									
								
								playbooks/proxy.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								playbooks/proxy.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| - name: Install Proxy Server | ||||
|   hosts: proxyhosts | ||||
|   become: true | ||||
|   roles: | ||||
|     - base | ||||
|     - jenkins | ||||
|     - mariadb | ||||
|     - proxy | ||||
|     - docker | ||||
|     - gitea | ||||
|     - bitwarden | ||||
							
								
								
									
										17
									
								
								roles/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								roles/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,17 +0,0 @@ | ||||
| /* | ||||
| !.gitignore | ||||
| !requirements.yml | ||||
| !base*/ | ||||
| !bitwarden*/ | ||||
| !docker*/ | ||||
| !gitea*/ | ||||
| !jenkins*/ | ||||
| !libvirt*/ | ||||
| !minecraft*/ | ||||
| !nextcloud*/ | ||||
| !nginx*/ | ||||
| !prometheus*/ | ||||
| !rsnapshot*/ | ||||
| !traefik*/ | ||||
| !unifi*/ | ||||
| !wordpress*/ | ||||
| @@ -1,8 +1,11 @@ | ||||
| allow_reboot: true | ||||
| manage_firewall: true | ||||
| manage_network: false | ||||
| network_type: static | ||||
| allow_reboot: true | ||||
| locale_default: en_US.UTF-8 | ||||
|  | ||||
| packages: | ||||
|   - apache2-utils | ||||
|   - cryptsetup | ||||
|   - curl | ||||
|   - dnsutils | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| deb http://deb.debian.org/debian buster-backports main | ||||
| @@ -1,12 +1,34 @@ | ||||
| - name: Reboot host | ||||
|   reboot: | ||||
|   ansible.builtin.reboot: | ||||
|     msg: "Reboot initiated by Ansible" | ||||
|     connect_timeout: 5 | ||||
|   listen: reboot_host | ||||
|   when: allow_reboot | ||||
|  | ||||
| - name: Reconfigure locales | ||||
|   ansible.builtin.command: dpkg-reconfigure -f noninteractive locales | ||||
|   listen: reconfigure_locales | ||||
|  | ||||
| - name: Restart WireGuard | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: wg-quick@wg0 | ||||
|     state: restarted | ||||
|   listen: restart_wireguard | ||||
|  | ||||
| - name: Restart Fail2ban | ||||
|   ansible.builtin.service: | ||||
|     name: fail2ban | ||||
|     state: restarted | ||||
|   listen: restart_fail2ban | ||||
|  | ||||
| - name: Restart ddclient | ||||
|   ansible.builtin.service: | ||||
|     name: ddclient | ||||
|     state: restarted | ||||
|   listen: restart_ddclient | ||||
|  | ||||
| - name: Restart Samba | ||||
|   ansible.builtin.service: | ||||
|     name: smbd | ||||
|     state: restarted | ||||
|   listen: restart_samba | ||||
|   | ||||
| @@ -1,15 +1,5 @@ | ||||
| - name: 'Install Ansible dependency: python3-apt' | ||||
|   shell: 'apt-get update && apt-get install python3-apt -y' | ||||
|   args: | ||||
|     creates: /usr/lib/python3/dist-packages/apt | ||||
|     warn: false | ||||
|  | ||||
| - name: Install additional Ansible dependencies | ||||
|   apt: | ||||
|     name: "{{ item }}" | ||||
|     state: present | ||||
|     force_apt_get: true | ||||
|     update_cache: true | ||||
|   loop: | ||||
|     - aptitude | ||||
|     - python3-docker | ||||
| - name: Create Ansible's temporary remote directory | ||||
|   ansible.builtin.file: | ||||
|     path: "~/.ansible/tmp" | ||||
|     state: directory | ||||
|     mode: "700" | ||||
|   | ||||
| @@ -1,22 +1,17 @@ | ||||
| - name: Install ddclient | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: ddclient | ||||
|     state: present | ||||
|  | ||||
| - name: Install ddclient settings | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: ddclient.conf.j2 | ||||
|     dest: /etc/ddclient.conf | ||||
|     mode: "600" | ||||
|   register: ddclient_settings | ||||
|  | ||||
| - name: Start ddclient and enable on boot | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: ddclient | ||||
|     state: started | ||||
|     enabled: true | ||||
|  | ||||
| - name: Restart ddclient | ||||
|   service: | ||||
|     name: ddclient | ||||
|     state: restarted | ||||
|   when: ddclient_settings.changed | ||||
|   | ||||
							
								
								
									
										48
									
								
								roles/base/tasks/firewall.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								roles/base/tasks/firewall.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| - name: Install the Uncomplicated Firewall | ||||
|   ansible.builtin.apt: | ||||
|     name: ufw | ||||
|     state: present | ||||
|  | ||||
| - name: Install Fail2ban | ||||
|   ansible.builtin.apt: | ||||
|     name: fail2ban | ||||
|     state: present | ||||
|  | ||||
| - name: Deny incoming traffic by default | ||||
|   community.general.ufw: | ||||
|     default: deny | ||||
|     direction: incoming | ||||
|  | ||||
| - name: Allow outgoing traffic by default | ||||
|   community.general.ufw: | ||||
|     default: allow | ||||
|     direction: outgoing | ||||
|  | ||||
| - name: Allow OpenSSH with rate limiting | ||||
|   community.general.ufw: | ||||
|     name: ssh | ||||
|     rule: limit | ||||
|  | ||||
| - name: Remove Fail2ban defaults-debian.conf | ||||
|   ansible.builtin.file: | ||||
|     path: /etc/fail2ban/jail.d/defaults-debian.conf | ||||
|     state: absent | ||||
|  | ||||
| - name: Install OpenSSH's Fail2ban jail | ||||
|   ansible.builtin.template: | ||||
|     src: fail2ban-ssh.conf.j2 | ||||
|     dest: /etc/fail2ban/jail.d/sshd.conf | ||||
|     mode: "640" | ||||
|   notify: restart_fail2ban | ||||
|  | ||||
| - name: Install Fail2ban IP allow list | ||||
|   ansible.builtin.template: | ||||
|     src: fail2ban-allowlist.conf.j2 | ||||
|     dest: /etc/fail2ban/jail.d/allowlist.conf | ||||
|     mode: "640" | ||||
|   when: fail2ban_ignoreip is defined | ||||
|   notify: restart_fail2ban | ||||
|  | ||||
| - name: Enable firewall | ||||
|   community.general.ufw: | ||||
|     state: enabled | ||||
| @@ -1,5 +1,5 @@ | ||||
| - name: Install msmtp | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: "{{ item }}" | ||||
|     state: present | ||||
|   loop: | ||||
| @@ -8,12 +8,13 @@ | ||||
|     - mailutils | ||||
|  | ||||
| - name: Install msmtp configuration | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: msmtprc.j2 | ||||
|     dest: /root/.msmtprc | ||||
|     mode: 0700 | ||||
|     mode: "600" | ||||
|  | ||||
| - name: Install /etc/aliases | ||||
|   copy: | ||||
|   ansible.builtin.copy: | ||||
|     dest: /etc/aliases | ||||
|     content: "root: {{ mail.rootalias }}" | ||||
|     mode: "644" | ||||
|   | ||||
| @@ -1,21 +1,37 @@ | ||||
| - import_tasks: ansible.yml | ||||
| - name: Import Ansible tasks | ||||
|   ansible.builtin.import_tasks: ansible.yml | ||||
|   tags: ansible | ||||
|  | ||||
| - import_tasks: system.yml | ||||
| - name: Import System tasks | ||||
|   ansible.builtin.import_tasks: system.yml | ||||
|   tags: system | ||||
|  | ||||
| - import_tasks: network.yml | ||||
| - name: Import Firewall tasks | ||||
|   ansible.builtin.import_tasks: firewall.yml | ||||
|   tags: firewall | ||||
|   when: manage_firewall | ||||
|  | ||||
| - name: Import Network tasks | ||||
|   ansible.builtin.import_tasks: network.yml | ||||
|   tags: network | ||||
|   when: manage_network | ||||
|  | ||||
| - import_tasks: mail.yml | ||||
| - name: Import Mail tasks | ||||
|   ansible.builtin.import_tasks: mail.yml | ||||
|   tags: mail | ||||
|   when: mail is defined | ||||
|  | ||||
| - import_tasks: ddclient.yml | ||||
| - name: Import ddclient tasks | ||||
|   ansible.builtin.import_tasks: ddclient.yml | ||||
|   tags: ddclient | ||||
|   when: ddclient is defined | ||||
|  | ||||
| - import_tasks: wireguard.yml | ||||
| - name: Import WireGuard tasks | ||||
|   ansible.builtin.import_tasks: wireguard.yml | ||||
|   tags: wireguard | ||||
|   when: wireguard is defined | ||||
|  | ||||
| - name: Import Samba tasks | ||||
|   ansible.builtin.import_tasks: samba.yml | ||||
|   tags: samba | ||||
|   when: samba is defined | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| - name: Install network interfaces file | ||||
|   copy: | ||||
|   ansible.builtin.copy: | ||||
|     src: network-interfaces.cfg | ||||
|     dest: /etc/network/interfaces | ||||
|     owner: root | ||||
| @@ -7,13 +7,9 @@ | ||||
|     mode: '0644' | ||||
|  | ||||
| - name: Install network interfaces | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: "interface.j2" | ||||
|     dest: "/etc/network/interfaces.d/{{ item.name }}" | ||||
|     mode: "400" | ||||
|   loop: "{{ interfaces }}" | ||||
|   notify: reboot_host | ||||
|  | ||||
| - name: Install bridge utilities | ||||
|   apt: | ||||
|     name: bridge-utils | ||||
|     state: present | ||||
|   | ||||
							
								
								
									
										46
									
								
								roles/base/tasks/samba.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								roles/base/tasks/samba.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| - name: Install Samba | ||||
|   ansible.builtin.apt: | ||||
|     name: samba | ||||
|     state: present | ||||
|  | ||||
| - name: Create Samba users | ||||
|   ansible.builtin.command: "smbpasswd -a {{ item.name }}" | ||||
|   args: | ||||
|     stdin: "{{ item.password }}\n{{ item.password }}" | ||||
|   loop: "{{ samba.users }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.name }}" | ||||
|   register: samba_users | ||||
|   changed_when: "'Added user' in samba_users.stdout" | ||||
|  | ||||
| - name: Ensure share directories exist | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ item.path }}" | ||||
|     owner: "{{ item.owner }}" | ||||
|     group: "{{ item.group }}" | ||||
|     state: directory | ||||
|     mode: "755" | ||||
|   loop: "{{ samba.shares }}" | ||||
|  | ||||
| - name: Configure Samba shares | ||||
|   ansible.builtin.template: | ||||
|     src: smb.conf.j2 | ||||
|     dest: /etc/samba/smb.conf | ||||
|     mode: "700" | ||||
|   notify: restart_samba | ||||
|  | ||||
| - name: Start smbd and enable on boot | ||||
|   ansible.builtin.service: | ||||
|     name: smbd | ||||
|     state: started | ||||
|     enabled: true | ||||
|  | ||||
| - name: Allow SMB connections | ||||
|   community.general.ufw: | ||||
|     rule: allow | ||||
|     port: 445 | ||||
|     proto: tcp | ||||
|     from: "{{ item }}" | ||||
|     state: enabled | ||||
|   loop: "{{ samba.firewall }}" | ||||
|   when: manage_firewall | ||||
| @@ -1,23 +1,105 @@ | ||||
| - name: Install useful software | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: "{{ packages }}" | ||||
|     state: present | ||||
|     update_cache: true | ||||
|  | ||||
| - name: Install GPG | ||||
|   ansible.builtin.apt: | ||||
|     name: gpg | ||||
|     state: present | ||||
|  | ||||
| - name: Check for existing GPG keys | ||||
|   ansible.builtin.command: "gpg --list-keys {{ item.id }} 2>/dev/null" | ||||
|   register: gpg_check | ||||
|   loop: "{{ root_gpgkeys }}" | ||||
|   failed_when: false | ||||
|   changed_when: false | ||||
|   when: root_gpgkeys is defined | ||||
|  | ||||
| - name: Import GPG keys | ||||
|   ansible.builtin.command: | ||||
|     "gpg --keyserver {{ item.item.server | default('keys.openpgp.org') }} --recv-key {{ item.item.id }}" | ||||
|   register: gpg_check_import | ||||
|   loop: "{{ gpg_check.results }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.item }}" | ||||
|   changed_when: false | ||||
|   when: root_gpgkeys is defined and item.rc != 0 | ||||
|  | ||||
| - name: Check GPG key imports | ||||
|   ansible.builtin.fail: | ||||
|     msg: "{{ item.stderr }}" | ||||
|   loop: "{{ gpg_check_import.results }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.item.item }}" | ||||
|   when: root_gpgkeys is defined and (not item.skipped | default(false)) and ('imported' not in item.stderr) | ||||
|  | ||||
| - name: Install NTPsec | ||||
|   ansible.builtin.apt: | ||||
|     name: ntpsec | ||||
|     state: present | ||||
|  | ||||
| - name: Install locales | ||||
|   ansible.builtin.apt: | ||||
|     name: locales | ||||
|     state: present | ||||
|  | ||||
| - name: Generate locale | ||||
|   community.general.locale_gen: | ||||
|     name: "{{ locale_default }}" | ||||
|     state: present | ||||
|   notify: reconfigure_locales | ||||
|  | ||||
| - name: Set the default locale | ||||
|   ansible.builtin.lineinfile: | ||||
|     path: /etc/default/locale | ||||
|     regexp: "^LANG=" | ||||
|     line: "LANG={{ locale_default }}" | ||||
|  | ||||
| - name: Manage root authorized_keys | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: authorized_keys.j2 | ||||
|     dest: /root/.ssh/authorized_keys | ||||
|     mode: "400" | ||||
|   when: authorized_keys is defined | ||||
|  | ||||
| - name: Install btrfs-tools | ||||
|   apt: | ||||
|     name: btrfs-tools | ||||
| - name: Create system user groups | ||||
|   ansible.builtin.group: | ||||
|     name: "{{ item.key }}" | ||||
|     gid: "{{ item.value.gid }}" | ||||
|     state: present | ||||
|   when: btrfs_support is defined and btrfs_support | bool == true | ||||
|   loop: "{{ users | dict2items }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.key }}" | ||||
|   when: users is defined | ||||
|  | ||||
| - name: Create system users | ||||
|   ansible.builtin.user: | ||||
|     name: "{{ item.key }}" | ||||
|     state: present | ||||
|     uid: "{{ item.value.uid }}" | ||||
|     group: "{{ item.value.gid }}" | ||||
|     shell: "{{ item.value.shell | default('/bin/bash') }}" | ||||
|     create_home: "{{ item.value.home | default(false) }}" | ||||
|     system: "{{ item.value.system | default(false) }}" | ||||
|   loop: "{{ users | dict2items }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.key }}" | ||||
|   when: users is defined | ||||
|  | ||||
| - name: Set authorized_keys for system users | ||||
|   ansible.posix.authorized_key: | ||||
|     user: "{{ item.key }}" | ||||
|     key: "{{ item.value.key }}" | ||||
|     state: present | ||||
|   loop: "{{ users | dict2items }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.key }}" | ||||
|   when: users is defined and item.value.key is defined | ||||
|  | ||||
| - name: Manage filesystem mounts | ||||
|   mount: | ||||
|   ansible.posix.mount: | ||||
|     path: "{{ item.path }}" | ||||
|     src: "UUID={{ item.uuid }}" | ||||
|     fstype: "{{ item.fstype }}" | ||||
|   | ||||
| @@ -1,51 +1,39 @@ | ||||
| # Copyright (C) 2021  Kris Lamoureux | ||||
| # | ||||
| # This program is free software: you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation, version 3 of the License. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| - name: Add Debian Buster backports | ||||
|   copy: | ||||
|     src: buster-backports.list | ||||
|     dest: /etc/apt/sources.list.d/buster-backports.list | ||||
|     owner: root | ||||
|     group: root | ||||
|     mode: '0644' | ||||
|  | ||||
| - name: Install WireGuard | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: wireguard | ||||
|     state: present | ||||
|     update_cache: true | ||||
|  | ||||
| - name: Generate WireGuard keys | ||||
|   shell: wg genkey | tee privatekey | wg pubkey > publickey | ||||
|   ansible.builtin.shell: | | ||||
|     set -o pipefail | ||||
|     wg genkey | tee privatekey | wg pubkey > publickey | ||||
|   args: | ||||
|     chdir: /etc/wireguard/ | ||||
|     creates: /etc/wireguard/privatekey | ||||
|     executable: /usr/bin/bash | ||||
|  | ||||
| - name: Grab WireGuard private key for configuration | ||||
|   slurp: | ||||
|   ansible.builtin.slurp: | ||||
|     src: /etc/wireguard/privatekey | ||||
|   register: wgkey | ||||
|  | ||||
| - name: Install WireGuard configuration | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: wireguard.j2 | ||||
|     dest: /etc/wireguard/wg0.conf | ||||
|   notify: | ||||
|     - restart_wireguard | ||||
|     mode: "400" | ||||
|   notify: restart_wireguard | ||||
|  | ||||
| - name: Start WireGuard interface | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: wg-quick@wg0 | ||||
|     state: started | ||||
|     enabled: true | ||||
|  | ||||
| - name: Add WireGuard firewall rule | ||||
|   community.general.ufw: | ||||
|     rule: allow | ||||
|     port: "{{ wireguard.listenport }}" | ||||
|     proto: udp | ||||
|   when: wireguard.listenport is defined | ||||
|   | ||||
							
								
								
									
										2
									
								
								roles/base/templates/fail2ban-allowlist.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								roles/base/templates/fail2ban-allowlist.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| [DEFAULT] | ||||
| ignoreip = {% for host in fail2ban_ignoreip %}{{ host }}{% if not loop.last %} {% endif %}{% endfor %} | ||||
							
								
								
									
										3
									
								
								roles/base/templates/fail2ban-ssh.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								roles/base/templates/fail2ban-ssh.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| [sshd] | ||||
| mode = aggressive | ||||
| enabled = true | ||||
							
								
								
									
										28
									
								
								roles/base/templates/smb.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								roles/base/templates/smb.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| [global] | ||||
|    workgroup = WORKGROUP | ||||
|    server string = Samba Server %v | ||||
|    netbios name = {{ ansible_hostname }} | ||||
|    security = user | ||||
|    map to guest = bad user | ||||
|    dns proxy = no | ||||
| {% for user in samba.users %} | ||||
|    smb encrypt = {{ 'mandatory' if user.encrypt | default(false) else 'disabled' }} | ||||
| {% endfor %} | ||||
|  | ||||
| {% for share in samba.shares %} | ||||
| [{{ share.name }}] | ||||
|    path = {{ share.path }} | ||||
|    browsable = yes | ||||
| {% if share.guest_allow is defined and share.guest_allow %} | ||||
|    guest ok = yes | ||||
| {% else %} | ||||
|    guest ok = no | ||||
| {% endif %} | ||||
|    read only = {{ 'yes' if share.read_only | default(false) else 'no' }} | ||||
| {% if share.valid_users is defined %} | ||||
|    valid users = {{ share.valid_users }} | ||||
| {% endif %} | ||||
| {% if share.force_user is defined %} | ||||
|    force user = {{ share.force_user }} | ||||
| {% endif %} | ||||
| {% endfor %} | ||||
| @@ -1,4 +1,8 @@ | ||||
| bitwarden_name: bitwarden | ||||
| bitwarden_root: "/opt/{{ bitwarden_name }}" | ||||
| bitwarden_root: "/var/lib/{{ bitwarden_name }}" | ||||
| bitwarden_logs_identity: "{{ bitwarden_root }}/bwdata/logs/identity/Identity" | ||||
| bitwarden_logs_identity_date: "{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}" | ||||
| bitwarden_database: "{{ bitwarden_name }}" | ||||
| bitwarden_realips: "172.16.0.0/12" | ||||
| bitwarden_standalone: false | ||||
| bitwarden_production: false | ||||
|   | ||||
| @@ -1,7 +1,28 @@ | ||||
| - name: Rebuild Bitwarden | ||||
|   shell: "{{ bitwarden_root }}/bitwarden.sh rebuild" | ||||
| - name: Stop Bitwarden for rebuild | ||||
|   ansible.builtin.service: | ||||
|     name: "{{ bitwarden_name }}" | ||||
|     state: stopped | ||||
|   listen: rebuild_bitwarden | ||||
|  | ||||
| - name: Start Bitwarden | ||||
|   shell: "{{ bitwarden_root }}/bitwarden.sh start" | ||||
|   listen: start_bitwarden | ||||
| - name: Rebuild Bitwarden | ||||
|   ansible.builtin.command: "{{ bitwarden_root }}/bitwarden.sh rebuild" | ||||
|   listen: rebuild_bitwarden | ||||
|  | ||||
| - name: Reload systemd manager configuration | ||||
|   ansible.builtin.systemd: | ||||
|     daemon_reload: true | ||||
|   listen: rebuild_bitwarden | ||||
|  | ||||
| - name: Start Bitwarden after rebuild | ||||
|   ansible.builtin.service: | ||||
|     name: "{{ bitwarden_name }}" | ||||
|     state: started | ||||
|     enabled: true | ||||
|   listen: rebuild_bitwarden | ||||
|  | ||||
| - name: Create Bitwarden's initial log file | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ bitwarden_logs_identity }}/{{ bitwarden_logs_identity_date }}.txt" | ||||
|     state: touch | ||||
|     mode: "644" | ||||
|   listen: touch_bitwarden | ||||
|   | ||||
| @@ -1,76 +1,97 @@ | ||||
| - name: Install expect | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: expect | ||||
|     state: present | ||||
|  | ||||
| - name: Create Bitwarden directory | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ bitwarden_root }}" | ||||
|     state: directory | ||||
|     mode: "755" | ||||
|  | ||||
| - name: Download Bitwarden script | ||||
|   get_url: | ||||
|   ansible.builtin.get_url: | ||||
|     url: "https://raw.githubusercontent.com/\ | ||||
|           bitwarden/server/master/scripts/bitwarden.sh" | ||||
|           bitwarden/self-host/master/bitwarden.sh" | ||||
|     dest: "{{ bitwarden_root }}" | ||||
|     mode: u+x | ||||
|  | ||||
| - name: Install Bitwarden script wrapper | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: bw_wrapper.j2 | ||||
|     dest: "{{ bitwarden_root }}/bw_wrapper" | ||||
|     mode: u+x | ||||
|  | ||||
| - name: Run Bitwarden installation script | ||||
|   shell: "{{ bitwarden_root }}/bw_wrapper" | ||||
|   ansible.builtin.command: "{{ bitwarden_root }}/bw_wrapper" | ||||
|   args: | ||||
|     creates: "{{ bitwarden_root }}/bwdata/config.yml" | ||||
|   notify: start_bitwarden | ||||
|  | ||||
| - name: Install docker-compose override | ||||
|   template: | ||||
| - name: Install compose override | ||||
|   ansible.builtin.template: | ||||
|     src: compose.override.yml.j2 | ||||
|     dest: "{{ bitwarden_root }}/bwdata/docker/docker-compose.override.yml" | ||||
|   notify: | ||||
|     - rebuild_bitwarden | ||||
|     - start_bitwarden | ||||
|     mode: "644" | ||||
|   when: bitwarden_override | default(true) | ||||
|   notify: rebuild_bitwarden | ||||
|  | ||||
| - name: Disable bitwarden-nginx HTTP on 80 | ||||
|   replace: | ||||
|   ansible.builtin.replace: | ||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||
|     regexp: "^http_port: 80$" | ||||
|     replace: "http_port: 8080" | ||||
|     replace: "http_port: {{ bitwarden_http_port | default('127.0.0.1:9080') }}" | ||||
|   when: not bitwarden_standalone | ||||
|   notify: | ||||
|     - rebuild_bitwarden | ||||
|     - start_bitwarden | ||||
|   notify: rebuild_bitwarden | ||||
|  | ||||
| - name: Disable bitwarden-nginx HTTPS on 443 | ||||
|   replace: | ||||
|   ansible.builtin.replace: | ||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||
|     regexp: "^https_port: 443$" | ||||
|     replace: "https_port: 8443" | ||||
|     replace: "https_port: {{ bitwarden_https_port | default('127.0.0.1:9443') }}" | ||||
|   when: not bitwarden_standalone | ||||
|   notify: | ||||
|     - rebuild_bitwarden | ||||
|     - start_bitwarden | ||||
|   notify: rebuild_bitwarden | ||||
|  | ||||
| - name: Disable Bitwarden managed Lets Encrypt | ||||
|   replace: | ||||
|   ansible.builtin.replace: | ||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||
|     regexp: "^ssl_managed_lets_encrypt: true$" | ||||
|     replace: "ssl_managed_lets_encrypt: false" | ||||
|   when: not bitwarden_standalone or not bitwarden_production | ||||
|   notify: | ||||
|     - rebuild_bitwarden | ||||
|     - start_bitwarden | ||||
|   notify: rebuild_bitwarden | ||||
|  | ||||
| - name: Disable Bitwarden managed SSL | ||||
|   replace: | ||||
|   ansible.builtin.replace: | ||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||
|     regexp: "^ssl: true$" | ||||
|     replace: "ssl: false" | ||||
|   when: not bitwarden_standalone | ||||
|   notify: | ||||
|     - rebuild_bitwarden | ||||
|     - start_bitwarden | ||||
|   notify: rebuild_bitwarden | ||||
|  | ||||
| - name: Define reverse proxy servers | ||||
|   ansible.builtin.lineinfile: | ||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||
|     line: "- {{ bitwarden_realips }}" | ||||
|     insertafter: "^real_ips" | ||||
|   notify: rebuild_bitwarden | ||||
|  | ||||
| - name: Install Bitwarden systemd service | ||||
|   ansible.builtin.template: | ||||
|     src: bitwarden.service.j2 | ||||
|     dest: "/etc/systemd/system/{{ bitwarden_name }}.service" | ||||
|     mode: "644" | ||||
|   register: bitwarden_systemd | ||||
|   notify: rebuild_bitwarden | ||||
|  | ||||
| - name: Create Bitwarden's initial logging directory | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ bitwarden_logs_identity }}" | ||||
|     state: directory | ||||
|     mode: "755" | ||||
|   notify: touch_bitwarden | ||||
|  | ||||
| - name: Install Bitwarden's Fail2ban jail | ||||
|   ansible.builtin.template: | ||||
|     src: fail2ban-jail.conf.j2 | ||||
|     dest: /etc/fail2ban/jail.d/bitwarden.conf | ||||
|     mode: "640" | ||||
|   notify: restart_fail2ban | ||||
|   | ||||
							
								
								
									
										13
									
								
								roles/bitwarden/templates/bitwarden.service.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								roles/bitwarden/templates/bitwarden.service.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| [Unit] | ||||
| Description=Bitwarden Password Manager Server | ||||
| PartOf=docker.service | ||||
| After=docker.service | ||||
|  | ||||
| [Service] | ||||
| Type=oneshot | ||||
| RemainAfterExit=true | ||||
| ExecStart={{ bitwarden_root }}/bitwarden.sh start | ||||
| ExecStop={{ bitwarden_root }}/bitwarden.sh stop | ||||
|  | ||||
| [Install] | ||||
| WantedBy=multi-user.target | ||||
| @@ -14,16 +14,22 @@ send "y\r" | ||||
| send "n\r" | ||||
| {% endif %} | ||||
|  | ||||
| expect "Enter the database name for your Bitwarden instance (ex. vault):" | ||||
| send "{{ bitwarden_database }}\r" | ||||
|  | ||||
| expect "Enter your installation id (get at https://bitwarden.com/host):" | ||||
| send "{{ bitwarden_install_id }}\r" | ||||
|  | ||||
| expect "Enter your installation key:" | ||||
| send "{{ bitwarden_install_key }}\r" | ||||
|  | ||||
| expect "Do you have a SSL certificate to use? (y/n):" | ||||
| expect "Enter your region (US/EU) \\\[US\\\]:" | ||||
| send "US\r" | ||||
|  | ||||
| expect "Do you have a SSL certificate to use? (y/N):" | ||||
| send "n\r" | ||||
|  | ||||
| expect "Do you want to generate a self-signed SSL certificate? (y/n):" | ||||
| expect "Do you want to generate a self-signed SSL certificate? (y/N):" | ||||
| {% if bitwarden_standalone and not bitwarden_production %} | ||||
| send "y\r" | ||||
| {% else %} | ||||
|   | ||||
| @@ -1,16 +1,16 @@ | ||||
| version: '3' | ||||
|  | ||||
| services: | ||||
|   nginx: | ||||
|     networks: | ||||
|       - traefik | ||||
|     labels: | ||||
|       traefik.http.routers.bitwarden.rule: "Host(`{{ bitwarden_domain }}`)" | ||||
|       traefik.http.routers.bitwarden.entrypoints: websecure | ||||
|       traefik.http.routers.bitwarden.tls.certresolver: letsencrypt | ||||
|       traefik.http.routers.bitwarden.middlewares: "securehttps@file" | ||||
|       traefik.http.routers.bitwarden.entrypoints: {{ bitwarden_entrypoint | default('web') }} | ||||
|       traefik.http.routers.bitwarden.tls: {{ bitwarden_traefik_tls | default('false') }} | ||||
|       traefik.http.services.bitwarden.loadbalancer.server.port: 8080 | ||||
|       traefik.docker.network: traefik | ||||
|       traefik.enable: "true" | ||||
|  | ||||
| networks: | ||||
|   traefik: | ||||
|     external: true | ||||
|   | ||||
							
								
								
									
										9
									
								
								roles/bitwarden/templates/fail2ban-jail.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								roles/bitwarden/templates/fail2ban-jail.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # {{ ansible_managed }} | ||||
| [bitwarden] | ||||
| enabled = true | ||||
| filter = bitwarden | ||||
| logpath = {{ bitwarden_root }}/bwdata/logs/identity/Identity/* | ||||
| maxretry = 10 | ||||
| findtime = 3600 | ||||
| bantime = 900 | ||||
| action = iptables-allports | ||||
							
								
								
									
										11
									
								
								roles/docker/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								roles/docker/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| docker_apt_keyring: /etc/apt/keyrings/docker.asc | ||||
| docker_apt_keyring_hash: 1500c1f56fa9e26b9b8f42452a553675796ade0807cdce11975eb98170b3a570 | ||||
| docker_apt_keyring_url: https://download.docker.com/linux/debian/gpg | ||||
| docker_apt_repo: https://download.docker.com/linux/debian | ||||
| docker_compose_root: /var/lib/compose | ||||
| docker_compose_service: compose | ||||
| docker_compose: "{{ (docker_official | bool) | ternary('/usr/bin/docker compose', '/usr/bin/docker-compose') }}" | ||||
| docker_official: false | ||||
| docker_repos_keys: "{{ docker_repos_path }}/.keys" | ||||
| docker_repos_keytype: rsa | ||||
| docker_repos_path: /srv/.compose_repos | ||||
| @@ -1 +0,0 @@ | ||||
| deb [arch=amd64] https://download.docker.com/linux/debian buster stable | ||||
							
								
								
									
										54
									
								
								roles/docker/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								roles/docker/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| - name: Reload systemd manager configuration | ||||
|   ansible.builtin.systemd: | ||||
|     daemon_reload: true | ||||
|   listen: compose_systemd | ||||
|  | ||||
| - name: Find which services had a docker-compose.yml updated | ||||
|   ansible.builtin.set_fact: | ||||
|     compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}" | ||||
|   loop: "{{ compose_update.results }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.item.name }}" | ||||
|   when: item.changed | ||||
|   listen: compose_restart | ||||
|  | ||||
| - name: Find which services had their .env updated | ||||
|   ansible.builtin.set_fact: | ||||
|     compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}" | ||||
|   loop: "{{ compose_env_update.results }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.item.name }}" | ||||
|   when: item.changed | ||||
|   listen: compose_restart | ||||
|  | ||||
| - name: Restart MariaDB | ||||
|   ansible.builtin.service: | ||||
|     name: mariadb | ||||
|     state: restarted | ||||
|   when: not mariadb_restarted | ||||
|   listen: restart_mariadb # hijack handler for early restart | ||||
|  | ||||
| - name: Set MariaDB as restarted | ||||
|   ansible.builtin.set_fact: | ||||
|     mariadb_restarted: true | ||||
|   when: not mariadb_restarted | ||||
|   listen: restart_mariadb | ||||
|  | ||||
| - name: Restart compose services | ||||
|   ansible.builtin.systemd: | ||||
|     state: restarted | ||||
|     name: "{{ docker_compose_service }}@{{ item }}" | ||||
|   loop: "{{ compose_restart_list | default([]) | unique }}" | ||||
|   when: compose_restart_list is defined | ||||
|   listen: compose_restart | ||||
|  | ||||
| - name: Start compose services and enable on boot | ||||
|   ansible.builtin.service: | ||||
|     name: "{{ docker_compose_service }}@{{ item.name }}" | ||||
|     state: started | ||||
|     enabled: true | ||||
|   loop: "{{ docker_compose_deploy }}" | ||||
|   loop_control: | ||||
|     label: "{{ docker_compose_service }}@{{ item.name }}" | ||||
|   when: item.enabled is defined and item.enabled is true | ||||
|   listen: compose_enable | ||||
| @@ -1,38 +0,0 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| # Github username and repo name | ||||
| user="docker" | ||||
| repo="compose" | ||||
|  | ||||
| # Retrieve the latest version number | ||||
| addr="https://github.com/$user/$repo/releases/latest" | ||||
| page=$(curl -s $addr | grep -o releases/tag/*.*\") | ||||
| version=$(echo $page | awk '{print substr($1, 14, length($1) - 14)}') | ||||
|  | ||||
| # Download prep | ||||
| url="https://github.com/$user/$repo/releases/download/$version" | ||||
| file="docker-compose-$(uname -s)-$(uname -m)" | ||||
|  | ||||
| # Download latest Docker Compose if that version hasn't been downloaded | ||||
| if [ ! -f /tmp/docker_compose_$version ]; then | ||||
|   curl -L $url/$file -o /tmp/docker-compose_$version | ||||
| fi | ||||
|  | ||||
| # Is it already installed? | ||||
| if installed=$(which docker-compose); then | ||||
|  | ||||
|   new_chksum=$(sha256sum /tmp/docker-compose_$version) | ||||
|   old_chksum=$(sha256sum /usr/local/bin/docker-compose) | ||||
|  | ||||
|   # If checksums are different, delete and install new version | ||||
|   if [ ! "$new_chksum" = "$old_chksum" ]; then | ||||
|     rm /usr/local/bin/docker-compose | ||||
|     mv /tmp/docker-compose_$version /usr/local/bin/docker-compose | ||||
|     chmod +x /usr/local/bin/docker-compose | ||||
|   fi | ||||
|  | ||||
| else | ||||
|   # It's not installed, so no need to remove | ||||
|   mv /tmp/docker-compose_$version /usr/local/bin/docker-compose | ||||
|   chmod +x /usr/local/bin/docker-compose | ||||
| fi | ||||
| @@ -1,61 +1,151 @@ | ||||
| # Copyright (C) 2019  Kris Lamoureux | ||||
| # | ||||
| # This program is free software: you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation, version 3 of the License. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
| - name: Add official Docker APT key | ||||
|   ansible.builtin.get_url: | ||||
|     url: "{{ docker_apt_keyring_url }}" | ||||
|     dest: "{{ docker_apt_keyring }}" | ||||
|     checksum: "sha256:{{ docker_apt_keyring_hash }}" | ||||
|     mode: "644" | ||||
|     owner: root | ||||
|     group: root | ||||
|   when: docker_official | ||||
|  | ||||
| - name: Remove old versions of Docker | ||||
|   apt: | ||||
|     name: ['docker', 'docker-engine', 'docker.io', 'containerd', 'runc'] | ||||
| - name: Remove official Docker APT key | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ docker_apt_keyring }}" | ||||
|     state: absent | ||||
|   when: not docker_official | ||||
|  | ||||
| - name: Add/remove official Docker APT repository | ||||
|   ansible.builtin.apt_repository: | ||||
|     repo: > | ||||
|       deb [arch=amd64 signed-by={{ docker_apt_keyring }}] | ||||
|       {{ docker_apt_repo }} {{ ansible_distribution_release }} stable | ||||
|     state: "{{ 'present' if docker_official else 'absent' }}" | ||||
|     filename: "{{ docker_apt_keyring | regex_replace('^.*/', '') }}" | ||||
|  | ||||
| - name: Install/uninstall Docker from Debian repositories | ||||
|   ansible.builtin.apt: | ||||
|     name: ['docker.io', 'docker-compose', 'containerd', 'runc'] | ||||
|     state: "{{ 'absent' if docker_official else 'present' }}" | ||||
|     autoremove: true | ||||
|     update_cache: true | ||||
|  | ||||
| - name: Install HTTPS capability for apt | ||||
|   apt: | ||||
|     name: ['apt-transport-https', 'ca-certificates', | ||||
|            'curl', 'gnupg2', 'software-properties-common'] | ||||
|     state: present | ||||
|  | ||||
| - name: Install Docker's signing key | ||||
|   apt_key: | ||||
|     url: https://download.docker.com/linux/debian/gpg | ||||
|     id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88 | ||||
|     state: present | ||||
|  | ||||
| - name: Install Docker's stable repository | ||||
|   template: | ||||
|     src: docker-ce.list | ||||
|     dest: /etc/apt/sources.list.d/docker-ce.list | ||||
|  | ||||
| - name: Install Docker CE | ||||
|   apt: | ||||
|     name: ['docker-ce', 'docker-ce-cli', 'containerd.io'] | ||||
|     state: present | ||||
| - name: Install/uninstall Docker from Docker repositories | ||||
|   ansible.builtin.apt: | ||||
|     name: ['docker-ce', 'docker-ce-cli', 'containerd.io', | ||||
|            'docker-buildx-plugin', 'docker-compose-plugin'] | ||||
|     state: "{{ 'present' if docker_official else 'absent' }}" | ||||
|     autoremove: true | ||||
|     update_cache: true | ||||
|  | ||||
| - name: Login to private registry | ||||
|   community.docker.docker_login: | ||||
|     registry_url: "{{ docker_login_url | default('') }}" | ||||
|     username: "{{ docker_login_user }}" | ||||
|     password: "{{ docker_login_pass }}" | ||||
|   when: docker_login_user is defined and docker_login_pass is defined | ||||
|  | ||||
| - name: Create docker-compose root | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ docker_compose_root }}" | ||||
|     state: directory | ||||
|     mode: "500" | ||||
|  | ||||
| - name: Install docker-compose systemd service | ||||
|   ansible.builtin.template: | ||||
|     src: docker-compose.service.j2 | ||||
|     dest: "/etc/systemd/system/{{ docker_compose_service }}@.service" | ||||
|     mode: "400" | ||||
|   notify: compose_systemd | ||||
|  | ||||
| - name: Create directories to clone docker-compose repositories | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ item }}" | ||||
|     state: directory | ||||
|     mode: "400" | ||||
|   loop: | ||||
|     - "{{ docker_repos_path }}" | ||||
|     - "{{ docker_repos_keys }}" | ||||
|   when: docker_compose_deploy is defined | ||||
|  | ||||
| - name: Generate OpenSSH deploy keys for docker-compose clones | ||||
|   community.crypto.openssh_keypair: | ||||
|     path: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}" | ||||
|     type: "{{ docker_repos_keytype }}" | ||||
|     comment: "{{ ansible_hostname }}-deploy-key" | ||||
|     mode: "400" | ||||
|     state: present | ||||
|   when: docker_compose_deploy is defined | ||||
|  | ||||
| - name: Check for git installation | ||||
|   ansible.builtin.apt: | ||||
|     name: git | ||||
|     state: present | ||||
|   when: docker_compose_deploy is defined | ||||
|  | ||||
| - name: Clone external docker-compose projects | ||||
|   ansible.builtin.git: | ||||
|     repo: "{{ item.url }}" | ||||
|     dest: "{{ docker_repos_path }}/{{ item.name }}" | ||||
|     version: "{{ item.version }}" | ||||
|     accept_newhostkey: "{{ item.accept_newhostkey | default(false) }}" | ||||
|     gpg_whitelist: "{{ item.trusted_keys | default([]) }}" | ||||
|     verify_commit: "{{ true if (item.trusted_keys is defined and item.trusted_keys) else false }}" | ||||
|     key_file: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}" | ||||
|   loop: "{{ docker_compose_deploy }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.url }}" | ||||
|   when: docker_compose_deploy is defined | ||||
|  | ||||
| - name: Create directories for docker-compose projects using the systemd service | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ docker_compose_root }}/{{ item.name }}" | ||||
|     state: directory | ||||
|     mode: "400" | ||||
|   loop: "{{ docker_compose_deploy }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.name }}" | ||||
|   when: docker_compose_deploy is defined | ||||
|  | ||||
| - name: Synchronize docker-compose.yml | ||||
|   ansible.posix.synchronize: | ||||
|     src: "{{ docker_repos_path }}/{{ item.name }}/{{ item.path | default('docker-compose.yml') }}" | ||||
|     dest: "{{ docker_compose_root }}/{{ item.name }}/docker-compose.yml" | ||||
|   delegate_to: "{{ inventory_hostname }}" | ||||
|   register: compose_update | ||||
|   notify: | ||||
|     - compose_restart | ||||
|     - compose_enable | ||||
|   loop: "{{ docker_compose_deploy | default([]) }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.name }}" | ||||
|   when: docker_compose_deploy is defined and docker_compose_deploy | length > 0 | ||||
|  | ||||
| - name: Set environment variables for docker-compose projects | ||||
|   ansible.builtin.template: | ||||
|     src: docker-compose-env.j2 | ||||
|     dest: "{{ docker_compose_root }}/{{ item.name }}/.env" | ||||
|     mode: "400" | ||||
|   register: compose_env_update | ||||
|   notify: | ||||
|     - compose_restart | ||||
|     - compose_enable | ||||
|   no_log: "{{ docker_compose_env_nolog | default(true) }}" | ||||
|   loop: "{{ docker_compose_deploy }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.name }}" | ||||
|   when: docker_compose_deploy is defined and item.env is defined | ||||
|  | ||||
| - name: Add users to docker group | ||||
|   user: | ||||
|   ansible.builtin.user: | ||||
|     name: "{{ item }}" | ||||
|     groups: docker | ||||
|     append: true | ||||
|   loop: "{{ docker_users }}" | ||||
|   when: docker_users is defined | ||||
|  | ||||
| - name: Install docker-compose | ||||
|   script: install-compose.sh | ||||
|   args: | ||||
|     creates: /usr/local/bin/docker-compose | ||||
|  | ||||
| - name: Start Docker and enable on boot | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: docker | ||||
|     state: started | ||||
|     enabled: true | ||||
|   when: docker_managed | default(true) | ||||
|   | ||||
							
								
								
									
										10
									
								
								roles/docker/templates/docker-compose-env.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								roles/docker/templates/docker-compose-env.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| # {{ ansible_managed }} | ||||
| {% if item.env is defined %} | ||||
| {% for key, value in item.env.items() %} | ||||
| {% if value is boolean %} | ||||
| {{ key }}={{ value | lower }} | ||||
| {% else %} | ||||
| {{ key }}={{ value }} | ||||
| {% endif %} | ||||
| {% endfor %} | ||||
| {% endif %} | ||||
							
								
								
									
										14
									
								
								roles/docker/templates/docker-compose.service.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								roles/docker/templates/docker-compose.service.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| [Unit] | ||||
| Description=%i {{ docker_compose_service }} service | ||||
| PartOf=docker.service | ||||
| After=docker.service | ||||
|  | ||||
| [Service] | ||||
| Type=oneshot | ||||
| RemainAfterExit=true | ||||
| WorkingDirectory={{ docker_compose_root }}/%i | ||||
| ExecStart={{ docker_compose }} up -d --remove-orphans | ||||
| ExecStop={{ docker_compose }} down | ||||
|  | ||||
| [Install] | ||||
| WantedBy=multi-user.target | ||||
| @@ -1,11 +1,22 @@ | ||||
| # container settings | ||||
| gitea_name: gitea | ||||
| gitea_dbname: "{{ gitea_name }}-db" | ||||
| gitea_ports: "222:22" | ||||
| gitea_sshport: "222" | ||||
| gitea_webport: "3000" | ||||
| gitea_ssh: "127.0.0.1:{{ gitea_sshport }}" | ||||
| gitea_web: "127.0.0.1:{{ gitea_webport }}" | ||||
| gitea_volume: "{{ gitea_name }}" | ||||
| gitea_rooturl: "https://{{ gitea_domain }}" | ||||
| gitea_signup: true | ||||
|  | ||||
| # database settings | ||||
| gitea_dbuser: "{{ gitea_dbname }}" | ||||
| gitea_dbtype: mysql | ||||
| gitea_dbhost: host.docker.internal | ||||
| gitea_dbname: "{{ gitea_name }}" | ||||
| gitea_dbuser: "{{ gitea_name }}" | ||||
|  | ||||
| # proxy settings | ||||
| gitea_proxy_limit: "1" | ||||
| gitea_trusted_proxies: "172.16.0.0/12" | ||||
|  | ||||
| # host | ||||
| gitea_root: "/opt/{{ gitea_name }}/data" | ||||
| gitea_dbroot: "/opt/{{ gitea_name }}/database" | ||||
| gitea_root: "{{ docker_compose_root }}/{{ gitea_name }}" | ||||
|   | ||||
							
								
								
									
										5
									
								
								roles/gitea/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								roles/gitea/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| - name: Restart Gitea | ||||
|   ansible.builtin.service: | ||||
|     name: "{{ docker_compose_service }}@{{ gitea_name }}" | ||||
|     state: restarted | ||||
|   listen: restart_gitea | ||||
| @@ -1,53 +1,78 @@ | ||||
| - name: Create Gitea Network | ||||
|   docker_network: | ||||
|     name: "{{ gitea_name }}" | ||||
| - name: Install MySQL module for Ansible | ||||
|   ansible.builtin.apt: | ||||
|     name: python3-pymysql | ||||
|     state: present | ||||
|  | ||||
| - name: Start Gitea's database container | ||||
|   docker_container: | ||||
|     name: "{{ gitea_dbname }}" | ||||
|     image: mariadb:{{ gitea_dbversion }} | ||||
|     state: started | ||||
|     restart_policy: always | ||||
|     volumes: "{{ gitea_dbroot }}:/var/lib/mysql" | ||||
|     networks_cli_compatible: true | ||||
|     networks: | ||||
|       - name: "{{ gitea_name }}" | ||||
|     env: | ||||
|       MYSQL_RANDOM_ROOT_PASSWORD: "true" | ||||
|       MYSQL_DATABASE: "{{ gitea_dbname }}" | ||||
|       MYSQL_USER: "{{ gitea_dbuser }}" | ||||
|       MYSQL_PASSWORD: "{{ gitea_dbpass }}" | ||||
| - name: Create Gitea database | ||||
|   community.mysql.mysql_db: | ||||
|     name: "{{ gitea.DB_NAME }}" | ||||
|     state: present | ||||
|     login_unix_socket: /var/run/mysqld/mysqld.sock | ||||
|  | ||||
| - name: Start Gitea container | ||||
|   docker_container: | ||||
|     name: "{{ gitea_name }}" | ||||
|     image: gitea/gitea:{{ gitea_version }} | ||||
|     state: started | ||||
|     restart_policy: always | ||||
|     networks_cli_compatible: true | ||||
|     ports: "{{ gitea_ports }}" | ||||
|     networks: | ||||
|       - name: "{{ gitea_name }}" | ||||
|       - name: traefik | ||||
|     volumes: | ||||
|       - "{{ gitea_root }}:/data" | ||||
|       - /etc/timezone:/etc/timezone:ro | ||||
|       - /etc/localtime:/etc/localtime:ro | ||||
|     env: | ||||
|       USER_UID: "1000" | ||||
|       USER_GID: "1000" | ||||
|       DB_TYPE: mysql | ||||
|       DB_HOST: "{{ gitea_dbname }}" | ||||
|       DB_NAME: "{{ gitea_dbname }}" | ||||
|       DB_USER: "{{ gitea_dbuser }}" | ||||
|       DB_PASSWD: "{{ gitea_dbpass }}" | ||||
|       ROOT_URL: "https://{{ gitea_domain }}/" | ||||
|       SSH_DOMAIN: "{{ gitea_domain }}" | ||||
|       DOMAIN: "{{ gitea_domain }}" | ||||
|     labels: | ||||
|       traefik.http.routers.gitea.rule: "Host(`{{ gitea_domain }}`)" | ||||
|       traefik.http.routers.gitea.entrypoints: websecure | ||||
|       traefik.http.routers.gitea.middlewares: "securehttps@file" | ||||
|       traefik.http.services.gitea.loadbalancer.server.port: "3000" | ||||
|       traefik.docker.network: traefik | ||||
|       traefik.enable: "true" | ||||
| - name: Create Gitea database user | ||||
|   community.mysql.mysql_user: | ||||
|     name: "{{ gitea.DB_USER }}" | ||||
|     password: "{{ gitea.DB_PASSWD }}" | ||||
|     host: '%' | ||||
|     state: present | ||||
|     priv: "{{ gitea.DB_NAME }}.*:ALL" | ||||
|     login_unix_socket: /var/run/mysqld/mysqld.sock | ||||
|  | ||||
| - name: Create git's .ssh directory | ||||
|   ansible.builtin.file: | ||||
|     path: /home/git/.ssh | ||||
|     mode: "700" | ||||
|     state: directory | ||||
|  | ||||
| - name: Generate git's SSH keys | ||||
|   community.crypto.openssh_keypair: | ||||
|     path: /home/git/.ssh/id_rsa | ||||
|  | ||||
| - name: Find git's public SSH key | ||||
|   ansible.builtin.slurp: | ||||
|     src: /home/git/.ssh/id_rsa.pub | ||||
|   register: git_rsapub | ||||
|  | ||||
| - name: Get stats on git's authorized_keys file | ||||
|   ansible.builtin.stat: | ||||
|     path: /home/git/.ssh/authorized_keys | ||||
|   register: git_authkeys | ||||
|  | ||||
| - name: Create git's authorized_keys file | ||||
|   ansible.builtin.file: | ||||
|     path: /home/git/.ssh/authorized_keys | ||||
|     mode: "600" | ||||
|     state: touch | ||||
|   when: not git_authkeys.stat.exists | ||||
|  | ||||
| - name: Add git's public SSH key to authorized_keys | ||||
|   ansible.builtin.lineinfile: | ||||
|     path: /home/git/.ssh/authorized_keys | ||||
|     regex: "^ssh-rsa" | ||||
|     line: "{{ git_rsapub['content'] | b64decode }}" | ||||
|  | ||||
| - name: Create Gitea host script for SSH | ||||
|   ansible.builtin.template: | ||||
|     src: gitea.sh.j2 | ||||
|     dest: /usr/local/bin/gitea | ||||
|     mode: "755" | ||||
|  | ||||
| - name: Create Gitea's logging directory | ||||
|   ansible.builtin.file: | ||||
|     name: /var/log/gitea | ||||
|     state: directory | ||||
|     mode: "755" | ||||
|  | ||||
| - name: Install Gitea's Fail2ban filter | ||||
|   ansible.builtin.template: | ||||
|     src: fail2ban-filter.conf.j2 | ||||
|     dest: /etc/fail2ban/filter.d/gitea.conf | ||||
|     mode: "644" | ||||
|   notify: restart_fail2ban | ||||
|  | ||||
| - name: Install Gitea's Fail2ban jail | ||||
|   ansible.builtin.template: | ||||
|     src: fail2ban-jail.conf.j2 | ||||
|     dest: /etc/fail2ban/jail.d/gitea.conf | ||||
|     mode: "640" | ||||
|   notify: restart_fail2ban | ||||
|   | ||||
							
								
								
									
										19
									
								
								roles/gitea/templates/compose-env.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								roles/gitea/templates/compose-env.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # {{ ansible_managed }} | ||||
| gitea_version={{ gitea_version }} | ||||
| gitea_name={{ gitea_name }} | ||||
| gitea_domain={{ gitea_domain }} | ||||
| gitea_rooturl={{ gitea_rooturl }} | ||||
| gitea_web={{ gitea_web }} | ||||
| gitea_ssh={{ gitea_ssh }} | ||||
| gitea_dbtype={{ gitea_dbtype }} | ||||
| gitea_dbhost={{ gitea_dbhost }} | ||||
| gitea_dbname={{ gitea_dbname }} | ||||
| gitea_dbuser={{ gitea_dbuser }} | ||||
| gitea_dbpass={{ gitea_dbpass }} | ||||
| gitea_proxy_limit={{ gitea_proxy_limit }} | ||||
| gitea_trusted_proxies={{ gitea_trusted_proxies }} | ||||
| {% if not gitea_signup %} | ||||
| gitea_disable_registration=true | ||||
| {% else %} | ||||
| gitea_disable_registration=false | ||||
| {% endif %} | ||||
							
								
								
									
										36
									
								
								roles/gitea/templates/docker-compose.yml.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								roles/gitea/templates/docker-compose.yml.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| version: '3.7' | ||||
|  | ||||
| services: | ||||
|   gitea: | ||||
|     image: "gitea/gitea:${gitea_version}" | ||||
|     container_name: "${gitea_name}" | ||||
|     ports: | ||||
|       - "${gitea_ssh}:22" | ||||
|       - "${gitea_web}:3000" | ||||
|     extra_hosts: | ||||
|       - "host.docker.internal:host-gateway" | ||||
|     environment: | ||||
|       - USER_UID={{ getent_passwd.git[1] }} | ||||
|       - USER_GID={{ getent_group.git[1] }} | ||||
|       - GITEA__log__MODE=file | ||||
|       - GITEA__server__ROOT_URL=${gitea_rooturl} | ||||
|       - GITEA__server__DOMAIN=${gitea_domain} | ||||
|       - GITEA__server__SSH_DOMAIN=${gitea_domain} | ||||
|       - GITEA__database__DB_TYPE=${gitea_dbtype} | ||||
|       - GITEA__database__HOST=${gitea_dbhost} | ||||
|       - GITEA__database__NAME=${gitea_dbname} | ||||
|       - GITEA__database__USER=${gitea_dbuser} | ||||
|       - GITEA__database__PASSWD=${gitea_dbpass} | ||||
|       - GITEA__security__INSTALL_LOCK=true | ||||
|       - GITEA__security__REVERSE_PROXY_LIMIT=${gitea_proxy_limit} | ||||
|       - GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES=${gitea_trusted_proxies} | ||||
|       - GITEA__service__DISABLE_REGISTRATION=${gitea_disable_registration} | ||||
|     volumes: | ||||
|       - {{ gitea_volume }}:/data | ||||
|       - /home/git/.ssh:/data/git/.ssh | ||||
|       - /var/log/gitea:/data/gitea/log | ||||
|       - /etc/timezone:/etc/timezone:ro | ||||
|       - /etc/localtime:/etc/localtime:ro | ||||
|  | ||||
| volumes: | ||||
|   {{ gitea_volume }}: | ||||
							
								
								
									
										4
									
								
								roles/gitea/templates/fail2ban-filter.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								roles/gitea/templates/fail2ban-filter.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| # {{ ansible_managed }} | ||||
| [Definition] | ||||
| failregex =  .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST> | ||||
| ignoreregex = | ||||
							
								
								
									
										18
									
								
								roles/gitea/templates/fail2ban-jail.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								roles/gitea/templates/fail2ban-jail.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # {{ ansible_managed }} | ||||
| [gitea] | ||||
| enabled = true | ||||
| filter = gitea | ||||
| logpath = /var/log/gitea/gitea.log | ||||
| maxretry = 10 | ||||
| findtime = 3600 | ||||
| bantime = 900 | ||||
| action = iptables-allports | ||||
|  | ||||
| [gitea-docker] | ||||
| enabled = true | ||||
| filter = gitea | ||||
| logpath = /var/log/gitea/gitea.log | ||||
| maxretry = 10 | ||||
| findtime = 3600 | ||||
| bantime = 900 | ||||
| action = iptables-allports[chain="FORWARD"] | ||||
							
								
								
									
										2
									
								
								roles/gitea/templates/gitea.sh.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								roles/gitea/templates/gitea.sh.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #!/bin/sh | ||||
| ssh -p {{ gitea_sshport }} -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@" | ||||
							
								
								
									
										4
									
								
								roles/jellyfin/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								roles/jellyfin/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| jellyfin_name: jellyfin | ||||
| jellyfin_router: "{{ jellyfin_name }}" | ||||
| jellyfin_rooturl: "https://{{ jellyfin_domain }}" | ||||
| jellyfin_root: "{{ docker_compose_root }}/{{ jellyfin_name }}" | ||||
							
								
								
									
										5
									
								
								roles/jellyfin/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								roles/jellyfin/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| - name: Restart Jellyfin | ||||
|   ansible.builtin.service: | ||||
|     name: "{{ docker_compose_service }}@{{ jellyfin_name }}" | ||||
|     state: restarted | ||||
|   listen: restart_jellyfin | ||||
							
								
								
									
										35
									
								
								roles/jellyfin/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								roles/jellyfin/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| - name: Create Jellyfin directory | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ jellyfin_root }}" | ||||
|     state: directory | ||||
|     mode: 0500 | ||||
|  | ||||
| - name: Get user jellyfin uid | ||||
|   ansible.builtin.getent: | ||||
|     database: passwd | ||||
|     key: jellyfin | ||||
|  | ||||
| - name: Get user jellyfin gid | ||||
|   ansible.builtin.getent: | ||||
|     database: group | ||||
|     key: jellyfin | ||||
|  | ||||
| - name: Install Jellyfin's docker-compose file | ||||
|   ansible.builtin.template: | ||||
|     src: docker-compose.yml.j2 | ||||
|     dest: "{{ jellyfin_root }}/docker-compose.yml" | ||||
|     mode: 0400 | ||||
|   notify: restart_jellyfin | ||||
|  | ||||
| - name: Install Jellyfin's docker-compose variables | ||||
|   ansible.builtin.template: | ||||
|     src: compose-env.j2 | ||||
|     dest: "{{ jellyfin_root }}/.env" | ||||
|     mode: 0400 | ||||
|   notify: restart_jellyfin | ||||
|  | ||||
| - name: Start and enable Jellyfin service | ||||
|   ansible.builtin.service: | ||||
|     name: "{{ docker_compose_service }}@{{ jellyfin_name }}" | ||||
|     state: started | ||||
|     enabled: true | ||||
							
								
								
									
										5
									
								
								roles/jellyfin/templates/compose-env.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								roles/jellyfin/templates/compose-env.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| # {{ ansible_managed }} | ||||
| jellyfin_version={{ jellyfin_version }} | ||||
| jellyfin_name={{ jellyfin_name }} | ||||
| jellyfin_domain={{ jellyfin_domain }} | ||||
| jellyfin_rooturl={{ jellyfin_rooturl }} | ||||
							
								
								
									
										30
									
								
								roles/jellyfin/templates/docker-compose.yml.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								roles/jellyfin/templates/docker-compose.yml.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| version: '3.7' | ||||
|  | ||||
| volumes: | ||||
|   config: | ||||
|   cache: | ||||
|  | ||||
| networks: | ||||
|   traefik: | ||||
|     external: true | ||||
|  | ||||
| services: | ||||
|   jellyfin: | ||||
|     image: "jellyfin/jellyfin:${jellyfin_version}" | ||||
|     container_name: "${jellyfin_name}" | ||||
|     networks: | ||||
|       - traefik | ||||
|     labels: | ||||
|       - "traefik.http.routers.{{ jellyfin_router }}.rule=Host(`{{ jellyfin_domain }}`)" | ||||
| {% if traefik_http_only %} | ||||
|       - "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web" | ||||
| {% else %} | ||||
|       - "traefik.http.routers.{{ jellyfin_router }}.entrypoints=websecure" | ||||
| {% endif %} | ||||
|       - "traefik.http.services.{{ jellyfin_router }}.loadbalancer.server.port=8096" | ||||
|       - "traefik.docker.network=traefik" | ||||
|       - "traefik.enable=true" | ||||
|     volumes: | ||||
|       - config:/config | ||||
|       - cache:/cache | ||||
|       - {{ jellyfin_media }}:/media | ||||
| @@ -1 +0,0 @@ | ||||
| deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main | ||||
| @@ -1,10 +1,5 @@ | ||||
| - name: Install GnuPG | ||||
|   apt: | ||||
|     name: gnupg | ||||
|     state: present | ||||
|  | ||||
| - name: Create Jenkins user | ||||
|   user: | ||||
|   ansible.builtin.user: | ||||
|     name: "{{ jenkins_user }}" | ||||
|     state: present | ||||
|     shell: /bin/bash | ||||
| @@ -12,35 +7,25 @@ | ||||
|     generate_ssh_key: true | ||||
|  | ||||
| - name: Set Jenkins authorized key | ||||
|   authorized_key: | ||||
|   ansible.posix.authorized_key: | ||||
|     user: jenkins | ||||
|     state: present | ||||
|     exclusive: true | ||||
|     key: "{{ jenkins_sshkey }}" | ||||
|  | ||||
| - name: Give Jenkins user passwordless sudo | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: jenkins_sudoers.j2 | ||||
|     dest: /etc/sudoers.d/{{ jenkins_user }} | ||||
|     validate: "visudo -cf %s" | ||||
|     mode: 0440 | ||||
|  | ||||
| - name: Install Ansible source | ||||
|   copy: | ||||
|     src: ansible.list | ||||
|     dest: /etc/apt/sources.list.d/ansible.list | ||||
|  | ||||
| - name: Add Ansible source key | ||||
|   apt_key: | ||||
|     keyserver: keyserver.ubuntu.com | ||||
|     id: 93C4A3FD7BB9C367 | ||||
|  | ||||
| - name: Install Ansible | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: ansible | ||||
|     state: present | ||||
|  | ||||
| - name: Install Java | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: default-jre | ||||
|     state: present | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| - import_tasks: agent.yml | ||||
| - ansible.builtin.import_tasks: agent.yml | ||||
|   when: jenkins_sshkey is defined | ||||
|  | ||||
| - import_tasks: server.yml | ||||
| - ansible.builtin.import_tasks: server.yml | ||||
|   when: jenkins_domain is defined | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| - name: Create Jenkin's directory | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ jenkins_root }}" | ||||
|     state: directory | ||||
|     owner: "1000" | ||||
|     group: "1000" | ||||
|  | ||||
| - name: Start Jenkins Container | ||||
|   docker_container: | ||||
|   community.general.docker_container: | ||||
|     name: "{{ jenkins_name }}" | ||||
|     image: jenkins/jenkins:{{ jenkins_version }} | ||||
|     state: started | ||||
| @@ -20,6 +20,7 @@ | ||||
|     labels: | ||||
|       traefik.http.routers.jenkins.rule: "Host(`{{ jenkins_domain }}`)" | ||||
|       traefik.http.routers.jenkins.entrypoints: websecure | ||||
|       traefik.http.routers.jenkins.tls.certresolver: letsencrypt | ||||
|       traefik.http.routers.jenkins.middlewares: "securehttps@file" | ||||
|       traefik.docker.network: traefik | ||||
|       traefik.enable: "true" | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| - name: Install QEMU/KVM | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: qemu-kvm | ||||
|     state: present | ||||
|  | ||||
| - name: Install Libvirt | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: ["libvirt-clients", "libvirt-daemon-system"] | ||||
|     state: present | ||||
|  | ||||
| - name: Add users to libvirt group | ||||
|   user: | ||||
|   ansible.builtin.user: | ||||
|     name: "{{ item }}" | ||||
|     groups: libvirt | ||||
|     append: yes | ||||
| @@ -17,12 +17,12 @@ | ||||
|   when: libvirt_users is defined | ||||
|  | ||||
| - name: Check for NODOWNLOAD file | ||||
|   stat: | ||||
|   ansible.builtin.stat: | ||||
|     path: /var/lib/libvirt/images/NODOWNLOAD | ||||
|   register: NODOWNLOAD | ||||
|  | ||||
| - name: Download GNU/Linux ISOs | ||||
|   get_url: | ||||
|   ansible.builtin.get_url: | ||||
|     url: "{{ item.url }}" | ||||
|     dest: /var/lib/libvirt/images | ||||
|     checksum: "{{ item.hash }}" | ||||
| @@ -34,7 +34,7 @@ | ||||
|  | ||||
| # Prevent downloaded ISOs from being rehashed every run | ||||
| - name: Create NODOWNLOAD file | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: /var/lib/libvirt/images/NODOWNLOAD | ||||
|     state: touch | ||||
|   when: download_isos.changed | ||||
|   | ||||
							
								
								
									
										12
									
								
								roles/mariadb/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								roles/mariadb/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| - name: Restart MariaDB | ||||
|   ansible.builtin.service: | ||||
|     name: mariadb | ||||
|     state: restarted | ||||
|   when: not mariadb_restarted | ||||
|   listen: restart_mariadb | ||||
|  | ||||
| - name: Set MariaDB as restarted | ||||
|   ansible.builtin.set_fact: | ||||
|     mariadb_restarted: true | ||||
|   when: not mariadb_restarted | ||||
|   listen: restart_mariadb | ||||
							
								
								
									
										26
									
								
								roles/mariadb/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								roles/mariadb/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| - name: Install MariaDB | ||||
|   ansible.builtin.apt: | ||||
|     name: mariadb-server | ||||
|     state: present | ||||
|  | ||||
| - name: Set MariaDB restarted fact | ||||
|   ansible.builtin.set_fact: | ||||
|     mariadb_restarted: false | ||||
|  | ||||
| - name: Regather facts for the potentially new docker0 interface | ||||
|   ansible.builtin.setup: | ||||
|  | ||||
| - name: Change the bind-address to allow from docker0 | ||||
|   ansible.builtin.lineinfile: | ||||
|     path: /etc/mysql/mariadb.conf.d/50-server.cnf | ||||
|     regex: "^bind-address" | ||||
|     line: "bind-address            = {{ ansible_facts.docker0.ipv4.address }}" | ||||
|   notify: restart_mariadb | ||||
|  | ||||
| - name: Allow database connections from Docker | ||||
|   community.general.ufw: | ||||
|     rule: allow | ||||
|     port: "3306" | ||||
|     proto: tcp | ||||
|     src: "{{ item }}" | ||||
|   loop: "{{ mariadb_trust | default(['172.16.0.0/12']) }}" | ||||
| @@ -1,28 +1,28 @@ | ||||
| - name: Install GPG | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: gpg | ||||
|     state: present | ||||
|  | ||||
| - name: Add AdoptOpenJDK's signing key | ||||
|   apt_key: | ||||
|   ansible.builtin.apt_key: | ||||
|     id: 8ED17AF5D7E675EB3EE3BCE98AC3B29174885C03 | ||||
|     url: https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | ||||
|  | ||||
| - name: Install AdoptOpenJDK repository | ||||
|   apt_repository: | ||||
|   ansible.builtin.apt_repository: | ||||
|     repo: deb https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/ buster main | ||||
|     mode: 0644 | ||||
|     state: present | ||||
|  | ||||
| - name: Install Java | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: "adoptopenjdk-{{ item.java.version }}-hotspot" | ||||
|     state: present | ||||
|   when: item.java.version is defined | ||||
|   loop: "{{ minecraft }}" | ||||
|  | ||||
| - name: "Install default Java, version {{ minecraft_java }}" | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: "{{ minecraft_java_pkg }}" | ||||
|     state: present | ||||
|   when: item.java.version is not defined | ||||
| @@ -30,7 +30,7 @@ | ||||
|   register: minecraft_java_default | ||||
|  | ||||
| - name: "Activate default Java, version {{ minecraft_java }}" | ||||
|   alternatives: | ||||
|   community.general.alternatives: | ||||
|     name: java | ||||
|     path: "/usr/lib/jvm/{{ minecraft_java_pkg }}-amd64/bin/java" | ||||
|   when: minecraft_java_default.changed | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| - import_tasks: system.yml | ||||
| - ansible.builtin.import_tasks: system.yml | ||||
|   when: minecraft_eula | ||||
|  | ||||
| - import_tasks: java.yml | ||||
| - ansible.builtin.import_tasks: java.yml | ||||
|   when: minecraft_eula | ||||
|  | ||||
| - import_tasks: vanilla.yml | ||||
| - ansible.builtin.import_tasks: vanilla.yml | ||||
|   when: minecraft_eula | ||||
|  | ||||
| - import_tasks: modpacks.yml | ||||
| - ansible.builtin.import_tasks: modpacks.yml | ||||
|   when: minecraft_eula | ||||
|  | ||||
| - import_tasks: service.yml | ||||
| - ansible.builtin.import_tasks: service.yml | ||||
|   when: minecraft_eula | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| - name: Download Minecraft modpack installer | ||||
|   get_url: | ||||
|   ansible.builtin.get_url: | ||||
|     url: "{{ minecraft_modpack_url }}" | ||||
|     dest: "{{ minecraft_home }}/{{ item.name }}/serverinstall_{{ item.modpack | replace ('/', '_') }}" | ||||
|     owner: "{{ minecraft_user }}" | ||||
| @@ -9,7 +9,7 @@ | ||||
|   when: item.modpack is defined and item.sha1 is not defined | ||||
|  | ||||
| - name: Run Minecraft modpack installer | ||||
|   command: "sudo -u {{ minecraft_user }} ./serverinstall_{{ item.modpack | replace ('/', '_') }} --auto" | ||||
|   ansible.builtin.command: "sudo -u {{ minecraft_user }} ./serverinstall_{{ item.modpack | replace ('/', '_') }} --auto" | ||||
|   args: | ||||
|     creates: "{{ minecraft_home }}/{{ item.name }}/mods" | ||||
|     chdir: "{{ minecraft_home }}/{{ item.name }}" | ||||
| @@ -17,7 +17,7 @@ | ||||
|   when: item.modpack is defined and item.sha1 is not defined | ||||
|  | ||||
| - name: Find Minecraft Forge | ||||
|   find: | ||||
|   ansible.builtin.find: | ||||
|     paths: "{{ minecraft_home }}/{{ item.name }}" | ||||
|     patterns: "forge*.jar" | ||||
|   register: minecraft_forge | ||||
| @@ -25,7 +25,7 @@ | ||||
|   when: item.modpack is defined and item.sha1 is not defined | ||||
|  | ||||
| - name: Link to Minecraft Forge | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     src: "{{ item.files[0].path }}" | ||||
|     dest: "{{ minecraft_home }}/{{ item.item.name }}/minecraft_server.jar" | ||||
|     owner: "{{ minecraft_user }}" | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| - name: Deploy Minecraft systemd service | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: minecraft.service.j2 | ||||
|     dest: "/etc/systemd/system/minecraft@.service" | ||||
|   register: minecraft_systemd | ||||
|  | ||||
| - name: Deploy service environmental variables | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: environment.conf.j2 | ||||
|     dest: "{{ minecraft_home }}/{{ item.name }}/environment.conf" | ||||
|     owner: "{{ minecraft_user }}" | ||||
| @@ -13,25 +13,25 @@ | ||||
|   loop: "{{ minecraft }}" | ||||
|  | ||||
| - name: Reload systemd manager configuration | ||||
|   systemd: | ||||
|   ansible.builtin.systemd: | ||||
|     daemon_reload: true | ||||
|   when: minecraft_systemd.changed | ||||
|  | ||||
| - name: Disable non-default service instances | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: "minecraft@{{ item.name }}" | ||||
|     enabled: false | ||||
|   loop: "{{ minecraft }}" | ||||
|   when: item.name != minecraft_onboot | ||||
|  | ||||
| - name: Enable default service instance | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: "minecraft@{{ minecraft_onboot }}" | ||||
|     enabled: true | ||||
|   when: minecraft_eula and minecraft_onboot is defined | ||||
|  | ||||
| - name: Run default service instance | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: "minecraft@{{ minecraft_onboot }}" | ||||
|     state: started | ||||
|   when: minecraft_eula and minecraft_onboot is defined and minecraft_onboot_run | ||||
|   | ||||
| @@ -1,16 +1,16 @@ | ||||
| - name: Install Screen | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: screen | ||||
|     state: present | ||||
|  | ||||
| - name: Create Minecraft user | ||||
|   user: | ||||
|   ansible.builtin.user: | ||||
|     name: "{{ minecraft_user }}" | ||||
|     state: present | ||||
|     shell: /bin/bash | ||||
|     ansible.builtin.shell: /bin/bash | ||||
|  | ||||
| - name: Create Minecraft directory | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ minecraft_home }}/{{ item.name }}" | ||||
|     state: directory | ||||
|     owner: "{{ minecraft_user }}" | ||||
| @@ -18,7 +18,7 @@ | ||||
|   loop: "{{ minecraft }}" | ||||
|  | ||||
| - name: Answer to Mojang's EULA | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: eula.txt.j2 | ||||
|     dest: "{{ minecraft_home }}/{{ item.name }}/eula.txt" | ||||
|     owner: "{{ minecraft_user }}" | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| - name: Download Minecraft | ||||
|   get_url: | ||||
|   ansible.builtin.get_url: | ||||
|     url: "{{ minecraft_url }}" | ||||
|     dest: "{{ minecraft_home }}/{{ item.name }}/minecraft_server.jar" | ||||
|     checksum: "sha1:{{ item.sha1 }}" | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| - name: Create Nextcloud network | ||||
|   docker_network: | ||||
|   community.general.docker_network: | ||||
|     name: "{{ nextcloud_container }}" | ||||
|  | ||||
| - name: Start Nextcloud's database container | ||||
|   docker_container: | ||||
|   community.general.docker_container: | ||||
|     name: "{{ nextcloud_dbcontainer }}" | ||||
|     image: mariadb:{{ nextcloud_dbversion }} | ||||
|     state: started | ||||
| @@ -19,7 +19,7 @@ | ||||
|       MYSQL_PASSWORD: "{{ nextcloud_dbpass }}" | ||||
|  | ||||
| - name: Start Nextcloud container | ||||
|   docker_container: | ||||
|   community.general.docker_container: | ||||
|     name: "{{ nextcloud_container }}" | ||||
|     image: nextcloud:{{ nextcloud_version }} | ||||
|     state: started | ||||
| @@ -29,9 +29,12 @@ | ||||
|     networks: | ||||
|       - name: "{{ nextcloud_container }}" | ||||
|       - name: traefik | ||||
|     env: | ||||
|       PHP_MEMORY_LIMIT: 1024M | ||||
|     labels: | ||||
|       traefik.http.routers.nextcloud.rule: "Host(`{{ nextcloud_domain }}`)" | ||||
|       traefik.http.routers.nextcloud.entrypoints: websecure | ||||
|       traefik.http.routers.nextcloud.tls.certresolver: letsencrypt | ||||
|       traefik.http.routers.nextcloud.middlewares: "securehttps@file,nextcloud-webdav" | ||||
|       traefik.http.middlewares.nextcloud-webdav.redirectregex.regex: "https://(.*)/.well-known/(card|cal)dav" | ||||
|       traefik.http.middlewares.nextcloud-webdav.redirectregex.replacement: "https://${1}/remote.php/dav/" | ||||
| @@ -40,34 +43,34 @@ | ||||
|       traefik.enable: "true" | ||||
|  | ||||
| - name: Grab Nextcloud database container information | ||||
|   docker_container_info: | ||||
|   community.general.docker_container_info: | ||||
|     name: "{{ nextcloud_dbcontainer }}" | ||||
|   register: nextcloud_dbinfo | ||||
|  | ||||
| - name: Grab Nextcloud container information | ||||
|   docker_container_info: | ||||
|   community.general.docker_container_info: | ||||
|     name: "{{ nextcloud_container }}" | ||||
|   register: nextcloud_info | ||||
|  | ||||
| - name: Wait for Nextcloud to become available | ||||
|   wait_for: | ||||
|   ansible.builtin.wait_for: | ||||
|     host: "{{ nextcloud_info.container.NetworkSettings.Networks.traefik.IPAddress }}" | ||||
|     port: 80 | ||||
|  | ||||
| - name: Check Nextcloud status | ||||
|   command: "docker exec --user www-data {{ nextcloud_container }} | ||||
|   ansible.builtin.command: "docker exec --user www-data {{ nextcloud_container }} | ||||
|             php occ status" | ||||
|   register: nextcloud_status | ||||
|   args: | ||||
|     removes: "{{ nextcloud_root }}/config/CAN_INSTALL" | ||||
|  | ||||
| - name: Wait for Nextcloud database to become available | ||||
|   wait_for: | ||||
|   ansible.builtin.wait_for: | ||||
|     host: "{{ nextcloud_dbinfo.container.NetworkSettings.Networks.nextcloud.IPAddress }}" | ||||
|     port: 3306 | ||||
|  | ||||
| - name: Install Nextcloud | ||||
|   command: 'docker exec --user www-data {{ nextcloud_container }} | ||||
|   ansible.builtin.command: 'docker exec --user www-data {{ nextcloud_container }} | ||||
|             php occ maintenance:install | ||||
|               --database "mysql" | ||||
|               --database-host "{{ nextcloud_dbcontainer }}" | ||||
| @@ -82,19 +85,19 @@ | ||||
|     - nextcloud_domain is defined | ||||
|  | ||||
| - name: Set Nextcloud's Trusted Proxy | ||||
|   command: 'docker exec --user www-data {{ nextcloud_container }} | ||||
|   ansible.builtin.command: 'docker exec --user www-data {{ nextcloud_container }} | ||||
|             php occ config:system:set trusted_proxies 0 | ||||
|               --value="{{ traefik_name }}"' | ||||
|   when: nextcloud_install.changed | ||||
|  | ||||
| - name: Set Nextcloud's Trusted Domain | ||||
|   command: 'docker exec --user www-data {{ nextcloud_container }} | ||||
|   ansible.builtin.command: 'docker exec --user www-data {{ nextcloud_container }} | ||||
|             php occ config:system:set trusted_domains 0 | ||||
|               --value="{{ nextcloud_domain }}"' | ||||
|   when: nextcloud_install.changed | ||||
|  | ||||
| - name: Preform Nextcloud database maintenance | ||||
|   command: "docker exec --user www-data {{ nextcloud_container }} {{ item }}" | ||||
|   ansible.builtin.command: "docker exec --user www-data {{ nextcloud_container }} {{ item }}" | ||||
|   loop: | ||||
|     - "php occ maintenance:mode --on" | ||||
|     - "php occ db:add-missing-indices" | ||||
| @@ -102,7 +105,14 @@ | ||||
|     - "php occ maintenance:mode --off" | ||||
|   when: nextcloud_install.changed | ||||
|  | ||||
| - name: Install Nextcloud background jobs cron | ||||
|   ansible.builtin.cron: | ||||
|     name: Nextcloud background job | ||||
|     minute: "*/5" | ||||
|     job: "/usr/bin/docker exec -u www-data nextcloud /usr/local/bin/php -f /var/www/html/cron.php" | ||||
|     user: root | ||||
|  | ||||
| - name: Remove Nextcloud's CAN_INSTALL file | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ nextcloud_root }}/config/CAN_INSTALL" | ||||
|     state: absent | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| - name: Create nginx root | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ nginx_root }}" | ||||
|     state: directory | ||||
|  | ||||
| - name: Generate deploy keys | ||||
|   openssh_keypair: | ||||
|   community.crypto.openssh_keypair: | ||||
|     path: "{{ nginx_repo_key }}" | ||||
|     state: present | ||||
|  | ||||
| - name: Clone static website files | ||||
|   git: | ||||
|   ansible.builtin.git: | ||||
|     repo: "{{ nginx_repo_url }}" | ||||
|     dest: "{{ nginx_html }}" | ||||
|     version: "{{ nginx_repo_branch }}" | ||||
| @@ -17,7 +17,7 @@ | ||||
|     separate_git_dir: "{{ nginx_repo_dest }}" | ||||
|  | ||||
| - name: Start nginx container | ||||
|   docker_container: | ||||
|   community.general.docker_container: | ||||
|     name: "{{ nginx_name }}" | ||||
|     image: nginx:{{ nginx_version }} | ||||
|     state: started | ||||
| @@ -31,6 +31,7 @@ | ||||
|       traefik.http.routers.nginx.rule: "Host(`{{ nginx_domain }}`)" | ||||
|       #traefik.http.middlewares.nginxauth.basicauth.users: "{{ nginx_auth }}" | ||||
|       traefik.http.routers.nginx.entrypoints: websecure | ||||
|       traefik.http.routers.nginx.middlewares: "securehttps@file" | ||||
|       #traefik.http.routers.nginx.tls.certresolver: letsencrypt | ||||
|       #traefik.http.routers.nginx.middlewares: "securehttps@file,nginxauth" | ||||
|       traefik.docker.network: traefik | ||||
|       traefik.enable: "true" | ||||
|   | ||||
							
								
								
									
										5
									
								
								roles/postgresql/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								roles/postgresql/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| postgresql_config: /etc/postgresql/13/main/pg_hba.conf | ||||
| postgresql_listen: "*" | ||||
| postgresql_trust: | ||||
|   - "172.16.0.0/12" | ||||
|   - "192.168.0.0/16" | ||||
							
								
								
									
										43
									
								
								roles/postgresql/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								roles/postgresql/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| - name: Install PostgreSQL | ||||
|   ansible.builtin.apt: | ||||
|     name: postgresql | ||||
|     state: present | ||||
|  | ||||
| - name: Trust connections to PostgreSQL | ||||
|   community.general.postgresql_pg_hba: | ||||
|     dest: "{{ postgresql_config }}" | ||||
|     contype: host | ||||
|     databases: all | ||||
|     users: all | ||||
|     address: "{{ item }}" | ||||
|     method: trust | ||||
|   register: postgresql_hba | ||||
|   loop: "{{ postgresql_trust }}" | ||||
|  | ||||
| - name: Change PostgreSQL listen addresses | ||||
|   community.general.postgresql_set: | ||||
|     name: listen_addresses | ||||
|     value: "{{ postgresql_listen }}" | ||||
|   become: true | ||||
|   become_user: postgres | ||||
|   register: postgresql_config | ||||
|  | ||||
| - name: Reload PostgreSQL | ||||
|   ansible.builtin.service: | ||||
|     name: postgresql | ||||
|     state: reloaded | ||||
|   when: postgresql_hba.changed and not postgresql_config.changed | ||||
|  | ||||
| - name: Restart PostgreSQL | ||||
|   ansible.builtin.service: | ||||
|     name: postgresql | ||||
|     state: restarted | ||||
|   when: postgresql_config.changed | ||||
|  | ||||
| - name: Allow database connections | ||||
|   community.general.ufw: | ||||
|     rule: allow | ||||
|     port: "5432" | ||||
|     proto: tcp | ||||
|     src: "{{ item }}" | ||||
|   loop: "{{ postgresql_trust }}" | ||||
| @@ -1,35 +1,35 @@ | ||||
| - name: Install Prometheus node exporter | ||||
|   apt: | ||||
|   ansible.builtin.apt: | ||||
|     name: prometheus-node-exporter | ||||
|     state: present | ||||
|  | ||||
| - name: Run Prometheus node exporter | ||||
|   service: | ||||
|   ansible.builtin.service: | ||||
|     name: prometheus-node-exporter | ||||
|     state: started | ||||
|  | ||||
| - name: Create Prometheus data directory | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ prom_root }}/prometheus" | ||||
|     state: directory | ||||
|     owner: nobody | ||||
|  | ||||
| - name: Create Prometheus config directory | ||||
|   file: | ||||
|   ansible.builtin.file: | ||||
|     path: "{{ prom_root }}/config" | ||||
|     state: directory | ||||
|  | ||||
| - name: Install Prometheus configuration | ||||
|   template: | ||||
|   ansible.builtin.template: | ||||
|     src: prometheus.yml.j2 | ||||
|     dest: "{{ prom_root }}/config/prometheus.yml" | ||||
|  | ||||
| - name: Create Prometheus network | ||||
|   docker_network: | ||||
|   community.general.docker_network: | ||||
|     name: "{{ prom_name }}" | ||||
|  | ||||
| - name: Start Prometheus container | ||||
|   docker_container: | ||||
|   community.general.docker_container: | ||||
|     name: "{{ prom_name }}" | ||||
|     image: prom/prometheus:{{ prom_version }} | ||||
|     state: started | ||||
| @@ -45,12 +45,13 @@ | ||||
|       traefik.http.routers.prometheus.rule: "Host(`{{ prom_domain }}`)" | ||||
|       traefik.http.routers.prometheus.entrypoints: websecure | ||||
|       traefik.http.routers.prometheus.middlewares: "securehttps@file,localonly" | ||||
|       traefik.http.routers.prometheus.tls.certresolver: letsencrypt | ||||
|       traefik.http.middlewares.localonly.ipwhitelist.sourcerange: "{{ traefik_localonly }}" | ||||
|       traefik.docker.network: traefik | ||||
|       traefik.enable: "true" | ||||
|  | ||||
| - name: Start Grafana container | ||||
|   docker_container: | ||||
|   community.general.docker_container: | ||||
|     name: "{{ grafana_name }}" | ||||
|     image: grafana/grafana:{{ grafana_version }} | ||||
|     state: started | ||||
| @@ -64,6 +65,7 @@ | ||||
|     labels: | ||||
|       traefik.http.routers.grafana.rule: "Host(`{{ grafana_domain }}`)" | ||||
|       traefik.http.routers.grafana.entrypoints: websecure | ||||
|       traefik.http.routers.grafana.tls.certresolver: letsencrypt | ||||
|       traefik.http.routers.grafana.middlewares: "securehttps@file" | ||||
|       traefik.docker.network: traefik | ||||
|       traefik.enable: "true" | ||||
|   | ||||
							
								
								
									
										2
									
								
								roles/proxy/files/reload-nginx.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								roles/proxy/files/reload-nginx.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #!/bin/bash | ||||
| systemctl reload nginx | ||||
							
								
								
									
										15
									
								
								roles/proxy/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								roles/proxy/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| - name: Enable nginx sites configuration | ||||
|   ansible.builtin.file: | ||||
|     src: "/etc/nginx/sites-available/{{ item.item.domain }}.conf" | ||||
|     dest: "/etc/nginx/sites-enabled/{{ item.item.domain }}.conf" | ||||
|     state: link | ||||
|     mode: "400" | ||||
|   loop: "{{ nginx_sites.results }}" | ||||
|   when: item.changed | ||||
|   listen: reload_nginx | ||||
|  | ||||
| - name: Reload nginx | ||||
|   ansible.builtin.service: | ||||
|     name: nginx | ||||
|     state: reloaded | ||||
|   listen: reload_nginx | ||||
							
								
								
									
										94
									
								
								roles/proxy/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								roles/proxy/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| - name: Install nginx | ||||
|   ansible.builtin.apt: | ||||
|     name: nginx | ||||
|     state: present | ||||
|     update_cache: true | ||||
|  | ||||
| - name: Start nginx and enable on boot | ||||
|   ansible.builtin.service: | ||||
|     name: nginx | ||||
|     state: started | ||||
|     enabled: true | ||||
|  | ||||
| - name: Generate DH Parameters | ||||
|   community.crypto.openssl_dhparam: | ||||
|     path: /etc/ssl/dhparams.pem | ||||
|     size: 4096 | ||||
|  | ||||
| - name: Install nginx base configuration | ||||
|   ansible.builtin.template: | ||||
|     src: nginx.conf.j2 | ||||
|     dest: /etc/nginx/nginx.conf | ||||
|     mode: "644" | ||||
|   notify: reload_nginx | ||||
|  | ||||
| - name: Install nginx sites configuration | ||||
|   ansible.builtin.template: | ||||
|     src: server-nginx.conf.j2 | ||||
|     dest: "/etc/nginx/sites-available/{{ item.domain }}.conf" | ||||
|     mode: "400" | ||||
|   loop: "{{ proxy.servers }}" | ||||
|   notify: reload_nginx | ||||
|   register: nginx_sites | ||||
|  | ||||
| - name: Generate self-signed certificate | ||||
|   ansible.builtin.command: 'openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes \ | ||||
|           -subj   "/C=US/ST=Local/L=Local/O=Org/OU=IT/CN=example.com" \ | ||||
|           -keyout /etc/ssl/private/nginx-selfsigned.key \ | ||||
|           -out    /etc/ssl/certs/nginx-selfsigned.crt' | ||||
|   args: | ||||
|     creates: /etc/ssl/certs/nginx-selfsigned.crt | ||||
|   when: proxy.production is not defined or not proxy.production | ||||
|   notify: reload_nginx | ||||
|  | ||||
| - name: Install LE's certbot | ||||
|   ansible.builtin.apt: | ||||
|     name: ['certbot', 'python3-certbot-dns-cloudflare'] | ||||
|     state: present | ||||
|   when: proxy.production is defined and proxy.production | ||||
|  | ||||
| - name: Install Cloudflare API token | ||||
|   ansible.builtin.template: | ||||
|     src: cloudflare.ini.j2 | ||||
|     dest: /root/.cloudflare.ini | ||||
|     mode: "400" | ||||
|   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined | ||||
|  | ||||
| - name: Create nginx post renewal hook directory | ||||
|   ansible.builtin.file: | ||||
|     path: /etc/letsencrypt/renewal-hooks/post | ||||
|     state: directory | ||||
|     mode: "500" | ||||
|   when: proxy.production is defined and proxy.production | ||||
|  | ||||
| - name: Install nginx post renewal hook | ||||
|   ansible.builtin.copy: | ||||
|     src: reload-nginx.sh | ||||
|     dest: /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh | ||||
|     mode: '0755' | ||||
|   when: proxy.production is defined and proxy.production | ||||
|  | ||||
| - name: Run Cloudflare DNS-01 challenges on wildcard domains | ||||
|   ansible.builtin.shell: '/usr/bin/certbot certonly \ | ||||
|             --non-interactive \ | ||||
|             --agree-tos \ | ||||
|             --email "{{ proxy.dns_cloudflare.email }}" \ | ||||
|             --dns-cloudflare \ | ||||
|             --dns-cloudflare-credentials /root/.cloudflare.ini \ | ||||
|             -d "*.{{ item }}" \ | ||||
|             -d "{{ item }}" \ | ||||
|             {{ proxy.dns_cloudflare.opts | default("") }}' | ||||
|   args: | ||||
|     creates: "/etc/letsencrypt/live/{{ item }}/fullchain.pem" | ||||
|   loop: "{{ proxy.dns_cloudflare.wildcard_domains }}" | ||||
|   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined | ||||
|   notify: reload_nginx | ||||
|  | ||||
| - name: Add HTTP and HTTPS firewall rule | ||||
|   community.general.ufw: | ||||
|     rule: allow | ||||
|     port: "{{ item }}" | ||||
|     proto: tcp | ||||
|   loop: | ||||
|     - "80" | ||||
|     - "443" | ||||
							
								
								
									
										2
									
								
								roles/proxy/templates/cloudflare.ini.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								roles/proxy/templates/cloudflare.ini.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # Cloudflare API token used by Certbot | ||||
| dns_cloudflare_api_token = {{ proxy.dns_cloudflare.api_token }} | ||||
							
								
								
									
										34
									
								
								roles/proxy/templates/nginx.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								roles/proxy/templates/nginx.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| user www-data; | ||||
| worker_processes auto; | ||||
| error_log /var/log/nginx/error.log; | ||||
| pid /run/nginx.pid; | ||||
| include /etc/nginx/modules-enabled/*.conf; | ||||
|  | ||||
| events { | ||||
|   worker_connections 1024; | ||||
| } | ||||
|  | ||||
| http { | ||||
|   include           /etc/nginx/mime.types; | ||||
|   default_type      application/octet-stream; | ||||
|   log_format        main '$remote_addr - $remote_user [$time_local]  $status ' | ||||
|                          '"$request" $body_bytes_sent "$http_referer" ' | ||||
|                          '"$http_user_agent" "$http_x_forwarded_for"'; | ||||
|   access_log        /var/log/nginx/access.log  main; | ||||
|   server_tokens     off; | ||||
|   sendfile          on; | ||||
|   tcp_nopush        on; | ||||
|   keepalive_timeout 65; | ||||
|   server_names_hash_bucket_size 128; | ||||
|  | ||||
|   ssl_protocols TLSv1.2 TLSv1.3; | ||||
|   ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; | ||||
|   ssl_prefer_server_ciphers off; | ||||
|   ssl_dhparam /etc/ssl/dhparams.pem; | ||||
|   ssl_session_cache shared:SSL:10m; | ||||
|   ssl_session_timeout 1d; | ||||
|   ssl_session_tickets off; | ||||
|  | ||||
|   include           /etc/nginx/conf.d/*.conf; | ||||
|   include           /etc/nginx/sites-enabled/*; | ||||
| } | ||||
							
								
								
									
										57
									
								
								roles/proxy/templates/server-nginx.conf.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								roles/proxy/templates/server-nginx.conf.j2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| server { | ||||
|   listen 80; | ||||
|   listen [::]:80; | ||||
|   server_name {{ item.domain }}; | ||||
|   return 301 https://{{ item.domain }}$request_uri; | ||||
| } | ||||
|  | ||||
| server { | ||||
|   listen              443      ssl http2; | ||||
|   listen              [::]:443 ssl http2; | ||||
|   server_name         {{ item.domain }}; | ||||
|   access_log          /var/log/nginx/{{ item.domain }}.log main; | ||||
| {% if proxy.production is defined and proxy.production and proxy.dns_cloudflare.wildcard_domains is defined and item.tls.cert is not defined %} | ||||
| {% for wildcard in proxy.dns_cloudflare.wildcard_domains %} | ||||
| {% set domain_regex = '^\*\.' + wildcard + '$' %} | ||||
| {% if item.domain | regex_search(wildcard) %} | ||||
|   ssl_certificate     /etc/letsencrypt/live/{{ wildcard }}/fullchain.pem; | ||||
|   ssl_certificate_key /etc/letsencrypt/live/{{ wildcard }}/privkey.pem; | ||||
| {% endif %} | ||||
| {% endfor %} | ||||
| {% elif proxy.production is defined and proxy.production and item.tls.cert is not defined %} | ||||
|   ssl_certificate     /etc/letsencrypt/live/{{ item.domain }}/fullchain.pem; | ||||
|   ssl_certificate_key /etc/letsencrypt/live/{{ item.domain }}/privkey.pem; | ||||
| {% elif proxy.production is defined and proxy.production and item.tls.cert is defined %} | ||||
|   ssl_certificate     {{ item.tls.cert }}; | ||||
|   ssl_certificate_key {{ item.tls.key }}; | ||||
| {% else %} | ||||
|   ssl_certificate     /etc/ssl/certs/nginx-selfsigned.crt; | ||||
|   ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; | ||||
| {% endif %} | ||||
| {% if item.hsts is defined %} | ||||
|   add_header Strict-Transport-Security "max-age={{ item.hsts }}" always; | ||||
| {% endif %} | ||||
| {% if item.client_max_body_size is defined %} | ||||
|   client_max_body_size {{ item.client_max_body_size }}; | ||||
| {% endif %} | ||||
|   location / { | ||||
| {% if item.restrict is defined and item.restrict  %} | ||||
|     auth_basic "{{ item.restrict_name | default('Restricted Access') }}"; | ||||
|     auth_basic_user_file {{ item.restrict_file | default('/etc/nginx/.htpasswd') }}; | ||||
|     proxy_set_header Authorization ""; | ||||
| {% endif %} | ||||
|     proxy_set_header Host $host; | ||||
|     proxy_set_header X-Real-IP $remote_addr; | ||||
|     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||
|     proxy_pass {{ item.proxy_pass }}; | ||||
| {% if item.proxy_ssl_verify is defined and item.proxy_ssl_verify is false %} | ||||
|     proxy_ssl_verify off; | ||||
| {% endif %} | ||||
| {% if item.websockets is defined and item.websockets %} | ||||
|     proxy_http_version 1.1; | ||||
|     proxy_set_header Connection $http_connection; | ||||
|     proxy_set_header Origin http://$host; | ||||
|     proxy_set_header Upgrade $http_upgrade; | ||||
| {% endif %} | ||||
|   } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user