Compare commits
	
		
			25 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ea9603a2db | |||
| d954c64e23 | |||
| ccf6b10a0e | |||
| bd8eca0466 | |||
| 56c3721a5e | |||
| 77c9b12186 | |||
| 3102c621f0 | |||
| e3f03edf3f | |||
| f481a965dd | |||
| a0aa289c05 | |||
| 324fe0b191 | |||
| 6fbd3c53bb | |||
| 01e8e22c01 | |||
| a31bf233dc | |||
| 60fafed9cd | |||
| 2c00858590 | |||
| be80681485 | |||
| a2e60972c7 | |||
| 598359854f | |||
| ef812c1877 | |||
| 385e60aee5 | |||
| 5633468f41 | |||
| 7f91b24adb | |||
| 5b09029239 | |||
| 7adb5f10e9 | 
							
								
								
									
										5
									
								
								.github/workflows/vagrant.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/vagrant.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,8 +3,9 @@ name: homelab-ci | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     branches: |     branches: | ||||||
|       - main |       - github_actions | ||||||
|       - testing |       # - main | ||||||
|  |       # - testing | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   homelab-ci: |   homelab-ci: | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,5 @@ | |||||||
|  | .ansible* | ||||||
|  | /environments/ | ||||||
| .playbook | .playbook | ||||||
| .vagrant* | .vagrant* | ||||||
| .vscode | .vscode | ||||||
| /environments/ |  | ||||||
							
								
								
									
										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 | ## Quick Start | ||||||
