Compare commits

...

83 Commits

Author SHA1 Message Date
3102c621f0
Add optional IP restriction for nginx site configs 2024-10-19 21:08:15 -04:00
e3f03edf3f
Use file-based preshared keys for WireGuard
- Include proxy role in standard Docker playbook
2024-10-13 22:27:27 -04:00
f481a965dd
Update Samba and WireGuard configuration
- Adjust Samba config file permissions to 644
- Introduce PresharedKey option in WireGuard config template
2024-09-10 22:35:20 -04:00
a0aa289c05
Restrict GitHub Actions to a dedicated branch
- The Vagrant testing setup on macos-latest is broken
- Temporary measure until fixed or abandoned
2024-09-10 22:11:31 -04:00
324fe0b191
Upgrade Nextcloud setup to use compose files
- Integrated MariaDB role into Dockerbox configuration
- Moved proxy role to the end to avoid early endpoint activation
- Temporarily disabled select roles for future re-evaluation
- Introduced flush_handlers task for early MariaDB restart
- Moved a few Nextcloud tasks to handlers
- Configured Nextcloud to utilize the host's MariaDB instance
- Enhanced overall code linting quality
2024-04-21 22:27:48 -04:00
6fbd3c53bb
Add Vagrant cache option for dhparams.pem 2024-03-26 21:51:39 -04:00
01e8e22c01
Prevent running 'vagrant ssh' as root
Resolve possible issues with 'vagrant ssh' when executed as root
2024-03-04 23:42:40 -05:00
a31bf233dc
Slight message tweaks in forward-ssh.sh script 2023-12-09 13:16:46 -05:00
60fafed9cd
Update forward-ssh.sh script for Swarm support
- Address limitations in Swarm with loopback binding
- Ensure compatibility with localhost DNS wildcard A record
- Enable port forwarding on 80 and 443 using VM IP for Swarm compatibility
- Retain 8443:localhost:8443 for non-Swarm setups
2023-12-09 13:04:07 -05:00
2c00858590
Update README.md 2023-11-18 17:37:27 -05:00
be80681485
Add multi-machine support to forward-ssh.sh
- Detects multiple private keys
- Adds validation for all discovered keys
- Defaults to "default" machine, with override via the first parameter
2023-11-05 21:37:33 -05:00
a2e60972c7
Comply with linting on proxy setup 2023-11-05 21:34:19 -05:00
598359854f
Update proxy role to comply with linting 2023-11-03 00:47:06 -04:00
ef812c1877
Add copyright notice on forward-ssh.sh 2023-11-03 00:12:12 -04:00
385e60aee5
Update proxy playbook 2023-11-02 23:29:54 -04:00
5633468f41
Fix linting issues on Docker role 2023-10-22 13:48:20 -04:00
7f91b24adb
Add Debian/Official Docker repo toggle
- Default docker_official toggle to false (for now)
- Preempt MariaDB restart before container restarts
- Start containers in a handler
2023-10-22 11:33:05 -04:00
5b09029239
Update base role to pass linting 2023-10-20 21:30:25 -04:00
7adb5f10e9
Update Gitea role for docker_compose_deploy
- Add MariaDB to dev playbook
- Set Git user in "users:"
- Define Gitea external compose project
- Forward SSH port in forwarding script
- Create user groups with system users
- Install python3-pymysql for Ansible
- Strip old Gitea deployment methods
- Bind MariaDB to docker0 for Docker access
2023-10-20 15:41:44 -04:00
c3b4321667
Add Gitea dev playbook and host_vars 2023-10-19 16:40:34 -04:00
d05c5d3086
Slight tweaks on Ansible output 2023-10-19 16:36:05 -04:00
ac412f16ef
Simplify the "Import GPG keys" loop 2023-10-19 14:09:10 -04:00
2354a8fb8c
Verify successful GPG imports 2023-10-19 13:37:35 -04:00
251a7c0dd5
Import PGP key and verify git commits 2023-10-19 02:56:36 -04:00
1d8ae8a0b6
Install ntpsec 2023-10-19 01:27:31 -04:00
6b2feaee5e
Hide docker-compose secrets from diff output 2023-10-18 23:03:52 -04:00
31e0538b84
Add locale configuration tasks to base role 2023-10-18 16:32:09 -04:00
a65c4b9cf6
Handle Ansible undefined loop variable
- Default docker_compose_deploy to empty list if undefined
- Add conditional check to avoid looping through an empty list
2023-10-10 00:14:52 -04:00
7ee6e4810d
Convert booleans to lowercase 2023-10-10 00:00:00 -04:00
87aa7ecf8b
Add external compose support in the docker role
- Use ansible.posix.synchronize for compose.yml
- Set fact for compose service restarts
- Introduce plain Docker dev host
- Optionally verify repos via GPG before sync
- Hide docker_repos_path in .folder
- Tweak .env for conciseness
- Add --diff to Ansible in Vagrantfile
- Clean output with loop_control
- Embed GPG in base role
2023-10-09 23:47:49 -04:00
0377a5e642
Add option for private OCI registry auth 2023-09-29 22:18:59 -04:00
2e02efcbb7
Add Makefile, roles_path, and SSH tunnel variable 2023-09-26 21:14:06 -04:00
8fed63792b
Ask permission for starting vagrant SSH tunnels 2023-09-16 00:04:58 -04:00
2c4fcbacc3
Introduce forward-ssh.sh method & reorganize
- Abandoned update-hosts.sh in favor of loopback SSH forwarding
- Adopted *.local.krislamo.org as a wildcard loopback domain
- Bound Traefik to ports 443/80 on Dockerbox dev
- Removed outdated Gitea config from Dockerbox
- Relocated production playbooks to a new directory
2023-09-15 23:46:45 -04:00
b81372c07a
Fix the Vagrantfile for Github runners 2023-08-30 19:45:42 -04:00
9b5be29a1a
Update Vagrantfile to use external settings 2023-08-21 18:46:47 -04:00
ef5aacdbbd
No deploy keys without compose deploy variable 2023-07-21 23:52:18 -04:00
a635c7aa48
Add option to deploy external docker-compose stack 2023-07-20 03:51:44 -04:00
56aee460ad
Limit Github actions to specific branches 2023-07-20 00:33:42 -04:00
027ba46f6b
Add Github actions and remove old ansible stuff 2023-07-08 23:43:52 -04:00
48216db8f9
Updated Nextcloud settings and added cron job 2023-06-18 23:52:10 -04:00
fa1dc4acb7
Fix WireGuard firewall rule 2023-06-15 03:09:13 -04:00
228cd5795b
Config adjustments for Jellyfin/Samba deployment
- Ignored .vscode
- Added firewall exclusion option
- Allowed guest access in Samba
2023-06-09 22:26:47 -04:00
74a559f1f6
Update mediaserver playbook and fix Wireguard task 2023-06-08 03:47:54 -04:00
4c2a1550c4
Adding samba and general user management 2023-06-07 02:12:17 -04:00
f02cf7b0cc
Refactor docker playbook
- Removed copyright notice
- Variablize 'hosts' value in the playbook
- Install Jenkins agent before running Docker role
2023-05-08 16:26:16 -04:00
9142254a57
Improvements for ansible-linting 2023-05-04 01:44:18 -04:00
dfd93dd5f8
Updated Ansible tasks to FQCN format 2023-05-03 23:42:55 -04:00
81d2ea447a
Add mediaserver, rm .gitignore, FQCN, Jellyfin
- Added development "mediaserver" playbook for testing
- rm .gitignore in roles dir since no external ansible roles are used
- Update a part of the base role to use FQCN for linting
- Added "jellyfin" role to install Jellyfin with docker-compose
- Updated Traefik to use the loopback for default web entry points
- Simplified Traefik docker-compose vars, Ansible sets defaults
2023-04-26 02:26:50 -04:00
9512212b84
Refactor Traefik deploy: docker-compose + systemd
- Replace docker_container ansible with new setup
- Add option to disable HTTPS for alternate reverse proxy use
2023-04-21 03:04:53 -04:00
c67a39982e
Option to enable websockets for the noVNC console 2022-12-06 00:15:10 -05:00
f68f57d0cf
ROOT_URL should have HTTPS for the clone URL 2022-09-18 15:21:16 -04:00
b9f9b0bf3c
Update TLS settings in nginx proxy 2022-08-27 18:56:12 -04:00
4f4a341b05
Add client_max_body_size for Nextcloud 2022-08-19 01:27:55 -04:00
cab6ab2d8e
Strip auth header and update external config 2022-08-19 00:51:05 -04:00
95f54b7f0a
Add Traefik toggles 2022-08-18 23:32:37 -04:00
7522c333da
Disable Traefik LE resolver and HSTS 2022-08-18 21:53:38 -04:00
344b79e97f
Add base domain to the wildcard certificate 2022-08-17 02:17:36 -04:00
e4fed78193
Remove basic auth on static nginx sites 2022-08-17 01:40:11 -04:00
85a6c3894a
Add basic auth and ignore backend SSL errors 2022-08-17 01:15:15 -04:00
7677bc25fa
Add WireGuard firewall rule 2022-08-13 00:19:24 -04:00
b255680a7a
Use host MariaDB in Gitea container 2022-08-11 21:04:07 -04:00
9eefad0e87
Install Fail2ban IP allow list 2022-06-28 23:43:58 -04:00
8362230eb4
Add nginx proxy server 2022-06-27 20:21:25 -04:00
82df91305a
Install aggressive Fail2ban jail for SSH 2022-06-18 19:47:02 -04:00
dd9f84d498
Create initial log files for fail2ban 2022-06-07 00:25:47 -04:00
b52ccabd22
Add Fail2ban to Gitea and Bitwarden 2022-05-28 02:31:41 -04:00
eccd6b7874
Add reverse proxy settings for Gitea and Bitwarden 2022-05-28 00:18:15 -04:00
3a92921932
Minor cleanup 2022-05-27 23:14:06 -04:00
330f2b5a91
Add X-Forwarded-For proxy header 2022-05-27 22:33:35 -04:00
45465ad26b
Add the ufw firewall 2022-05-27 16:29:27 -04:00
d7838563a1
Gitea SSH container passthrough 2022-05-27 02:28:51 -04:00
03a57d2531
Only create LE directory if production is true 2022-05-27 00:06:09 -04:00
e346180b13
Add Bitwarden systemd service 2022-05-27 00:03:49 -04:00
be6e1596c5
Rehaul Gitea role for compose and PostgreSQL 2022-05-27 00:02:45 -04:00
dc520a09e9
Add generic docker-compose systemd service 2022-05-26 23:50:14 -04:00
c0be314268
Add PostgreSQL server role 2022-05-26 23:49:06 -04:00
9aca035f2d
Redirect HTTP to HTTPS 2022-05-26 23:32:25 -04:00
209ff57a4a
Determine wildcard cert paths and tidy nginx role 2022-05-23 22:33:17 -04:00
9a4aece442
Use DNS-01 on Cloudflare for wildcard LE certs 2022-05-23 03:32:56 -04:00
acd2cefb1e
Setup nginx reverse proxy 2022-05-22 00:19:56 -04:00
cd11567164
Fix broken Bitwarden provision 2022-05-19 23:19:09 -04:00
1c321f6ef7
Use Debian repositories for Docker 2022-05-19 21:06:34 -04:00
116 changed files with 2110 additions and 717 deletions

40
.github/workflows/vagrant.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: homelab-ci
on:
push:
branches:
- github_actions
# - main
# - testing
jobs:
homelab-ci:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Cache Vagrant boxes
uses: actions/cache@v3
with:
path: ~/.vagrant.d/boxes
key: ${{ runner.os }}-vagrant-${{ hashFiles('Vagrantfile') }}
restore-keys: |
${{ runner.os }}-vagrant-
- name: Install Ansible
run: brew install ansible@7
- name: Software Versions
run: |
printf "VirtualBox "
vboxmanage --version
vagrant --version
export PATH="/usr/local/opt/ansible@7/bin:$PATH"
ansible --version
- name: Vagrant Up with Dockerbox Playbook
run: |
export PATH="/usr/local/opt/ansible@7/bin:$PATH"
PLAYBOOK=dockerbox vagrant up
vagrant ssh -c "docker ps"

12
.gitignore vendored
View File

@ -1,12 +1,4 @@
.vagrant
.playbook .playbook
/*.yml .vagrant*
/*.yaml .vscode
!backup.yml
!moxie.yml
!docker.yml
!dockerbox.yml
!hypervisor.yml
!minecraft.yml
!unifi.yml
/environments/ /environments/

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
.PHONY: clean install
all: install
install:
vagrant up --no-destroy-on-error
sudo ./forward-ssh.sh
clean:
vagrant destroy -f && rm -rf .vagrant

View File

@ -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
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, version 3 of the License.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

49
Vagrantfile vendored
View File

@ -1,42 +1,41 @@
# -*- mode: ruby -*- # -*- mode: ruby -*-
# vi: set ft=ruby : # vi: set ft=ruby :
SSH_FORWARD=ENV["SSH_FORWARD"] require 'yaml'
if !(SSH_FORWARD == "true") settings_path = '.vagrant.yml'
SSH_FORWARD = false settings = {}
if File.exist?(settings_path)
settings = YAML.load_file(settings_path)
end end
PLAYBOOK=ENV["PLAYBOOK"] VAGRANT_BOX = settings['VAGRANT_BOX'] || 'debian/bookworm64'
if !PLAYBOOK VAGRANT_CPUS = settings['VAGRANT_CPUS'] || 2
if File.exist?('.playbook') VAGRANT_MEM = settings['VAGRANT_MEM'] || 2048
PLAYBOOK = IO.read('.playbook').split("\n")[0] SSH_FORWARD = settings['SSH_FORWARD'] || false
end
if !PLAYBOOK || PLAYBOOK.empty? # Default to shell environment variable: PLAYBOOK (priority #1)
PLAYBOOK = "\nERROR: Set env PLAYBOOK" PLAYBOOK=ENV["PLAYBOOK"]
end if !PLAYBOOK || PLAYBOOK.empty?
else # PLAYBOOK setting in .vagrant.yml (priority #2)
File.write(".playbook", PLAYBOOK) PLAYBOOK = settings['PLAYBOOK'] || 'default'
end end
Vagrant.configure("2") do |config| Vagrant.configure("2") do |config|
config.vm.box = "debian/bullseye64" config.vm.box = VAGRANT_BOX
config.vm.network "private_network", type: "dhcp" config.vm.network "private_network", type: "dhcp"
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder "./scratch", "/vagrant/scratch"
config.ssh.forward_agent = SSH_FORWARD config.ssh.forward_agent = SSH_FORWARD
# Machine Name # Libvrit provider
config.vm.define :moxie do |moxie| #
end
# Disable Machine Name Prefix
config.vm.provider :libvirt do |libvirt| config.vm.provider :libvirt do |libvirt|
libvirt.default_prefix = "" libvirt.cpus = VAGRANT_CPUS
libvirt.memory = VAGRANT_MEM
end end
config.vm.provider "virtualbox" do |vbox| # Virtualbox provider
vbox.memory = 4096 config.vm.provider :virtualbox do |vbox|
vbox.cpus = VAGRANT_CPUS
vbox.memory = VAGRANT_MEM
end end
# Provision with Ansible # Provision with Ansible
@ -44,6 +43,6 @@ Vagrant.configure("2") do |config|
ENV['ANSIBLE_ROLES_PATH'] = File.dirname(__FILE__) + "/roles" ENV['ANSIBLE_ROLES_PATH'] = File.dirname(__FILE__) + "/roles"
ansible.compatibility_mode = "2.0" ansible.compatibility_mode = "2.0"
ansible.playbook = "dev/" + PLAYBOOK + ".yml" ansible.playbook = "dev/" + PLAYBOOK + ".yml"
ansible.raw_arguments = ["--diff"]
end end
end end

View File

@ -1,3 +1,7 @@
[defaults] [defaults]
inventory = ./environments/development inventory = ./environments/development
interpreter_python = /usr/bin/python3 interpreter_python = /usr/bin/python3
roles_path = ./roles
[connection]
pipelining = true

4
dev/default.yml Normal file
View File

@ -0,0 +1,4 @@
- name: Install 'default' aka nothing
hosts: all
become: true
tasks: []

8
dev/docker.yml Normal file
View File

@ -0,0 +1,8 @@
- name: Install Docker Server
hosts: all
become: true
vars_files:
- host_vars/docker.yml
roles:
- base
- docker

View File

@ -1,4 +1,4 @@
- name: Install Docker Box Server - name: Install Dockerbox Server
hosts: all hosts: all
become: true become: true
vars_files: vars_files:
@ -6,9 +6,7 @@
roles: roles:
- base - base
- docker - docker
- mariadb
- traefik - traefik
- nextcloud - nextcloud
- gitea - proxy
- jenkins
- prometheus
- nginx

10
dev/gitea.yml Normal file
View File

@ -0,0 +1,10 @@
- name: Install Gitea Server
hosts: all
become: true
vars_files:
- host_vars/gitea.yml
roles:
- base
- docker
- mariadb
- gitea

View File

@ -9,14 +9,14 @@ docker_users:
# traefik # traefik
traefik_version: latest traefik_version: latest
traefik_dashboard: true traefik_dashboard: true
traefik_domain: traefik.vm.krislamo.org traefik_domain: traefik.local.krislamo.org
traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
#traefik_acme_email: realemail@example.com # Let's Encrypt settings #traefik_acme_email: realemail@example.com # Let's Encrypt settings
#traefik_production: true #traefik_production: true
# bitwarden # bitwarden
# Get Installation ID & Key at https://bitwarden.com/host/ # Get Installation ID & Key at https://bitwarden.com/host/
bitwarden_domain: vault.vm.krislamo.org bitwarden_domain: vault.local.krislamo.org
bitwarden_dbpass: password bitwarden_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

48
dev/host_vars/docker.yml Normal file
View File

@ -0,0 +1,48 @@
# base
allow_reboot: false
manage_network: false
# Import my GPG key for git signature verification
root_gpgkeys:
- name: kris@lamoureux.io
id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925
# docker
docker_users:
- vagrant
#docker_login_url: https://myregistry.example.com
#docker_login_user: myuser
#docker_login_pass: YOUR_PASSWD
docker_compose_env_nolog: false # dev only setting
docker_compose_deploy:
# Traefik
- name: traefik
url: https://github.com/krislamo/traefik
version: 31ee724feebc1d5f91cb17ffd6892c352537f194
enabled: true
accept_newhostkey: true # Consider verifying manually instead
trusted_keys:
- FBF673CEEC030F8AECA814E73EDA9C3441EDA925
env:
ENABLE: true
# Traefik 2 (no other external compose to test currently)
- name: traefik2
url: https://github.com/krislamo/traefik
version: 31ee724feebc1d5f91cb17ffd6892c352537f194
enabled: true
accept_newhostkey: true # Consider verifying manually instead
trusted_keys:
- FBF673CEEC030F8AECA814E73EDA9C3441EDA925
env:
ENABLE: true
VERSION: "2.10"
DOMAIN: traefik2.local.krislamo.org
NAME: traefik2
ROUTER: traefik2
NETWORK: traefik2
WEB_PORT: 127.0.0.1:8000:80
WEBSECURE_PORT: 127.0.0.1:4443:443
LOCAL_PORT: 127.0.0.1:8444:8443

View File

@ -2,47 +2,47 @@
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: FBF673CEEC030F8AECA814E73EDA9C3441EDA925
# 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.vm.krislamo.org
traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
#traefik_acme_email: realemail@example.com # Let's Encrypt settings
#traefik_production: true
# nextcloud # nextcloud
nextcloud_version: stable nextcloud:
nextcloud_admin: admin DOMAIN: cloud.local.krislamo.org
nextcloud_pass: password DB_PASSWD: password
nextcloud_domain: cloud.vm.krislamo.org ADMIN_PASSWD: password
nextcloud_dbversion: latest
nextcloud_dbpass: password
# gitea
gitea_domain: git.vm.krislamo.org
gitea_version: 1
gitea_dbversion: latest
gitea_dbpass: password
# jenkins
jenkins_version: lts
jenkins_domain: jenkins.vm.krislamo.org
# prometheus (includes grafana)
prom_version: latest
prom_domain: prom.vm.krislamo.org
grafana_version: latest
grafana_domain: grafana.vm.krislamo.org
prom_targets: "['10.0.2.15:9100']"
# nginx
nginx_domain: nginx.vm.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

50
dev/host_vars/gitea.yml Normal file
View File

@ -0,0 +1,50 @@
# base
allow_reboot: false
manage_network: false
users:
git:
uid: 1001
gid: 1001
home: true
system: true
# Import my GPG key for git signature verification
root_gpgkeys:
- name: kris@lamoureux.io
id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925
# docker
docker_official: true # docker's apt repos
docker_users:
- vagrant
docker_compose_env_nolog: false # dev only setting
docker_compose_deploy:
# Traefik
- name: traefik
url: https://github.com/krislamo/traefik
version: 398eb48d311db78b86abf783f903af4a1658d773
enabled: true
accept_newhostkey: true
trusted_keys:
- FBF673CEEC030F8AECA814E73EDA9C3441EDA925
env:
ENABLE: true
# Gitea
- name: gitea
url: https://github.com/krislamo/gitea
version: b0ce66f6a1ab074172eed79eeeb36d7e9011ef8f
enabled: true
trusted_keys:
- FBF673CEEC030F8AECA814E73EDA9C3441EDA925
env:
USER_UID: "{{ users.git.uid }}"
USER_GID: "{{ users.git.gid }}"
DB_PASSWD: "{{ gitea.DB_PASSWD }}"
# gitea
gitea:
DB_NAME: gitea
DB_USER: gitea
DB_PASSWD: password

View File

@ -0,0 +1,61 @@
base_domain: local.krislamo.org
# base
allow_reboot: false
manage_network: false
users:
jellyfin:
uid: 1001
gid: 1001
shell: /usr/sbin/nologin
home: false
system: true
samba:
users:
- name: jellyfin
password: jellyfin
shares:
- name: jellyfin
path: /srv/jellyfin
owner: jellyfin
group: jellyfin
valid_users: jellyfin
firewall:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
# proxy
proxy:
#production: true
dns_cloudflare:
opts: --test-cert
#email: realemail@example.com
#api_token: CLOUDFLARE_DNS01_API_TOKEN
wildcard_domains:
- "{{ base_domain }}"
servers:
- domain: "{{ traefik_domain }}"
proxy_pass: "http://127.0.0.1:8000"
- domain: "{{ jellyfin_domain }}"
proxy_pass: "http://127.0.0.1:8000"
# docker
docker_users:
- vagrant
# traefik
traefik_version: latest
traefik_dashboard: true
traefik_domain: "traefik.{{ base_domain }}"
traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
#traefik_acme_email: realemail@example.com # Let's Encrypt settings
#traefik_production: true
traefik_http_only: true # if behind reverse-proxy
# jellyfin
jellyfin_domain: "jellyfin.{{ base_domain }}"
jellyfin_version: latest
jellyfin_media: /srv/jellyfin

View File

@ -5,14 +5,14 @@ docker_users:
# traefik # traefik
traefik_version: latest traefik_version: latest
traefik_dashboard: true traefik_dashboard: true
traefik_domain: traefik.vm.krislamo.org traefik_domain: traefik.local.krislamo.org
traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
# container settings # container settings
nextcloud_version: stable nextcloud_version: stable
nextcloud_admin: admin nextcloud_admin: admin
nextcloud_pass: password nextcloud_pass: password
nextcloud_domain: cloud.vm.krislamo.org nextcloud_domain: cloud.local.krislamo.org
# database settings # database settings
nextcloud_dbversion: latest nextcloud_dbversion: latest

View File

@ -9,13 +9,13 @@ docker_users:
# traefik # traefik
traefik_version: latest traefik_version: latest
traefik_dashboard: true traefik_dashboard: true
traefik_domain: traefik.vm.krislamo.org traefik_domain: traefik.local.krislamo.org
traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
#traefik_acme_email: realemail@example.com # Let's Encrypt settings #traefik_acme_email: realemail@example.com # Let's Encrypt settings
#traefik_production: true #traefik_production: true
# nginx # nginx
nginx_domain: nginx.vm.krislamo.org nginx_domain: nginx.local.krislamo.org
nginx_name: staticsite nginx_name: staticsite
nginx_repo_url: https://git.krislamo.org/kris/example-website/ nginx_repo_url: https://git.krislamo.org/kris/example-website/
nginx_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin nginx_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin

79
dev/host_vars/proxy.yml Normal file
View File

@ -0,0 +1,79 @@
base_domain: local.krislamo.org
# base
allow_reboot: false
manage_network: false
users:
git:
uid: 1001
gid: 1001
home: true
system: true
# Import my GPG key for git signature verification
root_gpgkeys:
- name: kris@lamoureux.io
id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925
# proxy
proxy:
#production: true
dns_cloudflare:
opts: --test-cert
#email: realemail@example.com
#api_token: CLOUDFLARE_DNS01_API_TOKEN
wildcard_domains:
- "{{ base_domain }}"
servers:
- domain: "{{ bitwarden_domain }}"
proxy_pass: "http://127.0.0.1"
- domain: "{{ gitea_domain }}"
proxy_pass: "http://127.0.0.1"
# docker
docker_official: true # docker's apt repos
docker_users:
- vagrant
docker_compose_env_nolog: false # dev only setting
docker_compose_deploy:
# Traefik
- name: traefik
url: https://github.com/krislamo/traefik
version: e97db75e2e214582fac5f5e495687ab5cdf855ad
path: docker-compose.web.yml
enabled: true
accept_newhostkey: true
trusted_keys:
- FBF673CEEC030F8AECA814E73EDA9C3441EDA925
env:
ENABLE: true
# Gitea
- name: gitea
url: https://github.com/krislamo/gitea
version: b0ce66f6a1ab074172eed79eeeb36d7e9011ef8f
enabled: true
trusted_keys:
- FBF673CEEC030F8AECA814E73EDA9C3441EDA925
env:
ENTRYPOINT: web
ENABLE_TLS: false
USER_UID: "{{ users.git.uid }}"
USER_GID: "{{ users.git.gid }}"
DB_PASSWD: "{{ gitea.DB_PASSWD }}"
# gitea
gitea_domain: "git.{{ base_domain }}"
gitea:
DB_NAME: gitea
DB_USER: gitea
DB_PASSWD: password
# bitwarden
# Get Installation ID & Key at https://bitwarden.com/host/
bitwarden_domain: "vault.{{ base_domain }}"
bitwarden_dbpass: password
bitwarden_install_id: 4ea840a3-532e-4cb6-a472-abd900728b23
bitwarden_install_key: 1yB3Z2gRI0KnnH90C6p
#bitwarden_prodution: true

View File

@ -9,14 +9,14 @@ docker_users:
# traefik # traefik
traefik_version: latest traefik_version: latest
traefik_dashboard: true traefik_dashboard: true
traefik_domain: traefik.vm.krislamo.org traefik_domain: traefik.local.krislamo.org
traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
#traefik_acme_email: realemail@example.com # Let's Encrypt settings #traefik_acme_email: realemail@example.com # Let's Encrypt settings
#traefik_production: true #traefik_production: true
# container settings # container settings
wordpress_version: latest wordpress_version: latest
wordpress_domain: wordpress.vm.krislamo.org wordpress_domain: wordpress.local.krislamo.org
wordpress_multisite: true wordpress_multisite: true
# database settings # database settings

11
dev/mediaserver.yml Normal file
View File

@ -0,0 +1,11 @@
- name: Install Media Server
hosts: all
become: true
vars_files:
- host_vars/mediaserver.yml
roles:
- base
- proxy
- docker
- traefik
- jellyfin

12
dev/proxy.yml Normal file
View File

@ -0,0 +1,12 @@
- name: Install Proxy Server
hosts: all
become: true
vars_files:
- host_vars/proxy.yml
roles:
- base
- proxy
- docker
- mariadb
- gitea
- bitwarden

View File

@ -1,21 +0,0 @@
# Copyright (C) 2020 Kris Lamoureux
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
- name: Install Docker Server
hosts: dockerhosts
become: true
roles:
- base
- docker
- jenkins

View File

@ -1,26 +0,0 @@
# Copyright (C) 2020 Kris Lamoureux
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
- name: Install Docker Box Server
hosts: dockerhosts
become: true
roles:
- base
- docker
- traefik
- nextcloud
- gitea
- jenkins
- prometheus
- nginx

125
forward-ssh.sh Executable file
View File

@ -0,0 +1,125 @@
#!/bin/bash
# Finds the SSH private key under ./.vagrant and connects to
# the Vagrant box, port forwarding localhost ports: 8443, 443, 80, 22
#
# Download the latest script:
# https://git.krislamo.org/kris/homelab/raw/branch/main/forward-ssh.sh
#
# Copyright (C) 2023 Kris Lamoureux
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Root check
if [ "$EUID" -ne 0 ]; then
echo "[ERROR]: Please run this script as root"
exit 1
fi
# Clean environment
unset PRIVATE_KEY
unset HOST_IP
unset MATCH_PATTERN
unset PKILL_ANSWER
# Function to create the SSH tunnel
function ssh_connect {
read -rp "Start a new vagrant SSH tunnel? [y/N] " PSTART_ANSWER
echo
case "$PSTART_ANSWER" in
[yY])
printf "[INFO]: Starting new vagrant SSH tunnel on PID "
sudo -u "$USER" ssh -fNT -i "$PRIVATE_KEY" \
-L 22:localhost:22 \
-L 80:"$HOST_IP":80 \
-L 443:"$HOST_IP":443 \
-L 8443:localhost:8443 \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
vagrant@"$HOST_IP" 2>/dev/null
sleep 2
pgrep -f "$MATCH_PATTERN"
;;
*)
echo "[INFO]: Declined to start a new vagrant SSH tunnel"
exit 0
;;
esac
}
# Check for valid PRIVATE_KEY location
PRIVATE_KEY="$(find .vagrant -name "private_key" 2>/dev/null | sort)"
# Single vagrant machine or multiple
if [ "$(echo "$PRIVATE_KEY" | wc -l)" -gt 1 ]; then
while IFS= read -r KEYFILE; do
if ! ssh-keygen -l -f "$KEYFILE" &>/dev/null; then
echo "[ERROR]: The SSH key '$KEYFILE' is not valid. Are your virtual machines running?"
exit 1
fi
echo "[CHECK]: Valid key at $KEYFILE"
done < <(echo "$PRIVATE_KEY")
PRIVATE_KEY="$(echo "$PRIVATE_KEY" | grep -m1 "${1:-default}")"
elif ! ssh-keygen -l -f "$PRIVATE_KEY" &>/dev/null; then
echo "[ERROR]: The SSH key '$PRIVATE_KEY' is not valid. Is your virtual machine running?"
exit 1
else
echo "[CHECK]: Valid key at $PRIVATE_KEY"
fi
# Grab first IP or use whatever HOST_IP_FIELD is set to and check that the guest is up
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
if ! ping -c 1 "$HOST_IP" &>/dev/null; then
echo "[ERROR]: Cannot ping the host IP '$HOST_IP'"
exit 1
fi
echo "[CHECK]: Host at $HOST_IP (${1:-default}) is up"
# Pattern for matching processes running
MATCH_PATTERN="ssh -fNT -i ${PRIVATE_KEY}.*vagrant@"
# Check amount of processes that match the pattern
if [ "$(pgrep -afc "$MATCH_PATTERN")" -eq 0 ]; then
ssh_connect
else
# Processes found, so prompt to kill remaining ones then start tunnel
printf "\n[WARNING]: Found processes running:\n"
pgrep -fa "$MATCH_PATTERN"
printf '\n'
read -rp "Would you like to kill these processes? [y/N] " PKILL_ANSWER
echo
case "$PKILL_ANSWER" in
[yY])
echo "[WARNING]: Killing old vagrant SSH tunnel(s): "
pgrep -f "$MATCH_PATTERN" | tee >(xargs kill -15)
echo
if [ "$(pgrep -afc "$MATCH_PATTERN")" -eq 0 ]; then
ssh_connect
else
echo "[ERROR]: Unable to kill processes:"
pgrep -f "$MATCH_PATTERN"
exit 1
fi
;;
*)
echo "[INFO]: Declined to kill existing processes"
exit 0
;;
esac
fi

8
playbooks/docker.yml Normal file
View File

@ -0,0 +1,8 @@
- name: Install Docker Server
hosts: "{{ PLAYBOOK_HOST | default('none') }}"
become: true
roles:
- base
- jenkins
- proxy
- docker

11
playbooks/dockerbox.yml Normal file
View File

@ -0,0 +1,11 @@
- name: Install Dockerbox Server
hosts: "{{ PLAYBOOK_HOST | default('none') }}"
become: true
roles:
- base
- docker
- traefik
- nextcloud
- jenkins
- prometheus
- nginx

10
playbooks/mediaserver.yml Normal file
View File

@ -0,0 +1,10 @@
- name: Install Media Server
hosts: "{{ PLAYBOOK_HOST | default('none') }}"
become: true
roles:
- base
- jenkins
- proxy
- docker
- traefik
- jellyfin

11
playbooks/proxy.yml Normal file
View File

@ -0,0 +1,11 @@
- name: Install Proxy Server
hosts: proxyhosts
become: true
roles:
- base
- jenkins
- mariadb
- proxy
- docker
- gitea
- bitwarden

17
roles/.gitignore vendored
View File

@ -1,17 +0,0 @@
/*
!.gitignore
!requirements.yml
!base*/
!bitwarden*/
!docker*/
!gitea*/
!jenkins*/
!libvirt*/
!minecraft*/
!nextcloud*/
!nginx*/
!prometheus*/
!rsnapshot*/
!traefik*/
!unifi*/
!wordpress*/