|  |  | ||||||
| To configure a local virtual machine for testing, follow these simple steps. | 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 | ### Installation | ||||||
|  |  | ||||||
| 1. Clone this repository | 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 | 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 |    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 | ## Vagrant Settings | ||||||
| Copyright (C) 2020-2021  Kris Lamoureux | 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) | [](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/>. |  | ||||||
|   | |||||||
| @@ -6,8 +6,7 @@ | |||||||
|   roles: |   roles: | ||||||
|     - base |     - base | ||||||
|     - docker |     - docker | ||||||
|  |     - mariadb | ||||||
|     - traefik |     - traefik | ||||||
|     - nextcloud |     - nextcloud | ||||||
|     - jenkins |     - proxy | ||||||
|     - prometheus |  | ||||||
|     - nginx |  | ||||||
|   | |||||||
| @@ -2,44 +2,51 @@ | |||||||
| allow_reboot: false | allow_reboot: false | ||||||
| manage_network: false | manage_network: false | ||||||
|  |  | ||||||
|  | # Import my GPG key for git signature verification | ||||||
|  | root_gpgkeys: | ||||||
|  |   - name: kris@lamoureux.io | ||||||
|  |     id: 42A3A92C5DA0F3E5F71A3710105B748C1362EB96 | ||||||
|  |   # Older key, but still in use | ||||||
|  |   - name: kris@lamoureux.io | ||||||
|  |     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||||
|  |     server: keyserver.ubuntu.com | ||||||
|  |  | ||||||
|  | # proxy | ||||||
|  | proxy: | ||||||
|  |   servers: | ||||||
|  |     - domain: cloud.local.krislamo.org | ||||||
|  |       proxy_pass: http://127.0.0.1:8000 | ||||||
|  |  | ||||||
| # docker | # docker | ||||||
|  | docker_official: true # docker's apt repos | ||||||
| docker_users: | docker_users: | ||||||
|   - vagrant |   - vagrant | ||||||
|  |  | ||||||
|  | docker_compose_env_nolog: false # dev only setting | ||||||
|  | docker_compose_deploy: | ||||||
|  |   # Traefik | ||||||
|  |   - name: traefik | ||||||
|  |     url: https://github.com/krislamo/traefik | ||||||
|  |     version: d62bd06b37ecf0993962b0449a9d708373f9e381 | ||||||
|  |     enabled: true | ||||||
|  |     accept_newhostkey: true # Consider verifying manually instead | ||||||
|  |     trusted_keys: | ||||||
|  |       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||||
|  |     env: | ||||||
|  |       DASHBOARD: true | ||||||
|  |   # Nextcloud | ||||||
|  |   - name: nextcloud | ||||||
|  |     url: https://github.com/krislamo/nextcloud | ||||||
|  |     version: fe6d349749f178e91ae7ff726d557f48ebf84356 | ||||||
|  |     env: | ||||||
|  |       DATA: ./data | ||||||
|  |  | ||||||
| # traefik | # traefik | ||||||
| traefik_version: latest | traefik: | ||||||
| traefik_dashboard: true |   ENABLE: true | ||||||
| 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 | ||||||
| nextcloud_version: stable | nextcloud: | ||||||
| nextcloud_admin: admin |   DOMAIN: cloud.local.krislamo.org | ||||||
| nextcloud_pass: password |   DB_PASSWD: password | ||||||
| nextcloud_domain: cloud.local.krislamo.org |   ADMIN_PASSWD: password | ||||||
|  |  | ||||||
| nextcloud_dbversion: latest |  | ||||||
| nextcloud_dbpass: password |  | ||||||
|  |  | ||||||
| # jenkins |  | ||||||
| jenkins_version: lts |  | ||||||
| jenkins_domain: jenkins.local.krislamo.org |  | ||||||
|  |  | ||||||
| # prometheus (includes grafana) |  | ||||||
| prom_version: latest |  | ||||||
| prom_domain: prom.local.krislamo.org |  | ||||||
| grafana_version: latest |  | ||||||
| grafana_domain: grafana.local.krislamo.org |  | ||||||
| prom_targets: "['10.0.2.15:9100']" |  | ||||||
|  |  | ||||||
| # nginx |  | ||||||
| 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 |  | ||||||
| nginx_version: latest |  | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ users: | |||||||
|     uid: 1001 |     uid: 1001 | ||||||
|     gid: 1001 |     gid: 1001 | ||||||
|     home: true |     home: true | ||||||
|  |     system: true | ||||||
|  |  | ||||||
| # Import my GPG key for git signature verification | # Import my GPG key for git signature verification | ||||||
| root_gpgkeys: | root_gpgkeys: | ||||||
| @@ -14,6 +15,7 @@ root_gpgkeys: | |||||||
|     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 |     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||||
|  |  | ||||||
| # docker | # docker | ||||||
|  | docker_official: true # docker's apt repos | ||||||
| docker_users: | docker_users: | ||||||
|   - vagrant |   - vagrant | ||||||
|  |  | ||||||
| @@ -33,6 +35,9 @@ docker_compose_deploy: | |||||||
|   - name: gitea |   - name: gitea | ||||||
|     url: https://github.com/krislamo/gitea |     url: https://github.com/krislamo/gitea | ||||||
|     version: b0ce66f6a1ab074172eed79eeeb36d7e9011ef8f |     version: b0ce66f6a1ab074172eed79eeeb36d7e9011ef8f | ||||||
|  |     enabled: true | ||||||
|  |     trusted_keys: | ||||||
|  |       - FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||||
|     env: |     env: | ||||||
|       USER_UID: "{{ users.git.uid }}" |       USER_UID: "{{ users.git.uid }}" | ||||||
|       USER_GID: "{{ users.git.gid }}" |       USER_GID: "{{ users.git.gid }}" | ||||||
|   | |||||||
| @@ -5,7 +5,12 @@ allow_reboot: false | |||||||
| manage_network: false | manage_network: false | ||||||
|  |  | ||||||
| users: | users: | ||||||
|   - name: jellyfin |   jellyfin: | ||||||
|  |     uid: 1001 | ||||||
|  |     gid: 1001 | ||||||
|  |     shell: /usr/sbin/nologin | ||||||
|  |     home: false | ||||||
|  |     system: true | ||||||
|  |  | ||||||
| samba: | samba: | ||||||
|   users: |   users: | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								dev/host_vars/podman.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dev/host_vars/podman.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | # base | ||||||
|  | allow_reboot: false | ||||||
|  | manage_network: false | ||||||
|  |  | ||||||
|  | users: | ||||||
|  |   kris: | ||||||
|  |     uid: 1001 | ||||||
|  |     gid: 1001 | ||||||
|  |     home: true | ||||||
|  |  | ||||||
|  | # podman | ||||||
|  | user_namespaces: | ||||||
|  |   - kris | ||||||
|  |  | ||||||
| @@ -4,6 +4,18 @@ base_domain: local.krislamo.org | |||||||
| allow_reboot: false | allow_reboot: false | ||||||
| manage_network: 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 | ||||||
| proxy: | proxy: | ||||||
|   #production: true |   #production: true | ||||||
| @@ -15,14 +27,49 @@ proxy: | |||||||
|       - "{{ base_domain }}" |       - "{{ base_domain }}" | ||||||
|   servers: |   servers: | ||||||
|     - domain: "{{ bitwarden_domain }}" |     - domain: "{{ bitwarden_domain }}" | ||||||
|       proxy_pass: "http://127.0.0.1:8080" |       proxy_pass: "http://127.0.0.1" | ||||||
|     - domain: "{{ gitea_domain }}" |     - domain: "{{ gitea_domain }}" | ||||||
|       proxy_pass: "http://127.0.0.1:3000" |       proxy_pass: "http://127.0.0.1" | ||||||
|  |  | ||||||
| # docker | # docker | ||||||
|  | docker_official: true # docker's apt repos | ||||||
| docker_users: | docker_users: | ||||||
|   - vagrant |   - 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 | # bitwarden | ||||||
| # Get Installation ID & Key at https://bitwarden.com/host/ | # Get Installation ID & Key at https://bitwarden.com/host/ | ||||||
| bitwarden_domain: "vault.{{ base_domain }}" | bitwarden_domain: "vault.{{ base_domain }}" | ||||||
| @@ -30,8 +77,3 @@ bitwarden_dbpass: password | |||||||
| bitwarden_install_id: 4ea840a3-532e-4cb6-a472-abd900728b23 | bitwarden_install_id: 4ea840a3-532e-4cb6-a472-abd900728b23 | ||||||
| bitwarden_install_key: 1yB3Z2gRI0KnnH90C6p | bitwarden_install_key: 1yB3Z2gRI0KnnH90C6p | ||||||
| #bitwarden_prodution: true | #bitwarden_prodution: true | ||||||
|  |  | ||||||
| # gitea |  | ||||||
| gitea_domain: "git.{{ base_domain }}" |  | ||||||
| gitea_version: 1 |  | ||||||
| gitea_dbpass: password |  | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								dev/podman.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								dev/podman.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | - name: Install Podman server | ||||||
|  |   hosts: all | ||||||
|  |   become: true | ||||||
|  |   vars_files: | ||||||
|  |     - host_vars/podman.yml | ||||||
|  |   roles: | ||||||
|  |     - base | ||||||
|  |     - podman | ||||||
| @@ -5,8 +5,8 @@ | |||||||
|     - host_vars/proxy.yml |     - host_vars/proxy.yml | ||||||
|   roles: |   roles: | ||||||
|     - base |     - base | ||||||
|     - mariadb |  | ||||||
|     - proxy |     - proxy | ||||||
|     - docker |     - docker | ||||||
|  |     - mariadb | ||||||
|     - gitea |     - gitea | ||||||
|     - bitwarden |     - bitwarden | ||||||
|   | |||||||
| @@ -1,11 +1,28 @@ | |||||||
| #!/bin/bash | #!/bin/bash | ||||||
|  |  | ||||||
| # Finds the SSH private key under ./.vagrant and connects to | # Finds the SSH private key under ./.vagrant and connects to | ||||||
| # the Vagrant box, port forwarding localhost ports: 8443, 80, 443 | # 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 | # Root check | ||||||
| if [ "$EUID" -ne 0 ]; then | if [ "$EUID" -ne 0 ]; then | ||||||
|   echo "[ERROR]: Please run script as root" |   echo "[ERROR]: Please run this script as root" | ||||||
|   exit 1 |   exit 1 | ||||||
| fi | fi | ||||||
|  |  | ||||||
| @@ -24,8 +41,8 @@ function ssh_connect { | |||||||
|       printf "[INFO]: Starting new vagrant SSH tunnel on PID " |       printf "[INFO]: Starting new vagrant SSH tunnel on PID " | ||||||
|       sudo -u "$USER" ssh -fNT -i "$PRIVATE_KEY" \ |       sudo -u "$USER" ssh -fNT -i "$PRIVATE_KEY" \ | ||||||
|         -L 22:localhost:22 \ |         -L 22:localhost:22 \ | ||||||
|         -L 80:localhost:80 \ |         -L 80:"$HOST_IP":80 \ | ||||||
|         -L 443:localhost:443 \ |         -L 443:"$HOST_IP":443 \ | ||||||
|         -L 8443:localhost:8443 \ |         -L 8443:localhost:8443 \ | ||||||
|         -o UserKnownHostsFile=/dev/null \ |         -o UserKnownHostsFile=/dev/null \ | ||||||
|         -o StrictHostKeyChecking=no \ |         -o StrictHostKeyChecking=no \ | ||||||
| @@ -34,28 +51,45 @@ function ssh_connect { | |||||||
|       pgrep -f "$MATCH_PATTERN" |       pgrep -f "$MATCH_PATTERN" | ||||||
|       ;; |       ;; | ||||||
|     *) |     *) | ||||||
|       echo "[INFO]: Delined to start a new vagrant SSH tunnel" |       echo "[INFO]: Declined to start a new vagrant SSH tunnel" | ||||||
|       exit 0 |       exit 0 | ||||||
|       ;; |       ;; | ||||||
|   esac |   esac | ||||||
| } | } | ||||||
|  |  | ||||||
| # Check for valid PRIVATE_KEY location | # Check for valid PRIVATE_KEY location | ||||||
| PRIVATE_KEY="$(find .vagrant -name "private_key" 2>/dev/null)" | PRIVATE_KEY="$(find .vagrant -name "private_key" 2>/dev/null | sort)" | ||||||
| if ! ssh-keygen -l -f "$PRIVATE_KEY" &>/dev/null; then |  | ||||||
|  | # 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?" |   echo "[ERROR]: The SSH key '$PRIVATE_KEY' is not valid. Is your virtual machine running?" | ||||||
|   exit 1 |   exit 1 | ||||||
|  | else | ||||||
|  |   echo "[CHECK]: Valid key at $PRIVATE_KEY" | ||||||
| fi | fi | ||||||
| echo "[CHECK]: Valid key at $PRIVATE_KEY" |  | ||||||
|  |  | ||||||
| # Grab first IP or use whatever HOST_IP_FIELD is set to and check that the guest is up | # Grab first IP or use whatever HOST_IP_FIELD is set to and check that the guest is up | ||||||
| HOST_IP="$(vagrant ssh -c "hostname -I | cut -d' ' -f${HOST_IP_FIELD:-1}" 2>/dev/null)" | 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 | HOST_IP="${HOST_IP::-1}" # trim | ||||||
|  |  | ||||||
| if ! ping -c 1 "$HOST_IP" &>/dev/null; then | if ! ping -c 1 "$HOST_IP" &>/dev/null; then | ||||||
|   echo "[ERROR]: Cannot ping the host IP '$HOST_IP'" |   echo "[ERROR]: Cannot ping the host IP '$HOST_IP'" | ||||||
|   exit 1 |   exit 1 | ||||||
| fi | fi | ||||||
| echo "[CHECK]: Host at $HOST_IP is up" | echo "[CHECK]: Host at $HOST_IP (${1:-default}) is up" | ||||||
|  |  | ||||||
| # Pattern for matching processes running | # Pattern for matching processes running | ||||||
| MATCH_PATTERN="ssh -fNT -i ${PRIVATE_KEY}.*vagrant@" | MATCH_PATTERN="ssh -fNT -i ${PRIVATE_KEY}.*vagrant@" | ||||||
|   | |||||||
| @@ -4,4 +4,5 @@ | |||||||
|   roles: |   roles: | ||||||
|     - base |     - base | ||||||
|     - jenkins |     - jenkins | ||||||
|  |     - proxy | ||||||
|     - docker |     - docker | ||||||
|   | |||||||
| @@ -3,9 +3,9 @@ | |||||||
|   become: true |   become: true | ||||||
|   roles: |   roles: | ||||||
|     - base |     - base | ||||||
|  |     - jenkins | ||||||
|     - docker |     - docker | ||||||
|  |     - mariadb | ||||||
|     - traefik |     - traefik | ||||||
|     - nextcloud |     - nextcloud | ||||||
|     - jenkins |     - proxy | ||||||
|     - prometheus |  | ||||||
|     - nginx |  | ||||||
|   | |||||||
| @@ -5,6 +5,10 @@ | |||||||
|   listen: reboot_host |   listen: reboot_host | ||||||
|   when: allow_reboot |   when: allow_reboot | ||||||
|  |  | ||||||
|  | - name: Reconfigure locales | ||||||
|  |   ansible.builtin.command: dpkg-reconfigure -f noninteractive locales | ||||||
|  |   listen: reconfigure_locales | ||||||
|  |  | ||||||
| - name: Restart WireGuard | - name: Restart WireGuard | ||||||
|   ansible.builtin.service: |   ansible.builtin.service: | ||||||
|     name: wg-quick@wg0 |     name: wg-quick@wg0 | ||||||
|   | |||||||
| @@ -2,4 +2,4 @@ | |||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: "~/.ansible/tmp" |     path: "~/.ansible/tmp" | ||||||
|     state: directory |     state: directory | ||||||
|     mode: 0700 |     mode: "700" | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: ddclient.conf.j2 |     src: ddclient.conf.j2 | ||||||
|     dest: /etc/ddclient.conf |     dest: /etc/ddclient.conf | ||||||
|     mode: 0600 |     mode: "600" | ||||||
|   register: ddclient_settings |   register: ddclient_settings | ||||||
|  |  | ||||||
| - name: Start ddclient and enable on boot | - name: Start ddclient and enable on boot | ||||||
|   | |||||||
| @@ -32,14 +32,14 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: fail2ban-ssh.conf.j2 |     src: fail2ban-ssh.conf.j2 | ||||||
|     dest: /etc/fail2ban/jail.d/sshd.conf |     dest: /etc/fail2ban/jail.d/sshd.conf | ||||||
|     mode: 0640 |     mode: "640" | ||||||
|   notify: restart_fail2ban |   notify: restart_fail2ban | ||||||
|  |  | ||||||
| - name: Install Fail2ban IP allow list | - name: Install Fail2ban IP allow list | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: fail2ban-allowlist.conf.j2 |     src: fail2ban-allowlist.conf.j2 | ||||||
|     dest: /etc/fail2ban/jail.d/allowlist.conf |     dest: /etc/fail2ban/jail.d/allowlist.conf | ||||||
|     mode: 0640 |     mode: "640" | ||||||
|   when: fail2ban_ignoreip is defined |   when: fail2ban_ignoreip is defined | ||||||
|   notify: restart_fail2ban |   notify: restart_fail2ban | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,10 +11,10 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: msmtprc.j2 |     src: msmtprc.j2 | ||||||
|     dest: /root/.msmtprc |     dest: /root/.msmtprc | ||||||
|     mode: 0600 |     mode: "600" | ||||||
|  |  | ||||||
| - name: Install /etc/aliases | - name: Install /etc/aliases | ||||||
|   ansible.builtin.copy: |   ansible.builtin.copy: | ||||||
|     dest: /etc/aliases |     dest: /etc/aliases | ||||||
|     content: "root: {{ mail.rootalias }}" |     content: "root: {{ mail.rootalias }}" | ||||||
|     mode: 0644 |     mode: "644" | ||||||
|   | |||||||
| @@ -10,6 +10,6 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: "interface.j2" |     src: "interface.j2" | ||||||
|     dest: "/etc/network/interfaces.d/{{ item.name }}" |     dest: "/etc/network/interfaces.d/{{ item.name }}" | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   loop: "{{ interfaces }}" |   loop: "{{ interfaces }}" | ||||||
|   notify: reboot_host |   notify: reboot_host | ||||||
|   | |||||||
| @@ -3,23 +3,15 @@ | |||||||
|     name: samba |     name: samba | ||||||
|     state: present |     state: present | ||||||
|  |  | ||||||
| - name: Create nologin shell accounts for Samba |  | ||||||
|   ansible.builtin.user: |  | ||||||
|     name: "{{ item.name }}" |  | ||||||
|     state: present |  | ||||||
|     shell: /usr/sbin/nologin |  | ||||||
|     createhome: false |  | ||||||
|     system: yes |  | ||||||
|   loop: "{{ samba.users }}" |  | ||||||
|   when: item.manage_user is defined and item.manage_user is true |  | ||||||
|  |  | ||||||
| - name: Create Samba users | - name: Create Samba users | ||||||
|   ansible.builtin.shell: "smbpasswd -a {{ item.name }}" |   ansible.builtin.command: "smbpasswd -a {{ item.name }}" | ||||||
|   args: |   args: | ||||||
|     stdin: "{{ item.password }}\n{{ item.password }}" |     stdin: "{{ item.password }}\n{{ item.password }}" | ||||||
|   loop: "{{ samba.users }}" |   loop: "{{ samba.users }}" | ||||||
|  |   loop_control: | ||||||
|  |     label: "{{ item.name }}" | ||||||
|   register: samba_users |   register: samba_users | ||||||
|   changed_when: "'User added' in samba_users.stdout" |   changed_when: "'Added user' in samba_users.stdout" | ||||||
|  |  | ||||||
| - name: Ensure share directories exist | - name: Ensure share directories exist | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
| @@ -27,13 +19,14 @@ | |||||||
|     owner: "{{ item.owner }}" |     owner: "{{ item.owner }}" | ||||||
|     group: "{{ item.group }}" |     group: "{{ item.group }}" | ||||||
|     state: directory |     state: directory | ||||||
|     mode: 0755 |     mode: "755" | ||||||
|   loop: "{{ samba.shares }}" |   loop: "{{ samba.shares }}" | ||||||
|  |  | ||||||
| - name: Configure Samba shares | - name: Configure Samba shares | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: smb.conf.j2 |     src: smb.conf.j2 | ||||||
|     dest: /etc/samba/smb.conf |     dest: /etc/samba/smb.conf | ||||||
|  |     mode: "644" | ||||||
|   notify: restart_samba |   notify: restart_samba | ||||||
|  |  | ||||||
| - name: Start smbd and enable on boot | - name: Start smbd and enable on boot | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
|     state: present |     state: present | ||||||
|  |  | ||||||
| - name: Check for existing GPG keys | - name: Check for existing GPG keys | ||||||
|   command: "gpg --list-keys {{ item.id }} 2>/dev/null" |   ansible.builtin.command: "gpg --list-keys {{ item.id }} 2>/dev/null" | ||||||
|   register: gpg_check |   register: gpg_check | ||||||
|   loop: "{{ root_gpgkeys }}" |   loop: "{{ root_gpgkeys }}" | ||||||
|   failed_when: false |   failed_when: false | ||||||
| @@ -18,20 +18,22 @@ | |||||||
|   when: root_gpgkeys is defined |   when: root_gpgkeys is defined | ||||||
|  |  | ||||||
| - name: Import GPG keys | - name: Import GPG keys | ||||||
|   command: "gpg --keyserver {{ item.item.server | default('keys.openpgp.org') }} --recv-key {{ item.item.id }}" |   ansible.builtin.command: | ||||||
|  |     "gpg --keyserver {{ item.item.server | default('keys.openpgp.org') }} --recv-key {{ item.item.id }}" | ||||||
|   register: gpg_check_import |   register: gpg_check_import | ||||||
|   loop: "{{ gpg_check.results }}" |   loop: "{{ gpg_check.results }}" | ||||||
|   loop_control: |   loop_control: | ||||||
|     label: "{{ item.item }}" |     label: "{{ item.item }}" | ||||||
|  |   changed_when: false | ||||||
|   when: root_gpgkeys is defined and item.rc != 0 |   when: root_gpgkeys is defined and item.rc != 0 | ||||||
|  |  | ||||||
| - name: Check GPG key imports | - name: Check GPG key imports | ||||||
|   fail: |   ansible.builtin.fail: | ||||||
|     msg: "{{ item.stderr }}" |     msg: "{{ item.stderr }}" | ||||||
|   loop: "{{ gpg_check_import.results }}" |   loop: "{{ gpg_check_import.results }}" | ||||||
|   loop_control: |   loop_control: | ||||||
|     label: "{{ item.item.item }}" |     label: "{{ item.item.item }}" | ||||||
|   when: (item.skipped | default(false) == false) and ('imported' not in item.stderr) |   when: root_gpgkeys is defined and (not item.skipped | default(false)) and ('imported' not in item.stderr) | ||||||
|  |  | ||||||
| - name: Install NTPsec | - name: Install NTPsec | ||||||
|   ansible.builtin.apt: |   ansible.builtin.apt: | ||||||
| @@ -47,7 +49,7 @@ | |||||||
|   community.general.locale_gen: |   community.general.locale_gen: | ||||||
|     name: "{{ locale_default }}" |     name: "{{ locale_default }}" | ||||||
|     state: present |     state: present | ||||||
|   register: locale_gen_output |   notify: reconfigure_locales | ||||||
|  |  | ||||||
| - name: Set the default locale | - name: Set the default locale | ||||||
|   ansible.builtin.lineinfile: |   ansible.builtin.lineinfile: | ||||||
| @@ -55,15 +57,11 @@ | |||||||
|     regexp: "^LANG=" |     regexp: "^LANG=" | ||||||
|     line: "LANG={{ locale_default }}" |     line: "LANG={{ locale_default }}" | ||||||
|  |  | ||||||
| - name: Reconfigure locales |  | ||||||
|   ansible.builtin.command: dpkg-reconfigure -f noninteractive locales |  | ||||||
|   when: locale_gen_output.changed |  | ||||||
|  |  | ||||||
| - name: Manage root authorized_keys | - name: Manage root authorized_keys | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: authorized_keys.j2 |     src: authorized_keys.j2 | ||||||
|     dest: /root/.ssh/authorized_keys |     dest: /root/.ssh/authorized_keys | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   when: authorized_keys is defined |   when: authorized_keys is defined | ||||||
|  |  | ||||||
| - name: Create system user groups | - name: Create system user groups | ||||||
| @@ -82,8 +80,11 @@ | |||||||
|     state: present |     state: present | ||||||
|     uid: "{{ item.value.uid }}" |     uid: "{{ item.value.uid }}" | ||||||
|     group: "{{ item.value.gid }}" |     group: "{{ item.value.gid }}" | ||||||
|  |     groups: "{{ item.value.groups | default([]) }}" | ||||||
|     shell: "{{ item.value.shell | default('/bin/bash') }}" |     shell: "{{ item.value.shell | default('/bin/bash') }}" | ||||||
|     create_home: "{{ item.value.home | default(false) }}" |     create_home: "{{ item.value.home | default(false) }}" | ||||||
|  |     home: "{{ item.value.homedir | default('/home/' + item.key) }}" | ||||||
|  |     system: "{{ item.value.system | default(false) }}" | ||||||
|   loop: "{{ users | dict2items }}" |   loop: "{{ users | dict2items }}" | ||||||
|   loop_control: |   loop_control: | ||||||
|     label: "{{ item.key }}" |     label: "{{ item.key }}" | ||||||
|   | |||||||
| @@ -18,11 +18,33 @@ | |||||||
|     src: /etc/wireguard/privatekey |     src: /etc/wireguard/privatekey | ||||||
|   register: wgkey |   register: wgkey | ||||||
|  |  | ||||||
|  | - name: Check if WireGuard preshared key file exists | ||||||
|  |   ansible.builtin.stat: | ||||||
|  |     path: /etc/wireguard/presharedkey-{{ item.name }} | ||||||
|  |   loop: "{{ wireguard.peers }}" | ||||||
|  |   loop_control: | ||||||
|  |     label: "{{ item.name }}" | ||||||
|  |   register: presharedkey_files | ||||||
|  |  | ||||||
|  | - name: Grab WireGuard preshared key for configuration | ||||||
|  |   ansible.builtin.slurp: | ||||||
|  |     src: /etc/wireguard/presharedkey-{{ item.item.name }} | ||||||
|  |   register: wgshared | ||||||
|  |   loop: "{{ presharedkey_files.results }}" | ||||||
|  |   loop_control: | ||||||
|  |     label: "{{ item.item.name }}" | ||||||
|  |   when: item.stat.exists | ||||||
|  |  | ||||||
|  | - name: Grab WireGuard private key for configuration | ||||||
|  |   ansible.builtin.slurp: | ||||||
|  |     src: /etc/wireguard/privatekey | ||||||
|  |   register: wgkey | ||||||
|  |  | ||||||
| - name: Install WireGuard configuration | - name: Install WireGuard configuration | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: wireguard.j2 |     src: wireguard.j2 | ||||||
|     dest: /etc/wireguard/wg0.conf |     dest: /etc/wireguard/wg0.conf | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   notify: restart_wireguard |   notify: restart_wireguard | ||||||
|  |  | ||||||
| - name: Start WireGuard interface | - name: Start WireGuard interface | ||||||
|   | |||||||
| @@ -1,4 +1,6 @@ | |||||||
| [Interface] | # {{ ansible_managed }} | ||||||
|  |  | ||||||
|  | [Interface] # {{ ansible_hostname }} | ||||||
| PrivateKey = {{ wgkey['content'] | b64decode | trim }} | PrivateKey = {{ wgkey['content'] | b64decode | trim }} | ||||||
| Address = {{ wireguard.address }} | Address = {{ wireguard.address }} | ||||||
| {% if wireguard.listenport is defined %} | {% if wireguard.listenport is defined %} | ||||||
| @@ -6,8 +8,26 @@ ListenPort = {{ wireguard.listenport }} | |||||||
| {% endif %} | {% endif %} | ||||||
|  |  | ||||||
| {% for peer in wireguard.peers %} | {% for peer in wireguard.peers %} | ||||||
|  | {% if peer.name is defined %} | ||||||
|  | [Peer] # {{ peer.name }} | ||||||
|  | {% else %} | ||||||
| [Peer] | [Peer] | ||||||
|  | {% endif %} | ||||||
| PublicKey = {{ peer.publickey }} | PublicKey = {{ peer.publickey }} | ||||||
|  | {% if peer.presharedkey is defined %} | ||||||
|  | PresharedKey = {{ peer.presharedkey }} | ||||||
|  | {% else %} | ||||||
|  | {% set preshared_key = ( | ||||||
|  |     wgshared.results | ||||||
|  |     | selectattr('item.item.name', 'equalto', peer.name) | ||||||
|  |     | first | ||||||
|  |   ).content | ||||||
|  |   | default(none) | ||||||
|  | %} | ||||||
|  | {% if preshared_key is not none %} | ||||||
|  | PresharedKey = {{ preshared_key | b64decode | trim }} | ||||||
|  | {% endif %} | ||||||
|  | {% endif %} | ||||||
| {% if peer.endpoint is defined %} | {% if peer.endpoint is defined %} | ||||||
| Endpoint = {{ peer.endpoint }} | Endpoint = {{ peer.endpoint }} | ||||||
| {% endif %} | {% endif %} | ||||||
|   | |||||||
| @@ -1,7 +1,10 @@ | |||||||
| bitwarden_name: bitwarden | bitwarden_name: bitwarden | ||||||
| bitwarden_root: "/var/lib/{{ bitwarden_name }}" | bitwarden_user: bitwarden | ||||||
|  | bitwarden_root: /home/bitwarden | ||||||
| bitwarden_logs_identity: "{{ bitwarden_root }}/bwdata/logs/identity/Identity" | 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_logs_identity_date: | ||||||
|  |   "{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ | ||||||
|  |   ansible_date_time.day }}" | ||||||
| bitwarden_database: "{{ bitwarden_name }}" | bitwarden_database: "{{ bitwarden_name }}" | ||||||
| bitwarden_realips: "172.16.0.0/12" | bitwarden_realips: "172.16.0.0/12" | ||||||
| bitwarden_standalone: false | bitwarden_standalone: false | ||||||
|   | |||||||
| @@ -5,7 +5,12 @@ | |||||||
|   listen: rebuild_bitwarden |   listen: rebuild_bitwarden | ||||||
|  |  | ||||||
| - name: Rebuild Bitwarden | - name: Rebuild Bitwarden | ||||||
|   ansible.builtin.shell: "{{ bitwarden_root }}/bitwarden.sh rebuild" |   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 |   listen: rebuild_bitwarden | ||||||
|  |  | ||||||
| - name: Start Bitwarden after rebuild | - name: Start Bitwarden after rebuild | ||||||
| @@ -14,3 +19,10 @@ | |||||||
|     state: started |     state: started | ||||||
|     enabled: true |     enabled: true | ||||||
|   listen: rebuild_bitwarden |   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 | ||||||
|   | |||||||
| @@ -3,41 +3,49 @@ | |||||||
|     name: expect |     name: expect | ||||||
|     state: present |     state: present | ||||||
|  |  | ||||||
| - name: Create Bitwarden directory |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ bitwarden_root }}" |  | ||||||
|     state: directory |  | ||||||
|  |  | ||||||
| - name: Download Bitwarden script | - name: Download Bitwarden script | ||||||
|   ansible.builtin.get_url: |   ansible.builtin.get_url: | ||||||
|     url: "https://raw.githubusercontent.com/\ |     url: "https://raw.githubusercontent.com/\ | ||||||
|           bitwarden/self-host/master/bitwarden.sh" |       bitwarden/self-host/master/bitwarden.sh" | ||||||
|     dest: "{{ bitwarden_root }}" |     dest: "{{ bitwarden_root }}" | ||||||
|  |     owner: "{{ bitwarden_user }}" | ||||||
|  |     group: "{{ bitwarden_user }}" | ||||||
|     mode: u+x |     mode: u+x | ||||||
|  |  | ||||||
| - name: Install Bitwarden script wrapper | - name: Install Bitwarden script wrapper | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: bw_wrapper.j2 |     src: bw_wrapper.j2 | ||||||
|     dest: "{{ bitwarden_root }}/bw_wrapper" |     dest: "{{ bitwarden_root }}/bw_wrapper" | ||||||
|  |     owner: "{{ bitwarden_user }}" | ||||||
|  |     group: "{{ bitwarden_user }}" | ||||||
|     mode: u+x |     mode: u+x | ||||||
|  |  | ||||||
| - name: Run Bitwarden installation script | - name: Run Bitwarden installation script | ||||||
|   ansible.builtin.shell: "{{ bitwarden_root }}/bw_wrapper" |   ansible.builtin.command: "{{ bitwarden_root }}/bw_wrapper" | ||||||
|   args: |   args: | ||||||
|     creates: "{{ bitwarden_root }}/bwdata/config.yml" |     creates: "{{ bitwarden_root }}/bwdata/config.yml" | ||||||
|  |   become_user: "{{ bitwarden_user }}" | ||||||
|  |   become: true | ||||||
|  |  | ||||||
| - name: Install docker-compose override | - name: Install compose override | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: compose.override.yml.j2 |     src: compose.override.yml.j2 | ||||||
|     dest: "{{ bitwarden_root }}/bwdata/docker/docker-compose.override.yml" |     dest: "{{ bitwarden_root }}/bwdata/docker/docker-compose.override.yml" | ||||||
|   when: traefik_version is defined |     owner: "{{ bitwarden_user }}" | ||||||
|  |     group: "{{ bitwarden_user }}" | ||||||
|  |     mode: "644" | ||||||
|  |   become_user: "{{ bitwarden_user }}" | ||||||
|  |   become: true | ||||||
|  |   when: bitwarden_override | default(true) | ||||||
|   notify: rebuild_bitwarden |   notify: rebuild_bitwarden | ||||||
|  |  | ||||||
| - name: Disable bitwarden-nginx HTTP on 80 | - name: Disable bitwarden-nginx HTTP on 80 | ||||||
|   ansible.builtin.replace: |   ansible.builtin.replace: | ||||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" |     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||||
|     regexp: "^http_port: 80$" |     regexp: "^http_port: 80$" | ||||||
|     replace: "http_port: 127.0.0.1:8080" |     replace: "http_port: {{ bitwarden_http_port | default('127.0.0.1:9080') }}" | ||||||
|  |   become_user: "{{ bitwarden_user }}" | ||||||
|  |   become: true | ||||||
|   when: not bitwarden_standalone |   when: not bitwarden_standalone | ||||||
|   notify: rebuild_bitwarden |   notify: rebuild_bitwarden | ||||||
|  |  | ||||||
| @@ -45,7 +53,10 @@ | |||||||
|   ansible.builtin.replace: |   ansible.builtin.replace: | ||||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" |     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||||
|     regexp: "^https_port: 443$" |     regexp: "^https_port: 443$" | ||||||
|     replace: "https_port: 127.0.0.1:8443" |     replace: | ||||||
|  |       "https_port: {{ bitwarden_https_port | default('127.0.0.1:9443') }}" | ||||||
|  |   become_user: "{{ bitwarden_user }}" | ||||||
|  |   become: true | ||||||
|   when: not bitwarden_standalone |   when: not bitwarden_standalone | ||||||
|   notify: rebuild_bitwarden |   notify: rebuild_bitwarden | ||||||
|  |  | ||||||
| @@ -54,6 +65,8 @@ | |||||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" |     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||||
|     regexp: "^ssl_managed_lets_encrypt: true$" |     regexp: "^ssl_managed_lets_encrypt: true$" | ||||||
|     replace: "ssl_managed_lets_encrypt: false" |     replace: "ssl_managed_lets_encrypt: false" | ||||||
|  |   become_user: "{{ bitwarden_user }}" | ||||||
|  |   become: true | ||||||
|   when: not bitwarden_standalone or not bitwarden_production |   when: not bitwarden_standalone or not bitwarden_production | ||||||
|   notify: rebuild_bitwarden |   notify: rebuild_bitwarden | ||||||
|  |  | ||||||
| @@ -62,6 +75,8 @@ | |||||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" |     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||||
|     regexp: "^ssl: true$" |     regexp: "^ssl: true$" | ||||||
|     replace: "ssl: false" |     replace: "ssl: false" | ||||||
|  |   become_user: "{{ bitwarden_user }}" | ||||||
|  |   become: true | ||||||
|   when: not bitwarden_standalone |   when: not bitwarden_standalone | ||||||
|   notify: rebuild_bitwarden |   notify: rebuild_bitwarden | ||||||
|  |  | ||||||
| @@ -70,12 +85,17 @@ | |||||||
|     path: "{{ bitwarden_root }}/bwdata/config.yml" |     path: "{{ bitwarden_root }}/bwdata/config.yml" | ||||||
|     line: "- {{ bitwarden_realips }}" |     line: "- {{ bitwarden_realips }}" | ||||||
|     insertafter: "^real_ips" |     insertafter: "^real_ips" | ||||||
|  |   become_user: "{{ bitwarden_user }}" | ||||||
|  |   become: true | ||||||
|   notify: rebuild_bitwarden |   notify: rebuild_bitwarden | ||||||
|  |  | ||||||
| - name: Install Bitwarden systemd service | - name: Install Bitwarden systemd service | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: bitwarden.service.j2 |     src: bitwarden.service.j2 | ||||||
|     dest: "/etc/systemd/system/{{ bitwarden_name }}.service" |     dest: "/etc/systemd/system/{{ bitwarden_name }}.service" | ||||||
|  |     owner: "{{ bitwarden_user }}" | ||||||
|  |     group: "{{ bitwarden_user }}" | ||||||
|  |     mode: "644" | ||||||
|   register: bitwarden_systemd |   register: bitwarden_systemd | ||||||
|   notify: rebuild_bitwarden |   notify: rebuild_bitwarden | ||||||
|  |  | ||||||
| @@ -83,22 +103,14 @@ | |||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: "{{ bitwarden_logs_identity }}" |     path: "{{ bitwarden_logs_identity }}" | ||||||
|     state: directory |     state: directory | ||||||
|   register: bitwarden_logs |     owner: "{{ bitwarden_user }}" | ||||||
|  |     group: "{{ bitwarden_user }}" | ||||||
| - name: Create Bitwarden's initial log file |     mode: "755" | ||||||
|   ansible.builtin.file: |   notify: touch_bitwarden | ||||||
|     path: "{{ bitwarden_logs_identity }}/{{ bitwarden_logs_identity_date }}.txt" |  | ||||||
|     state: touch |  | ||||||
|   when: bitwarden_logs.changed |  | ||||||
|  |  | ||||||
| - name: Install Bitwarden's Fail2ban jail | - name: Install Bitwarden's Fail2ban jail | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: fail2ban-jail.conf.j2 |     src: fail2ban-jail.conf.j2 | ||||||
|     dest: /etc/fail2ban/jail.d/bitwarden.conf |     dest: /etc/fail2ban/jail.d/bitwarden.conf | ||||||
|  |     mode: "640" | ||||||
|   notify: restart_fail2ban |   notify: restart_fail2ban | ||||||
|  |  | ||||||
| - name: Reload systemd manager configuration |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     daemon_reload: true |  | ||||||
|   when: bitwarden_systemd.changed |  | ||||||
|   notify: rebuild_bitwarden |  | ||||||
|   | |||||||
| @@ -23,10 +23,13 @@ send "{{ bitwarden_install_id }}\r" | |||||||
| expect "Enter your installation key:" | expect "Enter your installation key:" | ||||||
| send "{{ bitwarden_install_key }}\r" | 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" | 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 %} | {% if bitwarden_standalone and not bitwarden_production %} | ||||||
| send "y\r" | send "y\r" | ||||||
| {% else %} | {% else %} | ||||||
|   | |||||||
| @@ -6,13 +6,11 @@ services: | |||||||
|       - traefik |       - traefik | ||||||
|     labels: |     labels: | ||||||
|       traefik.http.routers.bitwarden.rule: "Host(`{{ bitwarden_domain }}`)" |       traefik.http.routers.bitwarden.rule: "Host(`{{ bitwarden_domain }}`)" | ||||||
|       traefik.http.routers.bitwarden.entrypoints: websecure |       traefik.http.routers.bitwarden.entrypoints: {{ bitwarden_entrypoint | default('web') }} | ||||||
|       traefik.http.routers.bitwarden.tls.certresolver: letsencrypt |       traefik.http.routers.bitwarden.tls: {{ bitwarden_traefik_tls | default('false') }} | ||||||
|       traefik.http.routers.bitwarden.middlewares: "securehttps@file" |  | ||||||
|       traefik.http.services.bitwarden.loadbalancer.server.port: 8080 |       traefik.http.services.bitwarden.loadbalancer.server.port: 8080 | ||||||
|       traefik.docker.network: traefik |       traefik.docker.network: traefik | ||||||
|       traefik.enable: "true" |       traefik.enable: "true" | ||||||
|  |  | ||||||
| networks: | networks: | ||||||
|   traefik: |   traefik: | ||||||
|     external: true |     external: true | ||||||
|   | |||||||
| @@ -1,6 +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_root: /var/lib/compose | ||||||
| docker_compose_service: compose | docker_compose_service: compose | ||||||
| docker_compose: /usr/bin/docker-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_keys: "{{ docker_repos_path }}/.keys" | ||||||
| docker_repos_keytype: rsa | docker_repos_keytype: rsa | ||||||
| docker_repos_path: /srv/.compose_repos | docker_repos_path: /srv/.compose_repos | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|   listen: compose_systemd |   listen: compose_systemd | ||||||
|  |  | ||||||
| - name: Find which services had a docker-compose.yml updated | - name: Find which services had a docker-compose.yml updated | ||||||
|   set_fact: |   ansible.builtin.set_fact: | ||||||
|     compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}" |     compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}" | ||||||
|   loop: "{{ compose_update.results }}" |   loop: "{{ compose_update.results }}" | ||||||
|   loop_control: |   loop_control: | ||||||
| @@ -13,7 +13,7 @@ | |||||||
|   listen: compose_restart |   listen: compose_restart | ||||||
|  |  | ||||||
| - name: Find which services had their .env updated | - name: Find which services had their .env updated | ||||||
|   set_fact: |   ansible.builtin.set_fact: | ||||||
|     compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}" |     compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}" | ||||||
|   loop: "{{ compose_env_update.results }}" |   loop: "{{ compose_env_update.results }}" | ||||||
|   loop_control: |   loop_control: | ||||||
| @@ -21,10 +21,34 @@ | |||||||
|   when: item.changed |   when: item.changed | ||||||
|   listen: compose_restart |   listen: compose_restart | ||||||
|  |  | ||||||
| - name: Restart {{ docker_compose_service }} services | - 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: |   ansible.builtin.systemd: | ||||||
|     state: restarted |     state: restarted | ||||||
|     name: "{{ docker_compose_service }}@{{ item }}" |     name: "{{ docker_compose_service }}@{{ item }}" | ||||||
|   loop: "{{ compose_restart_list | unique }}" |   loop: "{{ compose_restart_list | default([]) | unique }}" | ||||||
|   when: compose_restart_list is defined |   when: compose_restart_list is defined | ||||||
|   listen: compose_restart |   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,7 +1,46 @@ | |||||||
| - name: Install Docker | - 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 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: |   ansible.builtin.apt: | ||||||
|     name: ['docker.io', 'docker-compose'] |     name: ["docker.io", "docker-compose", "containerd", "runc"] | ||||||
|     state: present |     state: "{{ 'absent' if docker_official else 'present' }}" | ||||||
|  |     autoremove: true | ||||||
|  |     update_cache: true | ||||||
|  |  | ||||||
|  | - 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 |     update_cache: true | ||||||
|  |  | ||||||
| - name: Login to private registry | - name: Login to private registry | ||||||
| @@ -15,20 +54,20 @@ | |||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: "{{ docker_compose_root }}" |     path: "{{ docker_compose_root }}" | ||||||
|     state: directory |     state: directory | ||||||
|     mode: 0500 |     mode: "500" | ||||||
|  |  | ||||||
| - name: Install docker-compose systemd service | - name: Install docker-compose systemd service | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: docker-compose.service.j2 |     src: docker-compose.service.j2 | ||||||
|     dest: "/etc/systemd/system/{{ docker_compose_service }}@.service" |     dest: "/etc/systemd/system/{{ docker_compose_service }}@.service" | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   notify: compose_systemd |   notify: compose_systemd | ||||||
|  |  | ||||||
| - name: Create directories to clone docker-compose repositories | - name: Create directories to clone docker-compose repositories | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: "{{ item }}" |     path: "{{ item }}" | ||||||
|     state: directory |     state: directory | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   loop: |   loop: | ||||||
|     - "{{ docker_repos_path }}" |     - "{{ docker_repos_path }}" | ||||||
|     - "{{ docker_repos_keys }}" |     - "{{ docker_repos_keys }}" | ||||||
| @@ -39,7 +78,13 @@ | |||||||
|     path: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}" |     path: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}" | ||||||
|     type: "{{ docker_repos_keytype }}" |     type: "{{ docker_repos_keytype }}" | ||||||
|     comment: "{{ ansible_hostname }}-deploy-key" |     comment: "{{ ansible_hostname }}-deploy-key" | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|  |     state: present | ||||||
|  |   when: docker_compose_deploy is defined | ||||||
|  |  | ||||||
|  | - name: Check for git installation | ||||||
|  |   ansible.builtin.apt: | ||||||
|  |     name: git | ||||||
|     state: present |     state: present | ||||||
|   when: docker_compose_deploy is defined |   when: docker_compose_deploy is defined | ||||||
|  |  | ||||||
| @@ -48,7 +93,7 @@ | |||||||
|     repo: "{{ item.url }}" |     repo: "{{ item.url }}" | ||||||
|     dest: "{{ docker_repos_path }}/{{ item.name }}" |     dest: "{{ docker_repos_path }}/{{ item.name }}" | ||||||
|     version: "{{ item.version }}" |     version: "{{ item.version }}" | ||||||
|     accept_newhostkey: "{{ item.accept_newhostkey | default('false') }}" |     accept_newhostkey: "{{ item.accept_newhostkey | default(false) }}" | ||||||
|     gpg_whitelist: "{{ item.trusted_keys | default([]) }}" |     gpg_whitelist: "{{ item.trusted_keys | default([]) }}" | ||||||
|     verify_commit: "{{ true if (item.trusted_keys is defined and item.trusted_keys) else false }}" |     verify_commit: "{{ true if (item.trusted_keys is defined and item.trusted_keys) else false }}" | ||||||
|     key_file: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}" |     key_file: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}" | ||||||
| @@ -61,7 +106,7 @@ | |||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: "{{ docker_compose_root }}/{{ item.name }}" |     path: "{{ docker_compose_root }}/{{ item.name }}" | ||||||
|     state: directory |     state: directory | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   loop: "{{ docker_compose_deploy }}" |   loop: "{{ docker_compose_deploy }}" | ||||||
|   loop_control: |   loop_control: | ||||||
|     label: "{{ item.name }}" |     label: "{{ item.name }}" | ||||||
| @@ -73,7 +118,9 @@ | |||||||
|     dest: "{{ docker_compose_root }}/{{ item.name }}/docker-compose.yml" |     dest: "{{ docker_compose_root }}/{{ item.name }}/docker-compose.yml" | ||||||
|   delegate_to: "{{ inventory_hostname }}" |   delegate_to: "{{ inventory_hostname }}" | ||||||
|   register: compose_update |   register: compose_update | ||||||
|   notify: compose_restart |   notify: | ||||||
|  |     - compose_restart | ||||||
|  |     - compose_enable | ||||||
|   loop: "{{ docker_compose_deploy | default([]) }}" |   loop: "{{ docker_compose_deploy | default([]) }}" | ||||||
|   loop_control: |   loop_control: | ||||||
|     label: "{{ item.name }}" |     label: "{{ item.name }}" | ||||||
| @@ -83,35 +130,20 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: docker-compose-env.j2 |     src: docker-compose-env.j2 | ||||||
|     dest: "{{ docker_compose_root }}/{{ item.name }}/.env" |     dest: "{{ docker_compose_root }}/{{ item.name }}/.env" | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   register: compose_env_update |   register: compose_env_update | ||||||
|   notify: compose_restart |   notify: | ||||||
|   no_log: "{{ docker_compose_env_nolog | default('true') }}" |     - compose_restart | ||||||
|  |     - compose_enable | ||||||
|  |   no_log: "{{ docker_compose_env_nolog | default(true) }}" | ||||||
|   loop: "{{ docker_compose_deploy }}" |   loop: "{{ docker_compose_deploy }}" | ||||||
|   loop_control: |   loop_control: | ||||||
|     label: "{{ item.name }}" |     label: "{{ item.name }}" | ||||||
|   when: docker_compose_deploy is defined and item.env is defined |   when: docker_compose_deploy is defined and item.env is defined | ||||||
|  |  | ||||||
| - name: Add users to docker group |  | ||||||
|   ansible.builtin.user: |  | ||||||
|     name: "{{ item }}" |  | ||||||
|     groups: docker |  | ||||||
|     append: true |  | ||||||
|   loop: "{{ docker_users }}" |  | ||||||
|   when: docker_users is defined |  | ||||||
|  |  | ||||||
| - name: Start Docker and enable on boot | - name: Start Docker and enable on boot | ||||||
|   ansible.builtin.service: |   ansible.builtin.service: | ||||||
|     name: docker |     name: docker | ||||||
|     state: started |     state: started | ||||||
|     enabled: true |     enabled: true | ||||||
|  |   when: docker_managed | default(true) | ||||||
| - name: Start docker-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 |  | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| [Unit] | [Unit] | ||||||
| Description=%i docker-compose service | Description=%i {{ docker_compose_service }} service | ||||||
| PartOf=docker.service | PartOf=docker.service | ||||||
| After=docker.service | After=docker.service | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ | |||||||
| - name: Create git's .ssh directory | - name: Create git's .ssh directory | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: /home/git/.ssh |     path: /home/git/.ssh | ||||||
|  |     mode: "700" | ||||||
|     state: directory |     state: directory | ||||||
|  |  | ||||||
| - name: Generate git's SSH keys | - name: Generate git's SSH keys | ||||||
| @@ -40,6 +41,7 @@ | |||||||
| - name: Create git's authorized_keys file | - name: Create git's authorized_keys file | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: /home/git/.ssh/authorized_keys |     path: /home/git/.ssh/authorized_keys | ||||||
|  |     mode: "600" | ||||||
|     state: touch |     state: touch | ||||||
|   when: not git_authkeys.stat.exists |   when: not git_authkeys.stat.exists | ||||||
|  |  | ||||||
| @@ -53,27 +55,24 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: gitea.sh.j2 |     src: gitea.sh.j2 | ||||||
|     dest: /usr/local/bin/gitea |     dest: /usr/local/bin/gitea | ||||||
|     mode: 0755 |     mode: "755" | ||||||
|  |  | ||||||
| - name: Create Gitea's logging directory | - name: Create Gitea's logging directory | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     name: /var/log/gitea |     name: /var/log/gitea | ||||||
|     state: directory |     state: directory | ||||||
|  |     mode: "755" | ||||||
|  |  | ||||||
| - name: Install Gitea's Fail2ban filter | - name: Install Gitea's Fail2ban filter | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: fail2ban-filter.conf.j2 |     src: fail2ban-filter.conf.j2 | ||||||
|     dest: /etc/fail2ban/filter.d/gitea.conf |     dest: /etc/fail2ban/filter.d/gitea.conf | ||||||
|  |     mode: "644" | ||||||
|   notify: restart_fail2ban |   notify: restart_fail2ban | ||||||
|  |  | ||||||
| - name: Install Gitea's Fail2ban jail | - name: Install Gitea's Fail2ban jail | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: fail2ban-jail.conf.j2 |     src: fail2ban-jail.conf.j2 | ||||||
|     dest: /etc/fail2ban/jail.d/gitea.conf |     dest: /etc/fail2ban/jail.d/gitea.conf | ||||||
|  |     mode: "640" | ||||||
|   notify: restart_fail2ban |   notify: restart_fail2ban | ||||||
|  |  | ||||||
| - name: Start and enable Gitea service |  | ||||||
|   ansible.builtin.service: |  | ||||||
|     name: "{{ docker_compose_service }}@{{ gitea_name }}" |  | ||||||
|     state: started |  | ||||||
|     enabled: true |  | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ services: | |||||||
|     networks: |     networks: | ||||||
|       - traefik |       - traefik | ||||||
|     labels: |     labels: | ||||||
|       - "traefik.http.routers.{{ jellyfin_router }}.rule=Host(`{{ jellyfin_domain }}`)" |       - "traefik.http.routers.{{ jellyfin_router }}.rule=Host({{ jellyfin_domains }})" | ||||||
| {% if traefik_http_only %} | {% if traefik_http_only %} | ||||||
|       - "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web" |       - "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web" | ||||||
| {% else %} | {% else %} | ||||||
|   | |||||||
| @@ -2,4 +2,11 @@ | |||||||
|   ansible.builtin.service: |   ansible.builtin.service: | ||||||
|     name: mariadb |     name: mariadb | ||||||
|     state: restarted |     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 |   listen: restart_mariadb | ||||||
|   | |||||||
| @@ -3,6 +3,10 @@ | |||||||
|     name: mariadb-server |     name: mariadb-server | ||||||
|     state: present |     state: present | ||||||
|  |  | ||||||
|  | - name: Set MariaDB restarted fact | ||||||
|  |   ansible.builtin.set_fact: | ||||||
|  |     mariadb_restarted: false | ||||||
|  |  | ||||||
| - name: Regather facts for the potentially new docker0 interface | - name: Regather facts for the potentially new docker0 interface | ||||||
|   ansible.builtin.setup: |   ansible.builtin.setup: | ||||||
|  |  | ||||||
| @@ -12,6 +16,12 @@ | |||||||
|     regex: "^bind-address" |     regex: "^bind-address" | ||||||
|     line: "bind-address            = {{ ansible_facts.docker0.ipv4.address }}" |     line: "bind-address            = {{ ansible_facts.docker0.ipv4.address }}" | ||||||
|   notify: restart_mariadb |   notify: restart_mariadb | ||||||
|  |   when: ansible_facts.docker0 is defined | ||||||
|  |  | ||||||
|  | - name: Flush handlers to ensure MariaDB restarts immediately | ||||||
|  |   ansible.builtin.meta: flush_handlers | ||||||
|  |   tags: restart_mariadb | ||||||
|  |   when: ansible_facts.docker0 is defined | ||||||
|  |  | ||||||
| - name: Allow database connections from Docker | - name: Allow database connections from Docker | ||||||
|   community.general.ufw: |   community.general.ufw: | ||||||
|   | |||||||
| @@ -1,11 +1 @@ | |||||||
| # container names | nextcloud_name: nextcloud | ||||||
| nextcloud_container: nextcloud |  | ||||||
| nextcloud_dbcontainer: "{{ nextcloud_container }}-db" |  | ||||||
|  |  | ||||||
| # database settings |  | ||||||
| nextcloud_dbname: "{{ nextcloud_container }}" |  | ||||||
| nextcloud_dbuser: "{{ nextcloud_dbname }}" |  | ||||||
|  |  | ||||||
| # host mounts |  | ||||||
| nextcloud_root: "/opt/{{ nextcloud_container }}/public_html" |  | ||||||
| nextcloud_dbroot: "/opt/{{ nextcloud_container }}/database" |  | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								roles/nextcloud/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								roles/nextcloud/handlers/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | - name: Set Nextcloud's Trusted Proxy | ||||||
|  |   ansible.builtin.command: > | ||||||
|  |     docker exec --user www-data "{{ nextcloud_name }}" | ||||||
|  |       php occ config:system:set trusted_proxies 0 --value="{{ traefik_name }}" | ||||||
|  |   register: nextcloud_trusted_proxy | ||||||
|  |   changed_when: "nextcloud_trusted_proxy.stdout == 'System config value trusted_proxies => 0 set to string ' ~ traefik_name" | ||||||
|  |   listen: install_nextcloud | ||||||
|  |  | ||||||
|  | - name: Set Nextcloud's Trusted Domain | ||||||
|  |   ansible.builtin.command: > | ||||||
|  |     docker exec --user www-data "{{ nextcloud_name }}" | ||||||
|  |       php occ config:system:set trusted_domains 0 --value="{{ nextcloud.DOMAIN }}" | ||||||
|  |   register: nextcloud_trusted_domains | ||||||
|  |   changed_when: "nextcloud_trusted_domains.stdout == 'System config value trusted_domains => 0 set to string ' ~ nextcloud.DOMAIN" | ||||||
|  |   listen: install_nextcloud | ||||||
|  |  | ||||||
|  | - name: Preform Nextcloud database maintenance | ||||||
|  |   ansible.builtin.command: > | ||||||
|  |     docker exec --user www-data "{{ nextcloud_name }}" {{ item }} | ||||||
|  |   loop: | ||||||
|  |     - "php occ maintenance:mode --on" | ||||||
|  |     - "php occ db:add-missing-indices" | ||||||
|  |     - "php occ db:convert-filecache-bigint" | ||||||
|  |     - "php occ maintenance:mode --off" | ||||||
|  |   listen: install_nextcloud | ||||||
| @@ -1,109 +1,62 @@ | |||||||
| - name: Create Nextcloud network | - name: Install MySQL module for Ansible | ||||||
|   community.general.docker_network: |   ansible.builtin.apt: | ||||||
|     name: "{{ nextcloud_container }}" |     name: python3-pymysql | ||||||
|  |     state: present | ||||||
|  |  | ||||||
| - name: Start Nextcloud's database container | - name: Create Nextcloud database | ||||||
|   community.general.docker_container: |   community.mysql.mysql_db: | ||||||
|     name: "{{ nextcloud_dbcontainer }}" |     name: "{{ nextcloud.DB_NAME | default('nextcloud') }}" | ||||||
|     image: mariadb:{{ nextcloud_dbversion }} |     state: present | ||||||
|  |     login_unix_socket: /var/run/mysqld/mysqld.sock | ||||||
|  |  | ||||||
|  | - name: Create Nextcloud database user | ||||||
|  |   community.mysql.mysql_user: | ||||||
|  |     name: "{{ nextcloud.DB_USER | default('nextcloud') }}" | ||||||
|  |     password: "{{ nextcloud.DB_PASSWD }}" | ||||||
|  |     host: '%' | ||||||
|  |     state: present | ||||||
|  |     priv: "{{ nextcloud.DB_NAME | default('nextcloud') }}.*:ALL" | ||||||
|  |     login_unix_socket: /var/run/mysqld/mysqld.sock | ||||||
|  |  | ||||||
|  | - name: Start Nextcloud service and enable on boot | ||||||
|  |   ansible.builtin.service: | ||||||
|  |     name: "{{ docker_compose_service }}@{{ nextcloud_name }}" | ||||||
|     state: started |     state: started | ||||||
|     restart_policy: always |     enabled: true | ||||||
|     volumes: "{{ nextcloud_dbroot }}:/var/lib/mysql" |   when: nextcloud.ENABLE | default('false') | ||||||
|     networks_cli_compatible: true |  | ||||||
|     networks: |  | ||||||
|       - name: "{{ nextcloud_container }}" |  | ||||||
|     env: |  | ||||||
|       MYSQL_RANDOM_ROOT_PASSWORD: "true" |  | ||||||
|       MYSQL_DATABASE: "{{ nextcloud_dbname }}" |  | ||||||
|       MYSQL_USER: "{{ nextcloud_dbuser }}" |  | ||||||
|       MYSQL_PASSWORD: "{{ nextcloud_dbpass }}" |  | ||||||
|  |  | ||||||
| - name: Start Nextcloud container |  | ||||||
|   community.general.docker_container: |  | ||||||
|     name: "{{ nextcloud_container }}" |  | ||||||
|     image: nextcloud:{{ nextcloud_version }} |  | ||||||
|     state: started |  | ||||||
|     restart_policy: always |  | ||||||
|     volumes: "{{ nextcloud_root }}:/var/www/html" |  | ||||||
|     networks_cli_compatible: true |  | ||||||
|     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/" |  | ||||||
|       traefik.http.middlewares.nextcloud-webdav.redirectregex.permanent: "true" |  | ||||||
|       traefik.docker.network: traefik |  | ||||||
|       traefik.enable: "true" |  | ||||||
|  |  | ||||||
| - name: Grab Nextcloud database container information |  | ||||||
|   community.general.docker_container_info: |  | ||||||
|     name: "{{ nextcloud_dbcontainer }}" |  | ||||||
|   register: nextcloud_dbinfo |  | ||||||
|  |  | ||||||
| - name: Grab Nextcloud container information | - name: Grab Nextcloud container information | ||||||
|   community.general.docker_container_info: |   community.general.docker_container_info: | ||||||
|     name: "{{ nextcloud_container }}" |     name: "{{ nextcloud_name }}" | ||||||
|   register: nextcloud_info |   register: nextcloud_info | ||||||
|  |  | ||||||
| - name: Wait for Nextcloud to become available | - name: Wait for Nextcloud to become available | ||||||
|   ansible.builtin.wait_for: |   ansible.builtin.wait_for: | ||||||
|     host: "{{ nextcloud_info.container.NetworkSettings.Networks.traefik.IPAddress }}" |     host: "{{ nextcloud_info.container.NetworkSettings.Networks.traefik.IPAddress }}" | ||||||
|  |     delay: 10 | ||||||
|     port: 80 |     port: 80 | ||||||
|  |  | ||||||
| - name: Check Nextcloud status | - name: Check Nextcloud status | ||||||
|   ansible.builtin.command: "docker exec --user www-data {{ nextcloud_container }} |   ansible.builtin.command: > | ||||||
|             php occ status" |     docker exec --user www-data "{{ nextcloud_name }}" php occ status | ||||||
|   register: nextcloud_status |   register: nextcloud_status | ||||||
|   args: |   changed_when: false | ||||||
|     removes: "{{ nextcloud_root }}/config/CAN_INSTALL" |  | ||||||
|  |  | ||||||
| - name: Wait for Nextcloud database to become available |  | ||||||
|   ansible.builtin.wait_for: |  | ||||||
|     host: "{{ nextcloud_dbinfo.container.NetworkSettings.Networks.nextcloud.IPAddress }}" |  | ||||||
|     port: 3306 |  | ||||||
|  |  | ||||||
| - name: Install Nextcloud | - name: Install Nextcloud | ||||||
|   ansible.builtin.command: 'docker exec --user www-data {{ nextcloud_container }} |   ansible.builtin.command: > | ||||||
|             php occ maintenance:install |     docker exec --user www-data {{ nextcloud_name }} | ||||||
|               --database "mysql" |       php occ maintenance:install | ||||||
|               --database-host "{{ nextcloud_dbcontainer }}" |         --database "mysql" | ||||||
|               --database-name "{{ nextcloud_dbname }}" |         --database-host "{{ nextcloud.DB_HOST | default('host.docker.internal') }}" | ||||||
|               --database-user "{{ nextcloud_dbuser }}" |         --database-name "{{ nextcloud.DB_NAME | default('nextcloud') }}" | ||||||
|               --database-pass "{{ nextcloud_dbpass }}" |         --database-user "{{ nextcloud.DB_USER | default('nextcloud') }}" | ||||||
|               --admin-user "{{ nextcloud_admin }}" |         --database-pass "{{ nextcloud.DB_PASSWD }}" | ||||||
|               --admin-pass "{{ nextcloud_pass }}"' |         --admin-user "{{ nextcloud.ADMIN_USER | default('admin') }}" | ||||||
|  |         --admin-pass "{{ nextcloud.ADMIN_PASSWD }}" | ||||||
|   register: nextcloud_install |   register: nextcloud_install | ||||||
|   when: |   when: nextcloud_status.stderr[:26] == "Nextcloud is not installed" | ||||||
|     - nextcloud_status.stdout[:26] == "Nextcloud is not installed" |   changed_when: nextcloud_install.stdout == "Nextcloud was successfully installed" | ||||||
|     - nextcloud_domain is defined |   notify: install_nextcloud | ||||||
|  |  | ||||||
| - name: Set Nextcloud's Trusted Proxy |  | ||||||
|   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 |  | ||||||
|   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 |  | ||||||
|   ansible.builtin.command: "docker exec --user www-data {{ nextcloud_container }} {{ item }}" |  | ||||||
|   loop: |  | ||||||
|     - "php occ maintenance:mode --on" |  | ||||||
|     - "php occ db:add-missing-indices" |  | ||||||
|     - "php occ db:convert-filecache-bigint" |  | ||||||
|     - "php occ maintenance:mode --off" |  | ||||||
|   when: nextcloud_install.changed |  | ||||||
|  |  | ||||||
| - name: Install Nextcloud background jobs cron | - name: Install Nextcloud background jobs cron | ||||||
|   ansible.builtin.cron: |   ansible.builtin.cron: | ||||||
| @@ -111,8 +64,3 @@ | |||||||
|     minute: "*/5" |     minute: "*/5" | ||||||
|     job: "/usr/bin/docker exec -u www-data nextcloud /usr/local/bin/php -f /var/www/html/cron.php" |     job: "/usr/bin/docker exec -u www-data nextcloud /usr/local/bin/php -f /var/www/html/cron.php" | ||||||
|     user: root |     user: root | ||||||
|  |  | ||||||
| - name: Remove Nextcloud's CAN_INSTALL file |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ nextcloud_root }}/config/CAN_INSTALL" |  | ||||||
|     state: absent |  | ||||||
|   | |||||||
							
								
								
									
										62
									
								
								roles/podman/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								roles/podman/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | - name: Install Podman | ||||||