View File

@ -1,8 +1,11 @@
allow_reboot: true
manage_firewall: true
manage_network: false manage_network: false
network_type: static network_type: static
allow_reboot: true locale_default: en_US.UTF-8
packages: packages:
- apache2-utils
- cryptsetup - cryptsetup
- curl - curl
- dnsutils - dnsutils

View File

@ -1 +0,0 @@
deb http://deb.debian.org/debian buster-backports main

View File

@ -1,12 +1,34 @@
- name: Reboot host - name: Reboot host
reboot: ansible.builtin.reboot:
msg: "Reboot initiated by Ansible" msg: "Reboot initiated by Ansible"
connect_timeout: 5 connect_timeout: 5
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
service: ansible.builtin.service:
name: wg-quick@wg0 name: wg-quick@wg0
state: restarted state: restarted
listen: restart_wireguard listen: restart_wireguard
- name: Restart Fail2ban
ansible.builtin.service:
name: fail2ban
state: restarted
listen: restart_fail2ban
- name: Restart ddclient
ansible.builtin.service:
name: ddclient
state: restarted
listen: restart_ddclient
- name: Restart Samba
ansible.builtin.service:
name: smbd
state: restarted
listen: restart_samba

View File

@ -1,15 +1,5 @@
- name: 'Install Ansible dependency: python3-apt' - name: Create Ansible's temporary remote directory
shell: 'apt-get update && apt-get install python3-apt -y' ansible.builtin.file:
args: path: "~/.ansible/tmp"
creates: /usr/lib/python3/dist-packages/apt state: directory
warn: false mode: "700"
- name: Install additional Ansible dependencies
apt:
name: "{{ item }}"
state: present
force_apt_get: true
update_cache: true
loop:
- aptitude
- python3-docker

View File

@ -1,22 +1,17 @@
- name: Install ddclient - name: Install ddclient
apt: ansible.builtin.apt:
name: ddclient name: ddclient
state: present state: present
- name: Install ddclient settings - name: Install ddclient settings
template: ansible.builtin.template:
src: ddclient.conf.j2 src: ddclient.conf.j2
dest: /etc/ddclient.conf dest: /etc/ddclient.conf
mode: "600"
register: ddclient_settings register: ddclient_settings
- name: Start ddclient and enable on boot - name: Start ddclient and enable on boot
service: ansible.builtin.service:
name: ddclient name: ddclient
state: started state: started
enabled: true enabled: true
- name: Restart ddclient
service:
name: ddclient
state: restarted
when: ddclient_settings.changed

View File

@ -0,0 +1,48 @@
- name: Install the Uncomplicated Firewall
ansible.builtin.apt:
name: ufw
state: present
- name: Install Fail2ban
ansible.builtin.apt:
name: fail2ban
state: present
- name: Deny incoming traffic by default
community.general.ufw:
default: deny
direction: incoming
- name: Allow outgoing traffic by default
community.general.ufw:
default: allow
direction: outgoing
- name: Allow OpenSSH with rate limiting
community.general.ufw:
name: ssh
rule: limit
- name: Remove Fail2ban defaults-debian.conf
ansible.builtin.file:
path: /etc/fail2ban/jail.d/defaults-debian.conf
state: absent
- name: Install OpenSSH's Fail2ban jail
ansible.builtin.template:
src: fail2ban-ssh.conf.j2
dest: /etc/fail2ban/jail.d/sshd.conf
mode: "640"
notify: restart_fail2ban
- name: Install Fail2ban IP allow list
ansible.builtin.template:
src: fail2ban-allowlist.conf.j2
dest: /etc/fail2ban/jail.d/allowlist.conf
mode: "640"
when: fail2ban_ignoreip is defined
notify: restart_fail2ban
- name: Enable firewall
community.general.ufw:
state: enabled

View File

@ -1,5 +1,5 @@
- name: Install msmtp - name: Install msmtp
apt: ansible.builtin.apt:
name: "{{ item }}" name: "{{ item }}"
state: present state: present
loop: loop:
@ -8,12 +8,13 @@
- mailutils - mailutils
- name: Install msmtp configuration - name: Install msmtp configuration
template: ansible.builtin.template:
src: msmtprc.j2 src: msmtprc.j2
dest: /root/.msmtprc dest: /root/.msmtprc
mode: 0700 mode: "600"
- name: Install /etc/aliases - name: Install /etc/aliases
copy: ansible.builtin.copy:
dest: /etc/aliases dest: /etc/aliases
content: "root: {{ mail.rootalias }}" content: "root: {{ mail.rootalias }}"
mode: "644"

View File

@ -1,21 +1,37 @@
- import_tasks: ansible.yml - name: Import Ansible tasks
ansible.builtin.import_tasks: ansible.yml
tags: ansible tags: ansible
- import_tasks: system.yml - name: Import System tasks
ansible.builtin.import_tasks: system.yml
tags: system tags: system
- import_tasks: network.yml - name: Import Firewall tasks
ansible.builtin.import_tasks: firewall.yml
tags: firewall
when: manage_firewall
- name: Import Network tasks
ansible.builtin.import_tasks: network.yml
tags: network tags: network
when: manage_network when: manage_network
- import_tasks: mail.yml - name: Import Mail tasks
ansible.builtin.import_tasks: mail.yml
tags: mail tags: mail
when: mail is defined when: mail is defined
- import_tasks: ddclient.yml - name: Import ddclient tasks
ansible.builtin.import_tasks: ddclient.yml
tags: ddclient tags: ddclient
when: ddclient is defined when: ddclient is defined
- import_tasks: wireguard.yml - name: Import WireGuard tasks
ansible.builtin.import_tasks: wireguard.yml
tags: wireguard tags: wireguard
when: wireguard is defined when: wireguard is defined
- name: Import Samba tasks
ansible.builtin.import_tasks: samba.yml
tags: samba
when: samba is defined

View File

@ -1,5 +1,5 @@
- name: Install network interfaces file - name: Install network interfaces file
copy: ansible.builtin.copy:
src: network-interfaces.cfg src: network-interfaces.cfg
dest: /etc/network/interfaces dest: /etc/network/interfaces
owner: root owner: root
@ -7,13 +7,9 @@
mode: '0644' mode: '0644'
- name: Install network interfaces - name: Install network interfaces
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: "400"
loop: "{{ interfaces }}" loop: "{{ interfaces }}"
notify: reboot_host notify: reboot_host
- name: Install bridge utilities
apt:
name: bridge-utils
state: present

View File

@ -0,0 +1,46 @@
- name: Install Samba
ansible.builtin.apt:
name: samba
state: present
- name: Create Samba users
ansible.builtin.command: "smbpasswd -a {{ item.name }}"
args:
stdin: "{{ item.password }}\n{{ item.password }}"
loop: "{{ samba.users }}"
loop_control:
label: "{{ item.name }}"
register: samba_users
changed_when: "'Added user' in samba_users.stdout"
- name: Ensure share directories exist
ansible.builtin.file:
path: "{{ item.path }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
state: directory
mode: "755"
loop: "{{ samba.shares }}"
- name: Configure Samba shares
ansible.builtin.template:
src: smb.conf.j2
dest: /etc/samba/smb.conf
mode: "644"
notify: restart_samba
- name: Start smbd and enable on boot
ansible.builtin.service:
name: smbd
state: started
enabled: true
- name: Allow SMB connections
community.general.ufw:
rule: allow
port: 445
proto: tcp
from: "{{ item }}"
state: enabled
loop: "{{ samba.firewall }}"
when: manage_firewall

View File

@ -1,23 +1,105 @@
- name: Install useful software - name: Install useful software
apt: ansible.builtin.apt:
name: "{{ packages }}" name: "{{ packages }}"
state: present state: present
update_cache: true update_cache: true
- name: Install GPG
ansible.builtin.apt:
name: gpg
state: present
- name: Check for existing GPG keys
ansible.builtin.command: "gpg --list-keys {{ item.id }} 2>/dev/null"
register: gpg_check
loop: "{{ root_gpgkeys }}"
failed_when: false
changed_when: false
when: root_gpgkeys is defined
- name: Import GPG keys
ansible.builtin.command:
"gpg --keyserver {{ item.item.server | default('keys.openpgp.org') }} --recv-key {{ item.item.id }}"
register: gpg_check_import
loop: "{{ gpg_check.results }}"
loop_control:
label: "{{ item.item }}"
changed_when: false
when: root_gpgkeys is defined and item.rc != 0
- name: Check GPG key imports
ansible.builtin.fail:
msg: "{{ item.stderr }}"
loop: "{{ gpg_check_import.results }}"
loop_control:
label: "{{ item.item.item }}"
when: root_gpgkeys is defined and (not item.skipped | default(false)) and ('imported' not in item.stderr)
- name: Install NTPsec
ansible.builtin.apt:
name: ntpsec
state: present
- name: Install locales
ansible.builtin.apt:
name: locales
state: present
- name: Generate locale
community.general.locale_gen:
name: "{{ locale_default }}"
state: present
notify: reconfigure_locales
- name: Set the default locale
ansible.builtin.lineinfile:
path: /etc/default/locale
regexp: "^LANG="
line: "LANG={{ locale_default }}"
- name: Manage root authorized_keys - name: Manage root authorized_keys
template: ansible.builtin.template:
src: authorized_keys.j2 src: authorized_keys.j2
dest: /root/.ssh/authorized_keys dest: /root/.ssh/authorized_keys
mode: "400"
when: authorized_keys is defined when: authorized_keys is defined
- name: Install btrfs-tools - name: Create system user groups
apt: ansible.builtin.group:
name: btrfs-tools name: "{{ item.key }}"
gid: "{{ item.value.gid }}"
state: present state: present
when: btrfs_support is defined and btrfs_support | bool == true loop: "{{ users | dict2items }}"
loop_control:
label: "{{ item.key }}"
when: users is defined
- name: Create system users
ansible.builtin.user:
name: "{{ item.key }}"
state: present
uid: "{{ item.value.uid }}"
group: "{{ item.value.gid }}"
shell: "{{ item.value.shell | default('/bin/bash') }}"
create_home: "{{ item.value.home | default(false) }}"
system: "{{ item.value.system | default(false) }}"
loop: "{{ users | dict2items }}"
loop_control:
label: "{{ item.key }}"
when: users is defined
- name: Set authorized_keys for system users
ansible.posix.authorized_key:
user: "{{ item.key }}"
key: "{{ item.value.key }}"
state: present
loop: "{{ users | dict2items }}"
loop_control:
label: "{{ item.key }}"
when: users is defined and item.value.key is defined
- name: Manage filesystem mounts - name: Manage filesystem mounts
mount: ansible.posix.mount:
path: "{{ item.path }}" path: "{{ item.path }}"
src: "UUID={{ item.uuid }}" src: "UUID={{ item.uuid }}"
fstype: "{{ item.fstype }}" fstype: "{{ item.fstype }}"

View File

@ -1,51 +1,61 @@
# Copyright (C) 2021 Kris Lamoureux
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
- name: Add Debian Buster backports
copy:
src: buster-backports.list
dest: /etc/apt/sources.list.d/buster-backports.list
owner: root
group: root
mode: '0644'
- name: Install WireGuard - name: Install WireGuard
apt: ansible.builtin.apt:
name: wireguard name: wireguard
state: present state: present
update_cache: true update_cache: true
- name: Generate WireGuard keys - name: Generate WireGuard keys
shell: wg genkey | tee privatekey | wg pubkey > publickey ansible.builtin.shell: |
set -o pipefail
wg genkey | tee privatekey | wg pubkey > publickey
args: args:
chdir: /etc/wireguard/ chdir: /etc/wireguard/
creates: /etc/wireguard/privatekey creates: /etc/wireguard/privatekey
executable: /usr/bin/bash
- name: Grab WireGuard private key for configuration - name: Grab WireGuard private key for configuration
slurp: ansible.builtin.slurp:
src: /etc/wireguard/privatekey
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 src: /etc/wireguard/privatekey
register: wgkey register: wgkey
- name: Install WireGuard configuration - name: Install WireGuard configuration
template: ansible.builtin.template:
src: wireguard.j2 src: wireguard.j2
dest: /etc/wireguard/wg0.conf dest: /etc/wireguard/wg0.conf
notify: mode: "400"
- restart_wireguard notify: restart_wireguard
- name: Start WireGuard interface - name: Start WireGuard interface
service: ansible.builtin.service:
name: wg-quick@wg0 name: wg-quick@wg0
state: started state: started
enabled: true enabled: true
- name: Add WireGuard firewall rule
community.general.ufw:
rule: allow
port: "{{ wireguard.listenport }}"
proto: udp
when: wireguard.listenport is defined

View File

@ -0,0 +1,2 @@
[DEFAULT]
ignoreip = {% for host in fail2ban_ignoreip %}{{ host }}{% if not loop.last %} {% endif %}{% endfor %}

View File

@ -0,0 +1,3 @@
[sshd]
mode = aggressive
enabled = true

View File

@ -0,0 +1,28 @@
[global]
workgroup = WORKGROUP
server string = Samba Server %v
netbios name = {{ ansible_hostname }}
security = user
map to guest = bad user
dns proxy = no
{% for user in samba.users %}
smb encrypt = {{ 'mandatory' if user.encrypt | default(false) else 'disabled' }}
{% endfor %}
{% for share in samba.shares %}
[{{ share.name }}]
path = {{ share.path }}
browsable = yes
{% if share.guest_allow is defined and share.guest_allow %}
guest ok = yes
{% else %}
guest ok = no
{% endif %}
read only = {{ 'yes' if share.read_only | default(false) else 'no' }}
{% if share.valid_users is defined %}
valid users = {{ share.valid_users }}
{% endif %}
{% if share.force_user is defined %}
force user = {{ share.force_user }}
{% endif %}
{% endfor %}

View File

@ -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 %}

View File

@ -1,4 +1,8 @@
bitwarden_name: bitwarden bitwarden_name: bitwarden
bitwarden_root: "/opt/{{ bitwarden_name }}" bitwarden_root: "/var/lib/{{ bitwarden_name }}"
bitwarden_logs_identity: "{{ bitwarden_root }}/bwdata/logs/identity/Identity"
bitwarden_logs_identity_date: "{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}"
bitwarden_database: "{{ bitwarden_name }}"
bitwarden_realips: "172.16.0.0/12"
bitwarden_standalone: false bitwarden_standalone: false
bitwarden_production: false bitwarden_production: false

View File

@ -1,7 +1,28 @@
- name: Rebuild Bitwarden - name: Stop Bitwarden for rebuild
shell: "{{ bitwarden_root }}/bitwarden.sh rebuild" ansible.builtin.service:
name: "{{ bitwarden_name }}"
state: stopped
listen: rebuild_bitwarden listen: rebuild_bitwarden
- name: Start Bitwarden - name: Rebuild Bitwarden
shell: "{{ bitwarden_root }}/bitwarden.sh start" ansible.builtin.command: "{{ bitwarden_root }}/bitwarden.sh rebuild"
listen: start_bitwarden listen: rebuild_bitwarden
- name: Reload systemd manager configuration
ansible.builtin.systemd:
daemon_reload: true
listen: rebuild_bitwarden
- name: Start Bitwarden after rebuild
ansible.builtin.service:
name: "{{ bitwarden_name }}"
state: started
enabled: true
listen: rebuild_bitwarden
- name: Create Bitwarden's initial log file
ansible.builtin.file:
path: "{{ bitwarden_logs_identity }}/{{ bitwarden_logs_identity_date }}.txt"
state: touch
mode: "644"
listen: touch_bitwarden