|  |   ansible.builtin.apt: | ||||||
|  |     name: ["podman", "podman-compose", "podman-docker"] | ||||||
|  |     state: present | ||||||
|  |  | ||||||
|  | - name: Get user info for namespace users | ||||||
|  |   ansible.builtin.getent: | ||||||
|  |     database: passwd | ||||||
|  |     key: "{{ item }}" | ||||||
|  |   loop: "{{ user_namespaces }}" | ||||||
|  |   register: user_info | ||||||
|  |  | ||||||
|  | - name: Configure /etc/subuid for rootless users | ||||||
|  |   ansible.builtin.lineinfile: | ||||||
|  |     path: "/etc/subuid" | ||||||
|  |     line: | ||||||
|  |       "{{ item.item }}:{{ 100000 + | ||||||
|  |       ((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536) | ||||||
|  |       }}:65536" | ||||||
|  |     regexp: "^{{ item.item }}:" | ||||||
|  |     create: true | ||||||
|  |     backup: true | ||||||
|  |     mode: "0644" | ||||||
|  |   loop: "{{ user_info.results }}" | ||||||
|  |  | ||||||
|  | - name: Configure /etc/subgid for rootless users | ||||||
|  |   ansible.builtin.lineinfile: | ||||||
|  |     path: "/etc/subgid" | ||||||
|  |     line: | ||||||
|  |       "{{ item.item }}:{{ 100000 + | ||||||
|  |       ((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536) | ||||||
|  |       }}:65536" | ||||||
|  |     regexp: "^{{ item.item }}:" | ||||||
|  |     create: true | ||||||
|  |     backup: true | ||||||
|  |     mode: "0644" | ||||||
|  |   loop: "{{ user_info.results }}" | ||||||
|  |  | ||||||
|  | - name: Create nodocker file to disable Docker CLI emulation message | ||||||
|  |   ansible.builtin.file: | ||||||
|  |     path: /etc/containers/nodocker | ||||||
|  |     state: touch | ||||||
|  |     owner: root | ||||||
|  |     group: root | ||||||
|  |     mode: "0644" | ||||||
|  |  | ||||||
|  | - name: Create global containers config directory | ||||||
|  |   ansible.builtin.file: | ||||||
|  |     path: /etc/containers | ||||||
|  |     state: directory | ||||||
|  |     mode: "0755" | ||||||
|  |  | ||||||
|  | - name: Configure global containers.conf for rootless | ||||||
|  |   ansible.builtin.copy: | ||||||
|  |     content: | | ||||||
|  |       [engine] | ||||||
|  |       cgroup_manager = "cgroupfs" | ||||||
|  |       events_logger = "journald" | ||||||
|  |       runtime = "crun" | ||||||
|  |     dest: /etc/containers/containers.conf | ||||||
|  |     mode: "0644" | ||||||
|  |     backup: true | ||||||
							
								
								
									
										1
									
								
								roles/proxy/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								roles/proxy/defaults/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | cached_dhparams_pem: /vagrant/scratch/dhparams.pem | ||||||