View File

@ -1,76 +1,97 @@
- name: Install expect - name: Install expect
apt: ansible.builtin.apt:
name: expect name: expect
state: present state: present
- name: Create Bitwarden directory - name: Create Bitwarden directory
file: ansible.builtin.file:
path: "{{ bitwarden_root }}" path: "{{ bitwarden_root }}"
state: directory state: directory
mode: "755"
- name: Download Bitwarden script - name: Download Bitwarden script
get_url: ansible.builtin.get_url:
url: "https://raw.githubusercontent.com/\ url: "https://raw.githubusercontent.com/\
bitwarden/server/master/scripts/bitwarden.sh" bitwarden/self-host/master/bitwarden.sh"
dest: "{{ bitwarden_root }}" dest: "{{ bitwarden_root }}"
mode: u+x mode: u+x
- name: Install Bitwarden script wrapper - name: Install Bitwarden script wrapper
template: ansible.builtin.template:
src: bw_wrapper.j2 src: bw_wrapper.j2
dest: "{{ bitwarden_root }}/bw_wrapper" dest: "{{ bitwarden_root }}/bw_wrapper"
mode: u+x mode: u+x
- name: Run Bitwarden installation script - name: Run Bitwarden installation script
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"
notify: start_bitwarden
- name: Install docker-compose override - name: Install compose override
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"
notify: mode: "644"
- rebuild_bitwarden when: bitwarden_override | default(true)
- start_bitwarden notify: rebuild_bitwarden
- name: Disable bitwarden-nginx HTTP on 80 - name: Disable bitwarden-nginx HTTP on 80
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: 8080" replace: "http_port: {{ bitwarden_http_port | default('127.0.0.1:9080') }}"
when: not bitwarden_standalone when: not bitwarden_standalone
notify: notify: rebuild_bitwarden
- rebuild_bitwarden
- start_bitwarden
- name: Disable bitwarden-nginx HTTPS on 443 - name: Disable bitwarden-nginx HTTPS on 443
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: 8443" replace: "https_port: {{ bitwarden_https_port | default('127.0.0.1:9443') }}"
when: not bitwarden_standalone when: not bitwarden_standalone
notify: notify: rebuild_bitwarden
- rebuild_bitwarden
- start_bitwarden
- name: Disable Bitwarden managed Lets Encrypt - name: Disable Bitwarden managed Lets Encrypt
replace: ansible.builtin.replace:
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"
when: not bitwarden_standalone or not bitwarden_production when: not bitwarden_standalone or not bitwarden_production
notify: notify: rebuild_bitwarden
- rebuild_bitwarden
- start_bitwarden
- name: Disable Bitwarden managed SSL - name: Disable Bitwarden managed SSL
replace: ansible.builtin.replace:
path: "{{ bitwarden_root }}/bwdata/config.yml" path: "{{ bitwarden_root }}/bwdata/config.yml"
regexp: "^ssl: true$" regexp: "^ssl: true$"
replace: "ssl: false" replace: "ssl: false"
when: not bitwarden_standalone when: not bitwarden_standalone
notify: notify: rebuild_bitwarden
- rebuild_bitwarden
- start_bitwarden - name: Define reverse proxy servers
ansible.builtin.lineinfile:
path: "{{ bitwarden_root }}/bwdata/config.yml"
line: "- {{ bitwarden_realips }}"
insertafter: "^real_ips"
notify: rebuild_bitwarden
- name: Install Bitwarden systemd service
ansible.builtin.template:
src: bitwarden.service.j2
dest: "/etc/systemd/system/{{ bitwarden_name }}.service"
mode: "644"
register: bitwarden_systemd
notify: rebuild_bitwarden
- name: Create Bitwarden's initial logging directory
ansible.builtin.file:
path: "{{ bitwarden_logs_identity }}"
state: directory
mode: "755"
notify: touch_bitwarden
- name: Install Bitwarden's Fail2ban jail
ansible.builtin.template:
src: fail2ban-jail.conf.j2
dest: /etc/fail2ban/jail.d/bitwarden.conf
mode: "640"
notify: restart_fail2ban

View File

@ -0,0 +1,13 @@
[Unit]
Description=Bitwarden Password Manager Server
PartOf=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart={{ bitwarden_root }}/bitwarden.sh start
ExecStop={{ bitwarden_root }}/bitwarden.sh stop
[Install]
WantedBy=multi-user.target

View File

@ -14,16 +14,22 @@ send "y\r"
send "n\r" send "n\r"
{% endif %} {% endif %}
expect "Enter the database name for your Bitwarden instance (ex. vault):"
send "{{ bitwarden_database }}\r"
expect "Enter your installation id (get at https://bitwarden.com/host):" expect "Enter your installation id (get at https://bitwarden.com/host):"
send "{{ bitwarden_install_id }}\r" 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 %}

View File

@ -1,16 +1,16 @@
version: '3'
services: services:
nginx: nginx:
networks: networks:
- 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

View File

@ -0,0 +1,9 @@
# {{ ansible_managed }}
[bitwarden]
enabled = true
filter = bitwarden
logpath = {{ bitwarden_root }}/bwdata/logs/identity/Identity/*
maxretry = 10
findtime = 3600
bantime = 900
action = iptables-allports

View File

@ -0,0 +1,11 @@
docker_apt_keyring: /etc/apt/keyrings/docker.asc
docker_apt_keyring_hash: 1500c1f56fa9e26b9b8f42452a553675796ade0807cdce11975eb98170b3a570
docker_apt_keyring_url: https://download.docker.com/linux/debian/gpg
docker_apt_repo: https://download.docker.com/linux/debian
docker_compose_root: /var/lib/compose
docker_compose_service: compose
docker_compose: "{{ (docker_official | bool) | ternary('/usr/bin/docker compose', '/usr/bin/docker-compose') }}"
docker_official: false
docker_repos_keys: "{{ docker_repos_path }}/.keys"
docker_repos_keytype: rsa
docker_repos_path: /srv/.compose_repos

View File

@ -1 +0,0 @@
deb [arch=amd64] https://download.docker.com/linux/debian buster stable

View File

@ -0,0 +1,54 @@
- name: Reload systemd manager configuration
ansible.builtin.systemd:
daemon_reload: true
listen: compose_systemd
- name: Find which services had a docker-compose.yml updated
ansible.builtin.set_fact:
compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}"
loop: "{{ compose_update.results }}"
loop_control:
label: "{{ item.item.name }}"
when: item.changed
listen: compose_restart
- name: Find which services had their .env updated
ansible.builtin.set_fact:
compose_restart_list: "{{ (compose_restart_list | default([])) + [item.item.name] }}"
loop: "{{ compose_env_update.results }}"
loop_control:
label: "{{ item.item.name }}"
when: item.changed
listen: compose_restart
- name: Restart MariaDB
ansible.builtin.service:
name: mariadb
state: restarted
when: not mariadb_restarted
listen: restart_mariadb # hijack handler for early restart
- name: Set MariaDB as restarted
ansible.builtin.set_fact:
mariadb_restarted: true
when: not mariadb_restarted
listen: restart_mariadb
- name: Restart compose services
ansible.builtin.systemd:
state: restarted
name: "{{ docker_compose_service }}@{{ item }}"
loop: "{{ compose_restart_list | default([]) | unique }}"
when: compose_restart_list is defined
listen: compose_restart
- name: Start compose services and enable on boot
ansible.builtin.service:
name: "{{ docker_compose_service }}@{{ item.name }}"
state: started
enabled: true
loop: "{{ docker_compose_deploy }}"
loop_control:
label: "{{ docker_compose_service }}@{{ item.name }}"
when: item.enabled is defined and item.enabled is true
listen: compose_enable

View File

@ -1,38 +0,0 @@
#!/bin/bash
# Github username and repo name
user="docker"
repo="compose"
# Retrieve the latest version number
addr="https://github.com/$user/$repo/releases/latest"
page=$(curl -s $addr | grep -o releases/tag/*.*\")
version=$(echo $page | awk '{print substr($1, 14, length($1) - 14)}')
# Download prep
url="https://github.com/$user/$repo/releases/download/$version"
file="docker-compose-$(uname -s)-$(uname -m)"
# Download latest Docker Compose if that version hasn't been downloaded
if [ ! -f /tmp/docker_compose_$version ]; then
curl -L $url/$file -o /tmp/docker-compose_$version
fi
# Is it already installed?
if installed=$(which docker-compose); then
new_chksum=$(sha256sum /tmp/docker-compose_$version)
old_chksum=$(sha256sum /usr/local/bin/docker-compose)
# If checksums are different, delete and install new version
if [ ! "$new_chksum" = "$old_chksum" ]; then
rm /usr/local/bin/docker-compose
mv /tmp/docker-compose_$version /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
fi
else
# It's not installed, so no need to remove
mv /tmp/docker-compose_$version /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
fi

View File

@ -1,61 +1,151 @@
# Copyright (C) 2019 Kris Lamoureux - name: Add official Docker APT key
# ansible.builtin.get_url:
# This program is free software: you can redistribute it and/or modify url: "{{ docker_apt_keyring_url }}"
# it under the terms of the GNU General Public License as published by dest: "{{ docker_apt_keyring }}"
# the Free Software Foundation, version 3 of the License. checksum: "sha256:{{ docker_apt_keyring_hash }}"
# mode: "644"
# This program is distributed in the hope that it will be useful, owner: root
# but WITHOUT ANY WARRANTY; without even the implied warranty of group: root
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the when: docker_official
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
- name: Remove old versions of Docker - name: Remove official Docker APT key
apt: ansible.builtin.file:
name: ['docker', 'docker-engine', 'docker.io', 'containerd', 'runc'] path: "{{ docker_apt_keyring }}"
state: absent state: absent
when: not docker_official
- name: Add/remove official Docker APT repository
ansible.builtin.apt_repository:
repo: >
deb [arch=amd64 signed-by={{ docker_apt_keyring }}]
{{ docker_apt_repo }} {{ ansible_distribution_release }} stable
state: "{{ 'present' if docker_official else 'absent' }}"
filename: "{{ docker_apt_keyring | regex_replace('^.*/', '') }}"
- name: Install/uninstall Docker from Debian repositories
ansible.builtin.apt:
name: ['docker.io', 'docker-compose', 'containerd', 'runc']
state: "{{ 'absent' if docker_official else 'present' }}"
autoremove: true
update_cache: true update_cache: true
- name: Install HTTPS capability for apt - name: Install/uninstall Docker from Docker repositories
apt: ansible.builtin.apt:
name: ['apt-transport-https', 'ca-certificates', name: ['docker-ce', 'docker-ce-cli', 'containerd.io',
'curl', 'gnupg2', 'software-properties-common'] 'docker-buildx-plugin', 'docker-compose-plugin']
state: present state: "{{ 'present' if docker_official else 'absent' }}"
autoremove: true
- name: Install Docker's signing key
apt_key:
url: https://download.docker.com/linux/debian/gpg
id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
state: present
- name: Install Docker's stable repository
template:
src: docker-ce.list
dest: /etc/apt/sources.list.d/docker-ce.list
- name: Install Docker CE
apt:
name: ['docker-ce', 'docker-ce-cli', 'containerd.io']
state: present
update_cache: true update_cache: true
- name: Login to private registry
community.docker.docker_login:
registry_url: "{{ docker_login_url | default('') }}"
username: "{{ docker_login_user }}"
password: "{{ docker_login_pass }}"
when: docker_login_user is defined and docker_login_pass is defined
- name: Create docker-compose root
ansible.builtin.file:
path: "{{ docker_compose_root }}"
state: directory
mode: "500"
- name: Install docker-compose systemd service
ansible.builtin.template:
src: docker-compose.service.j2
dest: "/etc/systemd/system/{{ docker_compose_service }}@.service"
mode: "400"
notify: compose_systemd
- name: Create directories to clone docker-compose repositories
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "400"
loop:
- "{{ docker_repos_path }}"
- "{{ docker_repos_keys }}"
when: docker_compose_deploy is defined
- name: Generate OpenSSH deploy keys for docker-compose clones
community.crypto.openssh_keypair:
path: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}"
type: "{{ docker_repos_keytype }}"
comment: "{{ ansible_hostname }}-deploy-key"
mode: "400"
state: present
when: docker_compose_deploy is defined
- name: Check for git installation
ansible.builtin.apt:
name: git
state: present
when: docker_compose_deploy is defined
- name: Clone external docker-compose projects
ansible.builtin.git:
repo: "{{ item.url }}"
dest: "{{ docker_repos_path }}/{{ item.name }}"
version: "{{ item.version }}"
accept_newhostkey: "{{ item.accept_newhostkey | default(false) }}"
gpg_whitelist: "{{ item.trusted_keys | default([]) }}"
verify_commit: "{{ true if (item.trusted_keys is defined and item.trusted_keys) else false }}"
key_file: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}"
loop: "{{ docker_compose_deploy }}"
loop_control:
label: "{{ item.url }}"
when: docker_compose_deploy is defined
- name: Create directories for docker-compose projects using the systemd service
ansible.builtin.file:
path: "{{ docker_compose_root }}/{{ item.name }}"
state: directory
mode: "400"
loop: "{{ docker_compose_deploy }}"
loop_control:
label: "{{ item.name }}"
when: docker_compose_deploy is defined
- name: Synchronize docker-compose.yml
ansible.posix.synchronize:
src: "{{ docker_repos_path }}/{{ item.name }}/{{ item.path | default('docker-compose.yml') }}"
dest: "{{ docker_compose_root }}/{{ item.name }}/docker-compose.yml"
delegate_to: "{{ inventory_hostname }}"
register: compose_update
notify:
- compose_restart
- compose_enable
loop: "{{ docker_compose_deploy | default([]) }}"
loop_control:
label: "{{ item.name }}"
when: docker_compose_deploy is defined and docker_compose_deploy | length > 0
- name: Set environment variables for docker-compose projects
ansible.builtin.template:
src: docker-compose-env.j2
dest: "{{ docker_compose_root }}/{{ item.name }}/.env"
mode: "400"
register: compose_env_update
notify:
- compose_restart
- compose_enable
no_log: "{{ docker_compose_env_nolog | default(true) }}"
loop: "{{ docker_compose_deploy }}"
loop_control:
label: "{{ item.name }}"
when: docker_compose_deploy is defined and item.env is defined
- name: Add users to docker group - name: Add users to docker group
user: ansible.builtin.user:
name: "{{ item }}" name: "{{ item }}"
groups: docker groups: docker
append: true append: true
loop: "{{ docker_users }}" loop: "{{ docker_users }}"
when: docker_users is defined when: docker_users is defined
- name: Install docker-compose
script: install-compose.sh
args:
creates: /usr/local/bin/docker-compose
- name: Start Docker and enable on boot - name: Start Docker and enable on boot
service: ansible.builtin.service:
name: docker name: docker
state: started state: started
enabled: true enabled: true
when: docker_managed | default(true)

View File

@ -0,0 +1,10 @@
# {{ ansible_managed }}
{% if item.env is defined %}
{% for key, value in item.env.items() %}
{% if value is boolean %}
{{ key }}={{ value | lower }}
{% else %}
{{ key }}={{ value }}
{% endif %}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,14 @@
[Unit]
Description=%i {{ docker_compose_service }} service
PartOf=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory={{ docker_compose_root }}/%i
ExecStart={{ docker_compose }} up -d --remove-orphans
ExecStop={{ docker_compose }} down
[Install]
WantedBy=multi-user.target

View File

@ -1,11 +1,22 @@
# container settings # container settings
gitea_name: gitea gitea_name: gitea
gitea_dbname: "{{ gitea_name }}-db" gitea_sshport: "222"
gitea_ports: "222:22" gitea_webport: "3000"
gitea_ssh: "127.0.0.1:{{ gitea_sshport }}"
gitea_web: "127.0.0.1:{{ gitea_webport }}"
gitea_volume: "{{ gitea_name }}"
gitea_rooturl: "https://{{ gitea_domain }}"
gitea_signup: true
# database settings # database settings
gitea_dbuser: "{{ gitea_dbname }}" gitea_dbtype: mysql
gitea_dbhost: host.docker.internal
gitea_dbname: "{{ gitea_name }}"
gitea_dbuser: "{{ gitea_name }}"
# proxy settings
gitea_proxy_limit: "1"
gitea_trusted_proxies: "172.16.0.0/12"
# host # host
gitea_root: "/opt/{{ gitea_name }}/data" gitea_root: "{{ docker_compose_root }}/{{ gitea_name }}"
gitea_dbroot: "/opt/{{ gitea_name }}/database"

View File

@ -0,0 +1,5 @@
- name: Restart Gitea
ansible.builtin.service:
name: "{{ docker_compose_service }}@{{ gitea_name }}"
state: restarted
listen: restart_gitea

View File

@ -1,54 +1,78 @@
- name: Create Gitea Network - name: Install MySQL module for Ansible
docker_network: ansible.builtin.apt:
name: "{{ gitea_name }}" name: python3-pymysql
state: present
- name: Start Gitea's database container - name: Create Gitea database
docker_container: community.mysql.mysql_db:
name: "{{ gitea_dbname }}" name: "{{ gitea.DB_NAME }}"
image: mariadb:{{ gitea_dbversion }} state: present
state: started login_unix_socket: /var/run/mysqld/mysqld.sock
restart_policy: always
volumes: "{{ gitea_dbroot }}:/var/lib/mysql"
networks_cli_compatible: true
networks:
- name: "{{ gitea_name }}"
env:
MYSQL_RANDOM_ROOT_PASSWORD: "true"
MYSQL_DATABASE: "{{ gitea_dbname }}"
MYSQL_USER: "{{ gitea_dbuser }}"
MYSQL_PASSWORD: "{{ gitea_dbpass }}"
- name: Start Gitea container - name: Create Gitea database user
docker_container: community.mysql.mysql_user:
name: "{{ gitea_name }}" name: "{{ gitea.DB_USER }}"
image: gitea/gitea:{{ gitea_version }} password: "{{ gitea.DB_PASSWD }}"
state: started host: '%'
restart_policy: always state: present
networks_cli_compatible: true priv: "{{ gitea.DB_NAME }}.*:ALL"
ports: "{{ gitea_ports }}" login_unix_socket: /var/run/mysqld/mysqld.sock
networks:
- name: "{{ gitea_name }}" - name: Create git's .ssh directory
- name: traefik ansible.builtin.file:
volumes: path: /home/git/.ssh
- "{{ gitea_root }}:/data" mode: "700"
- /etc/timezone:/etc/timezone:ro state: directory
- /etc/localtime:/etc/localtime:ro
env: - name: Generate git's SSH keys
USER_UID: "1000" community.crypto.openssh_keypair:
USER_GID: "1000" path: /home/git/.ssh/id_rsa
DB_TYPE: mysql
DB_HOST: "{{ gitea_dbname }}" - name: Find git's public SSH key
DB_NAME: "{{ gitea_dbname }}" ansible.builtin.slurp:
DB_USER: "{{ gitea_dbuser }}" src: /home/git/.ssh/id_rsa.pub
DB_PASSWD: "{{ gitea_dbpass }}" register: git_rsapub
ROOT_URL: "https://{{ gitea_domain }}/"
SSH_DOMAIN: "{{ gitea_domain }}" - name: Get stats on git's authorized_keys file
DOMAIN: "{{ gitea_domain }}" ansible.builtin.stat:
labels: path: /home/git/.ssh/authorized_keys
traefik.http.routers.gitea.rule: "Host(`{{ gitea_domain }}`)" register: git_authkeys
traefik.http.routers.gitea.entrypoints: websecure
traefik.http.routers.gitea.tls.certresolver: letsencrypt - name: Create git's authorized_keys file
traefik.http.routers.gitea.middlewares: "securehttps@file" ansible.builtin.file:
traefik.http.services.gitea.loadbalancer.server.port: "3000" path: /home/git/.ssh/authorized_keys
traefik.docker.network: traefik mode: "600"
traefik.enable: "true" state: touch
when: not git_authkeys.stat.exists
- name: Add git's public SSH key to authorized_keys
ansible.builtin.lineinfile:
path: /home/git/.ssh/authorized_keys
regex: "^ssh-rsa"
line: "{{ git_rsapub['content'] | b64decode }}"
- name: Create Gitea host script for SSH
ansible.builtin.template:
src: gitea.sh.j2
dest: /usr/local/bin/gitea
mode: "755"
- name: Create Gitea's logging directory
ansible.builtin.file:
name: /var/log/gitea
state: directory
mode: "755"
- name: Install Gitea's Fail2ban filter
ansible.builtin.template:
src: fail2ban-filter.conf.j2
dest: /etc/fail2ban/filter.d/gitea.conf
mode: "644"
notify: restart_fail2ban
- name: Install Gitea's Fail2ban jail
ansible.builtin.template:
src: fail2ban-jail.conf.j2
dest: /etc/fail2ban/jail.d/gitea.conf
mode: "640"
notify: restart_fail2ban

View File

@ -0,0 +1,19 @@
# {{ ansible_managed }}
gitea_version={{ gitea_version }}
gitea_name={{ gitea_name }}
gitea_domain={{ gitea_domain }}
gitea_rooturl={{ gitea_rooturl }}
gitea_web={{ gitea_web }}
gitea_ssh={{ gitea_ssh }}
gitea_dbtype={{ gitea_dbtype }}
gitea_dbhost={{ gitea_dbhost }}
gitea_dbname={{ gitea_dbname }}
gitea_dbuser={{ gitea_dbuser }}
gitea_dbpass={{ gitea_dbpass }}
gitea_proxy_limit={{ gitea_proxy_limit }}
gitea_trusted_proxies={{ gitea_trusted_proxies }}
{% if not gitea_signup %}
gitea_disable_registration=true
{% else %}
gitea_disable_registration=false
{% endif %}

View File

@ -0,0 +1,36 @@
version: '3.7'
services:
gitea:
image: "gitea/gitea:${gitea_version}"
container_name: "${gitea_name}"
ports:
- "${gitea_ssh}:22"
- "${gitea_web}:3000"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- USER_UID={{ getent_passwd.git[1] }}
- USER_GID={{ getent_group.git[1] }}
- GITEA__log__MODE=file
- GITEA__server__ROOT_URL=${gitea_rooturl}
- GITEA__server__DOMAIN=${gitea_domain}
- GITEA__server__SSH_DOMAIN=${gitea_domain}
- GITEA__database__DB_TYPE=${gitea_dbtype}
- GITEA__database__HOST=${gitea_dbhost}
- GITEA__database__NAME=${gitea_dbname}
- GITEA__database__USER=${gitea_dbuser}
- GITEA__database__PASSWD=${gitea_dbpass}
- GITEA__security__INSTALL_LOCK=true
- GITEA__security__REVERSE_PROXY_LIMIT=${gitea_proxy_limit}
- GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES=${gitea_trusted_proxies}
- GITEA__service__DISABLE_REGISTRATION=${gitea_disable_registration}
volumes:
- {{ gitea_volume }}:/data
- /home/git/.ssh:/data/git/.ssh
- /var/log/gitea:/data/gitea/log
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
volumes:
{{ gitea_volume }}:

View File

@ -0,0 +1,4 @@
# {{ ansible_managed }}
[Definition]
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =

View File

@ -0,0 +1,18 @@
# {{ ansible_managed }}
[gitea]
enabled = true
filter = gitea
logpath = /var/log/gitea/gitea.log
maxretry = 10
findtime = 3600
bantime = 900
action = iptables-allports
[gitea-docker]
enabled = true
filter = gitea
logpath = /var/log/gitea/gitea.log
maxretry = 10
findtime = 3600
bantime = 900
action = iptables-allports[chain="FORWARD"]

View File

@ -0,0 +1,2 @@
#!/bin/sh
ssh -p {{ gitea_sshport }} -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"

View File

@ -0,0 +1,4 @@
jellyfin_name: jellyfin
jellyfin_router: "{{ jellyfin_name }}"
jellyfin_rooturl: "https://{{ jellyfin_domain }}"
jellyfin_root: "{{ docker_compose_root }}/{{ jellyfin_name }}"