| @@ -1,3 +1,13 @@ | |||||||
|  | - 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 | - name: Reload nginx | ||||||
|   ansible.builtin.service: |   ansible.builtin.service: | ||||||
|     name: nginx |     name: nginx | ||||||
|   | |||||||
| @@ -10,6 +10,19 @@ | |||||||
|     state: started |     state: started | ||||||
|     enabled: true |     enabled: true | ||||||
|  |  | ||||||
|  | - name: Check for cached dhparams.pem file | ||||||
|  |   ansible.builtin.stat: | ||||||
|  |     path: "{{ cached_dhparams_pem }}" | ||||||
|  |   register: dhparams_file | ||||||
|  |  | ||||||
|  | - name: Copy cached dhparams.pem to /etc/ssl/ | ||||||
|  |   ansible.builtin.copy: | ||||||
|  |     src: "{{ cached_dhparams_pem }}" | ||||||
|  |     dest: /etc/ssl/dhparams.pem | ||||||
|  |     mode: "600" | ||||||
|  |     remote_src: true | ||||||
|  |   when: dhparams_file.stat.exists | ||||||
|  |  | ||||||
| - name: Generate DH Parameters | - name: Generate DH Parameters | ||||||
|   community.crypto.openssl_dhparam: |   community.crypto.openssl_dhparam: | ||||||
|     path: /etc/ssl/dhparams.pem |     path: /etc/ssl/dhparams.pem | ||||||
| @@ -19,33 +32,24 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: nginx.conf.j2 |     src: nginx.conf.j2 | ||||||
|     dest: /etc/nginx/nginx.conf |     dest: /etc/nginx/nginx.conf | ||||||
|     mode: 0644 |     mode: "644" | ||||||
|   notify: reload_nginx |   notify: reload_nginx | ||||||
|  |  | ||||||
| - name: Install nginx sites configuration | - name: Install nginx sites configuration | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: server-nginx.conf.j2 |     src: server-nginx.conf.j2 | ||||||
|     dest: "/etc/nginx/sites-available/{{ item.domain }}.conf" |     dest: "/etc/nginx/sites-available/{{ item.domain }}.conf" | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|   loop: "{{ proxy.servers }}" |   loop: "{{ proxy.servers }}" | ||||||
|   notify: reload_nginx |   notify: reload_nginx | ||||||
|   register: nginx_sites |   register: nginx_sites | ||||||
|  |  | ||||||
| - 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: 0400 |  | ||||||
|   loop: "{{ nginx_sites.results }}" |  | ||||||
|   when: item.changed |  | ||||||
|   notify: reload_nginx |  | ||||||
|  |  | ||||||
| - name: Generate self-signed certificate | - name: Generate self-signed certificate | ||||||
|   ansible.builtin.command: 'openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes \ |   ansible.builtin.command: | ||||||
|           -subj   "/C=US/ST=Local/L=Local/O=Org/OU=IT/CN=example.com" \ |     'openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes \ | ||||||
|           -keyout /etc/ssl/private/nginx-selfsigned.key \ |     -subj   "/C=US/ST=Local/L=Local/O=Org/OU=IT/CN=example.com" \ | ||||||
|           -out    /etc/ssl/certs/nginx-selfsigned.crt' |     -keyout /etc/ssl/private/nginx-selfsigned.key \ | ||||||
|  |     -out    /etc/ssl/certs/nginx-selfsigned.crt' | ||||||
|   args: |   args: | ||||||
|     creates: /etc/ssl/certs/nginx-selfsigned.crt |     creates: /etc/ssl/certs/nginx-selfsigned.crt | ||||||
|   when: proxy.production is not defined or not proxy.production |   when: proxy.production is not defined or not proxy.production | ||||||
| @@ -53,41 +57,48 @@ | |||||||
|  |  | ||||||
| - name: Install LE's certbot | - name: Install LE's certbot | ||||||
|   ansible.builtin.apt: |   ansible.builtin.apt: | ||||||
|     name: ['certbot', 'python3-certbot-dns-cloudflare'] |     name: ["certbot", "python3-certbot-dns-cloudflare"] | ||||||
|     state: present |     state: present | ||||||
|   when: proxy.production is defined and proxy.production |   when: proxy.production is defined and proxy.production | ||||||
|  |  | ||||||
|  | - name: Grab Cloudflare API token for configuration | ||||||
|  |   ansible.builtin.slurp: | ||||||
|  |     src: /root/.cloudflare-api | ||||||
|  |   register: cfapi | ||||||
|  |   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined | ||||||
|  |  | ||||||
| - name: Install Cloudflare API token | - name: Install Cloudflare API token | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: cloudflare.ini.j2 |     src: cloudflare.ini.j2 | ||||||
|     dest: /root/.cloudflare.ini |     dest: /root/.cloudflare.ini | ||||||
|     mode: 0400 |     mode: "400" | ||||||
|  |   diff: false | ||||||
|   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined |   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined | ||||||
|  |  | ||||||
| - name: Create nginx post renewal hook directory | - name: Create nginx post renewal hook directory | ||||||
|   ansible.builtin.file: |   ansible.builtin.file: | ||||||
|     path: /etc/letsencrypt/renewal-hooks/post |     path: /etc/letsencrypt/renewal-hooks/post | ||||||
|     state: directory |     state: directory | ||||||
|     mode: 0500 |     mode: "500" | ||||||
|   when: proxy.production is defined and proxy.production |   when: proxy.production is defined and proxy.production | ||||||
|  |  | ||||||
| - name: Install nginx post renewal hook | - name: Install nginx post renewal hook | ||||||
|   ansible.builtin.copy: |   ansible.builtin.copy: | ||||||
|     src: reload-nginx.sh |     src: reload-nginx.sh | ||||||
|     dest: /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh |     dest: /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh | ||||||
|     mode: '0755' |     mode: "0755" | ||||||
|   when: proxy.production is defined and proxy.production |   when: proxy.production is defined and proxy.production | ||||||
|  |  | ||||||
| - name: Run Cloudflare DNS-01 challenges on wildcard domains | - name: Run Cloudflare DNS-01 challenges on wildcard domains | ||||||
|   ansible.builtin.shell: '/usr/bin/certbot certonly \ |   ansible.builtin.shell: '/usr/bin/certbot certonly \ | ||||||
|             --non-interactive \ |     --non-interactive \ | ||||||
|             --agree-tos \ |     --agree-tos \ | ||||||
|             --email "{{ proxy.dns_cloudflare.email }}" \ |     --email "{{ proxy.dns_cloudflare.email }}" \ | ||||||
|             --dns-cloudflare \ |     --dns-cloudflare \ | ||||||
|             --dns-cloudflare-credentials /root/.cloudflare.ini \ |     --dns-cloudflare-credentials /root/.cloudflare.ini \ | ||||||
|             -d "*.{{ item }}" \ |     -d "*.{{ item }}" \ | ||||||
|             -d "{{ item }}" \ |     -d "{{ item }}" \ | ||||||
|             {{ proxy.dns_cloudflare.opts | default("") }}' |     {{ proxy.dns_cloudflare.opts | default("") }}' | ||||||
|   args: |   args: | ||||||
|     creates: "/etc/letsencrypt/live/{{ item }}/fullchain.pem" |     creates: "/etc/letsencrypt/live/{{ item }}/fullchain.pem" | ||||||
|   loop: "{{ proxy.dns_cloudflare.wildcard_domains }}" |   loop: "{{ proxy.dns_cloudflare.wildcard_domains }}" | ||||||
|   | |||||||
| @@ -1,2 +1,2 @@ | |||||||
| # Cloudflare API token used by Certbot | # Cloudflare API token used by Certbot | ||||||
| dns_cloudflare_api_token = {{ proxy.dns_cloudflare.api_token }} | dns_cloudflare_api_token = {{ cfapi['content'] | b64decode | trim }} | ||||||
|   | |||||||
| @@ -28,14 +28,20 @@ server { | |||||||
|   ssl_certificate     /etc/ssl/certs/nginx-selfsigned.crt; |   ssl_certificate     /etc/ssl/certs/nginx-selfsigned.crt; | ||||||
|   ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; |   ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; | ||||||
| {% endif %} | {% 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 %} | {% if item.client_max_body_size is defined %} | ||||||
|   client_max_body_size {{ item.client_max_body_size }}; |   client_max_body_size {{ item.client_max_body_size }}; | ||||||
| {% endif %} | {% endif %} | ||||||
|   location / { |   location / { | ||||||
| {% if item.restrict is defined and item.restrict  %} | {% if item.hsts is defined %} | ||||||
|  |     add_header Strict-Transport-Security "max-age={{ item.hsts }}" always; | ||||||
|  | {% endif %} | ||||||
|  | {% if item.allowedips is defined %} | ||||||
|  | {% for ip in item.allowedips %} | ||||||
|  |     allow {{ ip }}; | ||||||
|  | {% endfor %} | ||||||
|  |     deny all; | ||||||
|  | {% endif %} | ||||||
|  | {% if item.restrict is defined and item.restrict %} | ||||||
|     auth_basic "{{ item.restrict_name | default('Restricted Access') }}"; |     auth_basic "{{ item.restrict_name | default('Restricted Access') }}"; | ||||||
|     auth_basic_user_file {{ item.restrict_file | default('/etc/nginx/.htpasswd') }}; |     auth_basic_user_file {{ item.restrict_file | default('/etc/nginx/.htpasswd') }}; | ||||||
|     proxy_set_header Authorization ""; |     proxy_set_header Authorization ""; | ||||||
| @@ -43,6 +49,7 @@ server { | |||||||
|     proxy_set_header Host $host; |     proxy_set_header Host $host; | ||||||
|     proxy_set_header X-Real-IP $remote_addr; |     proxy_set_header X-Real-IP $remote_addr; | ||||||
|     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||||
|  |     proxy_set_header X-Forwarded-Proto $scheme; | ||||||
|     proxy_pass {{ item.proxy_pass }}; |     proxy_pass {{ item.proxy_pass }}; | ||||||
| {% if item.proxy_ssl_verify is defined and item.proxy_ssl_verify is false %} | {% if item.proxy_ssl_verify is defined and item.proxy_ssl_verify is false %} | ||||||
|     proxy_ssl_verify off; |     proxy_ssl_verify off; | ||||||
|   | |||||||
| @@ -21,20 +21,6 @@ | |||||||
|   loop: "{{ traefik_external }}" |   loop: "{{ traefik_external }}" | ||||||
|   when: traefik_external is defined |   when: traefik_external is defined | ||||||
|  |  | ||||||
| - name: Install Traefik's docker-compose file |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: docker-compose.yml.j2 |  | ||||||
|     dest: "{{ traefik_root }}/docker-compose.yml" |  | ||||||
|     mode: 0400 |  | ||||||
|   notify: restart_traefik |  | ||||||
|  |  | ||||||
| - name: Install Traefik's docker-compose variables |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: compose-env.j2 |  | ||||||
|     dest: "{{ traefik_root }}/.env" |  | ||||||
|     mode: 0400 |  | ||||||
|   notify: restart_traefik |  | ||||||
|  |  | ||||||
| - name: Install static Traefik configuration | - name: Install static Traefik configuration | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: traefik.yml.j2 |     src: traefik.yml.j2 | ||||||
| @@ -42,8 +28,9 @@ | |||||||
|     mode: 0400 |     mode: 0400 | ||||||
|   notify: restart_traefik |   notify: restart_traefik | ||||||
|  |  | ||||||
| - name: Start and enable Traefik service | - name: Start Traefik service and enable on boot | ||||||
|   ansible.builtin.service: |   ansible.builtin.service: | ||||||
|     name: "{{ docker_compose_service }}@{{ traefik_name }}" |     name: "{{ docker_compose_service }}@{{ traefik_name }}" | ||||||
|     state: started |     state: started | ||||||
|     enabled: true |     enabled: true | ||||||
|  |   when: traefik.ENABLED | default('false') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user