View File

@ -0,0 +1,5 @@
- name: Restart Jellyfin
ansible.builtin.service:
name: "{{ docker_compose_service }}@{{ jellyfin_name }}"
state: restarted
listen: restart_jellyfin

View File

@ -0,0 +1,35 @@
- name: Create Jellyfin directory
ansible.builtin.file:
path: "{{ jellyfin_root }}"
state: directory
mode: 0500
- name: Get user jellyfin uid
ansible.builtin.getent:
database: passwd
key: jellyfin
- name: Get user jellyfin gid
ansible.builtin.getent:
database: group
key: jellyfin
- name: Install Jellyfin's docker-compose file
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ jellyfin_root }}/docker-compose.yml"
mode: 0400
notify: restart_jellyfin
- name: Install Jellyfin's docker-compose variables
ansible.builtin.template:
src: compose-env.j2
dest: "{{ jellyfin_root }}/.env"
mode: 0400
notify: restart_jellyfin
- name: Start and enable Jellyfin service
ansible.builtin.service:
name: "{{ docker_compose_service }}@{{ jellyfin_name }}"
state: started
enabled: true

View File

@ -0,0 +1,5 @@
# {{ ansible_managed }}
jellyfin_version={{ jellyfin_version }}
jellyfin_name={{ jellyfin_name }}
jellyfin_domain={{ jellyfin_domain }}
jellyfin_rooturl={{ jellyfin_rooturl }}

View File

@ -0,0 +1,30 @@
version: '3.7'
volumes:
config:
cache:
networks:
traefik:
external: true
services:
jellyfin:
image: "jellyfin/jellyfin:${jellyfin_version}"
container_name: "${jellyfin_name}"
networks:
- traefik
labels:
- "traefik.http.routers.{{ jellyfin_router }}.rule=Host(`{{ jellyfin_domain }}`)"
{% if traefik_http_only %}
- "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web"
{% else %}
- "traefik.http.routers.{{ jellyfin_router }}.entrypoints=websecure"
{% endif %}
- "traefik.http.services.{{ jellyfin_router }}.loadbalancer.server.port=8096"
- "traefik.docker.network=traefik"
- "traefik.enable=true"
volumes:
- config:/config
- cache:/cache
- {{ jellyfin_media }}:/media

View File

@ -1 +0,0 @@
deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main

View File

@ -1,10 +1,5 @@
- name: Install GnuPG
apt:
name: gnupg
state: present
- name: Create Jenkins user - name: Create Jenkins user
user: ansible.builtin.user:
name: "{{ jenkins_user }}" name: "{{ jenkins_user }}"
state: present state: present
shell: /bin/bash shell: /bin/bash
@ -12,35 +7,25 @@
generate_ssh_key: true generate_ssh_key: true
- name: Set Jenkins authorized key - name: Set Jenkins authorized key
authorized_key: ansible.posix.authorized_key:
user: jenkins user: jenkins
state: present state: present
exclusive: true exclusive: true
key: "{{ jenkins_sshkey }}" key: "{{ jenkins_sshkey }}"
- name: Give Jenkins user passwordless sudo - name: Give Jenkins user passwordless sudo
template: ansible.builtin.template:
src: jenkins_sudoers.j2 src: jenkins_sudoers.j2
dest: /etc/sudoers.d/{{ jenkins_user }} dest: /etc/sudoers.d/{{ jenkins_user }}
validate: "visudo -cf %s" validate: "visudo -cf %s"
mode: 0440 mode: 0440
- name: Install Ansible source
copy:
src: ansible.list
dest: /etc/apt/sources.list.d/ansible.list
- name: Add Ansible source key
apt_key:
keyserver: keyserver.ubuntu.com
id: 93C4A3FD7BB9C367
- name: Install Ansible - name: Install Ansible
apt: ansible.builtin.apt:
name: ansible name: ansible
state: present state: present
- name: Install Java - name: Install Java
apt: ansible.builtin.apt:
name: default-jre name: default-jre
state: present state: present

View File

@ -1,5 +1,5 @@
- import_tasks: agent.yml - ansible.builtin.import_tasks: agent.yml
when: jenkins_sshkey is defined when: jenkins_sshkey is defined
- import_tasks: server.yml - ansible.builtin.import_tasks: server.yml
when: jenkins_domain is defined when: jenkins_domain is defined

View File

@ -1,12 +1,12 @@
- name: Create Jenkin's directory - name: Create Jenkin's directory
file: ansible.builtin.file:
path: "{{ jenkins_root }}" path: "{{ jenkins_root }}"
state: directory state: directory
owner: "1000" owner: "1000"
group: "1000" group: "1000"
- name: Start Jenkins Container - name: Start Jenkins Container
docker_container: community.general.docker_container:
name: "{{ jenkins_name }}" name: "{{ jenkins_name }}"
image: jenkins/jenkins:{{ jenkins_version }} image: jenkins/jenkins:{{ jenkins_version }}
state: started state: started

View File

@ -1,15 +1,15 @@
- name: Install QEMU/KVM - name: Install QEMU/KVM
apt: ansible.builtin.apt:
name: qemu-kvm name: qemu-kvm
state: present state: present
- name: Install Libvirt - name: Install Libvirt
apt: ansible.builtin.apt:
name: ["libvirt-clients", "libvirt-daemon-system"] name: ["libvirt-clients", "libvirt-daemon-system"]
state: present state: present
- name: Add users to libvirt group - name: Add users to libvirt group
user: ansible.builtin.user:
name: "{{ item }}" name: "{{ item }}"
groups: libvirt groups: libvirt
append: yes append: yes
@ -17,12 +17,12 @@
when: libvirt_users is defined when: libvirt_users is defined
- name: Check for NODOWNLOAD file - name: Check for NODOWNLOAD file
stat: ansible.builtin.stat:
path: /var/lib/libvirt/images/NODOWNLOAD path: /var/lib/libvirt/images/NODOWNLOAD
register: NODOWNLOAD register: NODOWNLOAD
- name: Download GNU/Linux ISOs - name: Download GNU/Linux ISOs
get_url: ansible.builtin.get_url:
url: "{{ item.url }}" url: "{{ item.url }}"
dest: /var/lib/libvirt/images dest: /var/lib/libvirt/images
checksum: "{{ item.hash }}" checksum: "{{ item.hash }}"
@ -34,7 +34,7 @@
# Prevent downloaded ISOs from being rehashed every run # Prevent downloaded ISOs from being rehashed every run
- name: Create NODOWNLOAD file - name: Create NODOWNLOAD file
file: ansible.builtin.file:
path: /var/lib/libvirt/images/NODOWNLOAD path: /var/lib/libvirt/images/NODOWNLOAD
state: touch state: touch
when: download_isos.changed when: download_isos.changed

View File

@ -0,0 +1,12 @@
- name: Restart MariaDB
ansible.builtin.service:
name: mariadb
state: restarted
when: not mariadb_restarted
listen: restart_mariadb
- name: Set MariaDB as restarted
ansible.builtin.set_fact:
mariadb_restarted: true
when: not mariadb_restarted
listen: restart_mariadb

View File

@ -0,0 +1,30 @@
- name: Install MariaDB
ansible.builtin.apt:
name: mariadb-server
state: present
- name: Set MariaDB restarted fact
ansible.builtin.set_fact:
mariadb_restarted: false
- name: Regather facts for the potentially new docker0 interface
ansible.builtin.setup:
- name: Change the bind-address to allow from docker0
ansible.builtin.lineinfile:
path: /etc/mysql/mariadb.conf.d/50-server.cnf
regex: "^bind-address"
line: "bind-address = {{ ansible_facts.docker0.ipv4.address }}"
notify: restart_mariadb
- name: Flush handlers to ensure MariaDB restarts immediately
ansible.builtin.meta: flush_handlers
tags: restart_mariadb
- name: Allow database connections from Docker
community.general.ufw:
rule: allow
port: "3306"
proto: tcp
src: "{{ item }}"
loop: "{{ mariadb_trust | default(['172.16.0.0/12']) }}"

View File

@ -1,28 +1,28 @@
- name: Install GPG - name: Install GPG
apt: ansible.builtin.apt:
name: gpg name: gpg
state: present state: present
- name: Add AdoptOpenJDK's signing key - name: Add AdoptOpenJDK's signing key
apt_key: ansible.builtin.apt_key:
id: 8ED17AF5D7E675EB3EE3BCE98AC3B29174885C03 id: 8ED17AF5D7E675EB3EE3BCE98AC3B29174885C03
url: https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public url: https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public
- name: Install AdoptOpenJDK repository - name: Install AdoptOpenJDK repository
apt_repository: ansible.builtin.apt_repository:
repo: deb https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/ buster main repo: deb https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/ buster main
mode: 0644 mode: 0644
state: present state: present
- name: Install Java - name: Install Java
apt: ansible.builtin.apt:
name: "adoptopenjdk-{{ item.java.version }}-hotspot" name: "adoptopenjdk-{{ item.java.version }}-hotspot"
state: present state: present
when: item.java.version is defined when: item.java.version is defined
loop: "{{ minecraft }}" loop: "{{ minecraft }}"
- name: "Install default Java, version {{ minecraft_java }}" - name: "Install default Java, version {{ minecraft_java }}"
apt: ansible.builtin.apt:
name: "{{ minecraft_java_pkg }}" name: "{{ minecraft_java_pkg }}"
state: present state: present
when: item.java.version is not defined when: item.java.version is not defined
@ -30,7 +30,7 @@
register: minecraft_java_default register: minecraft_java_default
- name: "Activate default Java, version {{ minecraft_java }}" - name: "Activate default Java, version {{ minecraft_java }}"
alternatives: community.general.alternatives:
name: java name: java
path: "/usr/lib/jvm/{{ minecraft_java_pkg }}-amd64/bin/java" path: "/usr/lib/jvm/{{ minecraft_java_pkg }}-amd64/bin/java"
when: minecraft_java_default.changed when: minecraft_java_default.changed

View File

@ -1,14 +1,14 @@
- import_tasks: system.yml - ansible.builtin.import_tasks: system.yml
when: minecraft_eula when: minecraft_eula
- import_tasks: java.yml - ansible.builtin.import_tasks: java.yml
when: minecraft_eula when: minecraft_eula
- import_tasks: vanilla.yml - ansible.builtin.import_tasks: vanilla.yml
when: minecraft_eula when: minecraft_eula
- import_tasks: modpacks.yml - ansible.builtin.import_tasks: modpacks.yml
when: minecraft_eula when: minecraft_eula
- import_tasks: service.yml - ansible.builtin.import_tasks: service.yml
when: minecraft_eula when: minecraft_eula

View File

@ -1,5 +1,5 @@
- name: Download Minecraft modpack installer - name: Download Minecraft modpack installer
get_url: ansible.builtin.get_url:
url: "{{ minecraft_modpack_url }}" url: "{{ minecraft_modpack_url }}"
dest: "{{ minecraft_home }}/{{ item.name }}/serverinstall_{{ item.modpack | replace ('/', '_') }}" dest: "{{ minecraft_home }}/{{ item.name }}/serverinstall_{{ item.modpack | replace ('/', '_') }}"
owner: "{{ minecraft_user }}" owner: "{{ minecraft_user }}"
@ -9,7 +9,7 @@
when: item.modpack is defined and item.sha1 is not defined when: item.modpack is defined and item.sha1 is not defined
- name: Run Minecraft modpack installer - name: Run Minecraft modpack installer
command: "sudo -u {{ minecraft_user }} ./serverinstall_{{ item.modpack | replace ('/', '_') }} --auto" ansible.builtin.command: "sudo -u {{ minecraft_user }} ./serverinstall_{{ item.modpack | replace ('/', '_') }} --auto"
args: args:
creates: "{{ minecraft_home }}/{{ item.name }}/mods" creates: "{{ minecraft_home }}/{{ item.name }}/mods"
chdir: "{{ minecraft_home }}/{{ item.name }}" chdir: "{{ minecraft_home }}/{{ item.name }}"
@ -17,7 +17,7 @@
when: item.modpack is defined and item.sha1 is not defined when: item.modpack is defined and item.sha1 is not defined
- name: Find Minecraft Forge - name: Find Minecraft Forge
find: ansible.builtin.find:
paths: "{{ minecraft_home }}/{{ item.name }}" paths: "{{ minecraft_home }}/{{ item.name }}"
patterns: "forge*.jar" patterns: "forge*.jar"
register: minecraft_forge register: minecraft_forge
@ -25,7 +25,7 @@
when: item.modpack is defined and item.sha1 is not defined when: item.modpack is defined and item.sha1 is not defined
- name: Link to Minecraft Forge - name: Link to Minecraft Forge
file: ansible.builtin.file:
src: "{{ item.files[0].path }}" src: "{{ item.files[0].path }}"
dest: "{{ minecraft_home }}/{{ item.item.name }}/minecraft_server.jar" dest: "{{ minecraft_home }}/{{ item.item.name }}/minecraft_server.jar"
owner: "{{ minecraft_user }}" owner: "{{ minecraft_user }}"

View File

@ -1,11 +1,11 @@
- name: Deploy Minecraft systemd service - name: Deploy Minecraft systemd service
template: ansible.builtin.template:
src: minecraft.service.j2 src: minecraft.service.j2
dest: "/etc/systemd/system/minecraft@.service" dest: "/etc/systemd/system/minecraft@.service"
register: minecraft_systemd register: minecraft_systemd
- name: Deploy service environmental variables - name: Deploy service environmental variables
template: ansible.builtin.template:
src: environment.conf.j2 src: environment.conf.j2
dest: "{{ minecraft_home }}/{{ item.name }}/environment.conf" dest: "{{ minecraft_home }}/{{ item.name }}/environment.conf"
owner: "{{ minecraft_user }}" owner: "{{ minecraft_user }}"
@ -13,25 +13,25 @@
loop: "{{ minecraft }}" loop: "{{ minecraft }}"
- name: Reload systemd manager configuration - name: Reload systemd manager configuration
systemd: ansible.builtin.systemd:
daemon_reload: true daemon_reload: true
when: minecraft_systemd.changed when: minecraft_systemd.changed
- name: Disable non-default service instances - name: Disable non-default service instances
service: ansible.builtin.service:
name: "minecraft@{{ item.name }}" name: "minecraft@{{ item.name }}"
enabled: false enabled: false
loop: "{{ minecraft }}" loop: "{{ minecraft }}"
when: item.name != minecraft_onboot when: item.name != minecraft_onboot
- name: Enable default service instance - name: Enable default service instance
service: ansible.builtin.service:
name: "minecraft@{{ minecraft_onboot }}" name: "minecraft@{{ minecraft_onboot }}"
enabled: true enabled: true
when: minecraft_eula and minecraft_onboot is defined when: minecraft_eula and minecraft_onboot is defined
- name: Run default service instance - name: Run default service instance
service: ansible.builtin.service:
name: "minecraft@{{ minecraft_onboot }}" name: "minecraft@{{ minecraft_onboot }}"
state: started state: started
when: minecraft_eula and minecraft_onboot is defined and minecraft_onboot_run when: minecraft_eula and minecraft_onboot is defined and minecraft_onboot_run

View File

@ -1,16 +1,16 @@
- name: Install Screen - name: Install Screen
apt: ansible.builtin.apt:
name: screen name: screen
state: present state: present
- name: Create Minecraft user - name: Create Minecraft user
user: ansible.builtin.user:
name: "{{ minecraft_user }}" name: "{{ minecraft_user }}"
state: present state: present
shell: /bin/bash ansible.builtin.shell: /bin/bash
- name: Create Minecraft directory - name: Create Minecraft directory
file: ansible.builtin.file:
path: "{{ minecraft_home }}/{{ item.name }}" path: "{{ minecraft_home }}/{{ item.name }}"
state: directory state: directory
owner: "{{ minecraft_user }}" owner: "{{ minecraft_user }}"
@ -18,7 +18,7 @@
loop: "{{ minecraft }}" loop: "{{ minecraft }}"
- name: Answer to Mojang's EULA - name: Answer to Mojang's EULA
template: ansible.builtin.template:
src: eula.txt.j2 src: eula.txt.j2
dest: "{{ minecraft_home }}/{{ item.name }}/eula.txt" dest: "{{ minecraft_home }}/{{ item.name }}/eula.txt"
owner: "{{ minecraft_user }}" owner: "{{ minecraft_user }}"

View File

@ -1,5 +1,5 @@
- name: Download Minecraft - name: Download Minecraft
get_url: ansible.builtin.get_url:
url: "{{ minecraft_url }}" url: "{{ minecraft_url }}"
dest: "{{ minecraft_home }}/{{ item.name }}/minecraft_server.jar" dest: "{{ minecraft_home }}/{{ item.name }}/minecraft_server.jar"
checksum: "sha1:{{ item.sha1 }}" checksum: "sha1:{{ item.sha1 }}"

View File

@ -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"

View 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

View File

@ -1,109 +1,66 @@
- name: Create Nextcloud network - name: Install MySQL module for Ansible
docker_network: ansible.builtin.apt:
name: "{{ nextcloud_container }}" name: python3-pymysql
state: present
- name: Start Nextcloud's database container - name: Create Nextcloud database
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
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
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
docker_container_info:
name: "{{ nextcloud_dbcontainer }}"
register: nextcloud_dbinfo
- name: Grab Nextcloud container information - name: Grab Nextcloud container information
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
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
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
wait_for:
host: "{{ nextcloud_dbinfo.container.NetworkSettings.Networks.nextcloud.IPAddress }}"
port: 3306
- name: Install Nextcloud - name: Install Nextcloud
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 - name: Install Nextcloud background jobs cron
command: 'docker exec --user www-data {{ nextcloud_container }} ansible.builtin.cron:
php occ config:system:set trusted_proxies 0 name: Nextcloud background job
--value="{{ traefik_name }}"' minute: "*/5"
when: nextcloud_install.changed job: "/usr/bin/docker exec -u www-data nextcloud /usr/local/bin/php -f /var/www/html/cron.php"
user: root
- name: Set Nextcloud's Trusted Domain
command: 'docker exec --user www-data {{ nextcloud_container }}
php occ config:system:set trusted_domains 0
--value="{{ nextcloud_domain }}"'
when: nextcloud_install.changed
- name: Preform Nextcloud database maintenance
command: "docker exec --user www-data {{ nextcloud_container }} {{ item }}"
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: Remove Nextcloud's CAN_INSTALL file
file:
path: "{{ nextcloud_root }}/config/CAN_INSTALL"
state: absent

View File

@ -1,15 +1,15 @@
- name: Create nginx root - name: Create nginx root
file: ansible.builtin.file:
path: "{{ nginx_root }}" path: "{{ nginx_root }}"
state: directory state: directory
- name: Generate deploy keys - name: Generate deploy keys
openssh_keypair: community.crypto.openssh_keypair:
path: "{{ nginx_repo_key }}" path: "{{ nginx_repo_key }}"
state: present state: present
- name: Clone static website files - name: Clone static website files
git: ansible.builtin.git:
repo: "{{ nginx_repo_url }}" repo: "{{ nginx_repo_url }}"
dest: "{{ nginx_html }}" dest: "{{ nginx_html }}"
version: "{{ nginx_repo_branch }}" version: "{{ nginx_repo_branch }}"
@ -17,7 +17,7 @@
separate_git_dir: "{{ nginx_repo_dest }}" separate_git_dir: "{{ nginx_repo_dest }}"
- name: Start nginx container - name: Start nginx container
docker_container: community.general.docker_container:
name: "{{ nginx_name }}" name: "{{ nginx_name }}"
image: nginx:{{ nginx_version }} image: nginx:{{ nginx_version }}
state: started state: started
@ -29,9 +29,9 @@
- "{{ nginx_html }}:/usr/share/nginx/html:ro" - "{{ nginx_html }}:/usr/share/nginx/html:ro"
labels: labels:
traefik.http.routers.nginx.rule: "Host(`{{ nginx_domain }}`)" traefik.http.routers.nginx.rule: "Host(`{{ nginx_domain }}`)"
traefik.http.middlewares.nginxauth.basicauth.users: "{{ nginx_auth }}" #traefik.http.middlewares.nginxauth.basicauth.users: "{{ nginx_auth }}"
traefik.http.routers.nginx.entrypoints: websecure traefik.http.routers.nginx.entrypoints: websecure
traefik.http.routers.nginx.tls.certresolver: letsencrypt #traefik.http.routers.nginx.tls.certresolver: letsencrypt
traefik.http.routers.nginx.middlewares: "securehttps@file,nginxauth" #traefik.http.routers.nginx.middlewares: "securehttps@file,nginxauth"
traefik.docker.network: traefik traefik.docker.network: traefik
traefik.enable: "true" traefik.enable: "true"

View File

@ -0,0 +1,5 @@
postgresql_config: /etc/postgresql/13/main/pg_hba.conf
postgresql_listen: "*"
postgresql_trust:
- "172.16.0.0/12"
- "192.168.0.0/16"

View File

@ -0,0 +1,43 @@
- name: Install PostgreSQL
ansible.builtin.apt:
name: postgresql
state: present
- name: Trust connections to PostgreSQL
community.general.postgresql_pg_hba:
dest: "{{ postgresql_config }}"
contype: host
databases: all
users: all
address: "{{ item }}"
method: trust
register: postgresql_hba
loop: "{{ postgresql_trust }}"
- name: Change PostgreSQL listen addresses
community.general.postgresql_set:
name: listen_addresses
value: "{{ postgresql_listen }}"
become: true
become_user: postgres
register: postgresql_config
- name: Reload PostgreSQL
ansible.builtin.service:
name: postgresql
state: reloaded
when: postgresql_hba.changed and not postgresql_config.changed
- name: Restart PostgreSQL
ansible.builtin.service:
name: postgresql
state: restarted
when: postgresql_config.changed
- name: Allow database connections
community.general.ufw:
rule: allow
port: "5432"
proto: tcp
src: "{{ item }}"
loop: "{{ postgresql_trust }}"

View File

@ -1,35 +1,35 @@
- name: Install Prometheus node exporter - name: Install Prometheus node exporter
apt: ansible.builtin.apt:
name: prometheus-node-exporter name: prometheus-node-exporter
state: present state: present
- name: Run Prometheus node exporter - name: Run Prometheus node exporter
service: ansible.builtin.service:
name: prometheus-node-exporter name: prometheus-node-exporter
state: started state: started
- name: Create Prometheus data directory - name: Create Prometheus data directory
file: ansible.builtin.file:
path: "{{ prom_root }}/prometheus" path: "{{ prom_root }}/prometheus"
state: directory state: directory
owner: nobody owner: nobody
- name: Create Prometheus config directory - name: Create Prometheus config directory
file: ansible.builtin.file:
path: "{{ prom_root }}/config" path: "{{ prom_root }}/config"
state: directory state: directory
- name: Install Prometheus configuration - name: Install Prometheus configuration
template: ansible.builtin.template:
src: prometheus.yml.j2 src: prometheus.yml.j2
dest: "{{ prom_root }}/config/prometheus.yml" dest: "{{ prom_root }}/config/prometheus.yml"
- name: Create Prometheus network - name: Create Prometheus network
docker_network: community.general.docker_network:
name: "{{ prom_name }}" name: "{{ prom_name }}"
- name: Start Prometheus container - name: Start Prometheus container
docker_container: community.general.docker_container:
name: "{{ prom_name }}" name: "{{ prom_name }}"
image: prom/prometheus:{{ prom_version }} image: prom/prometheus:{{ prom_version }}
state: started state: started
@ -51,7 +51,7 @@
traefik.enable: "true" traefik.enable: "true"
- name: Start Grafana container - name: Start Grafana container
docker_container: community.general.docker_container:
name: "{{ grafana_name }}" name: "{{ grafana_name }}"
image: grafana/grafana:{{ grafana_version }} image: grafana/grafana:{{ grafana_version }}
state: started state: started

View File

@ -0,0 +1 @@
cached_dhparams_pem: /vagrant/scratch/dhparams.pem

View File

@ -0,0 +1,2 @@
#!/bin/bash
systemctl reload nginx

View File

@ -0,0 +1,15 @@
- name: Enable nginx sites configuration
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ item.item.domain }}.conf"
dest: "/etc/nginx/sites-enabled/{{ item.item.domain }}.conf"
state: link
mode: "400"
loop: "{{ nginx_sites.results }}"
when: item.changed
listen: reload_nginx
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
listen: reload_nginx

Some files were not shown because too many files have changed in this diff Show More