12 Commits

Author SHA1 Message Date
ea9603a2db testing 2025-08-08 01:31:39 -04:00
d954c64e23 Add Podman deployment configuration 2025-08-07 00:24:58 -04:00
ccf6b10a0e Add GPG key and reorganize dockerbox configuration
- Add new primary GPG key in dev config for compose repos
- Slight reorganization of the dockerbox production playbook
- Remove group management in the docker role
- Move HSTS inside the location block
- Add git ignore entry for .ansible files
- Add X-Forwarded-Proto proxy header
2025-03-26 22:07:06 -04:00
bd8eca0466 Remove redundant group management for Docker users
- Minor formatting updated
2025-01-19 17:48:45 -05:00
56c3721a5e Add flexible home and group controls for users 2025-01-19 16:28:54 -05:00
77c9b12186 Add multi-domain support for Jellyfin
- Allow Jellyfin to operate on multiple domains via Host rule config
- Move Cloudflare API tokens from Ansible inventory to manual file
- Minor formatting
2024-12-29 02:22:46 -05:00
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
26 changed files with 348 additions and 206 deletions

View File

@@ -3,8 +3,9 @@ name: homelab-ci
on: on:
push: push:
branches: branches:
- main - github_actions
- testing # - main
# - testing
jobs: jobs:
homelab-ci: homelab-ci:

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.ansible*
/environments/
.playbook .playbook
.vagrant* .vagrant*
.vscode .vscode
/environments/

View File

@@ -6,8 +6,7 @@
roles: roles:
- base - base
- docker - docker
- mariadb
- traefik - traefik
- nextcloud - nextcloud
- jenkins - proxy
- prometheus
- nginx

View File

@@ -2,44 +2,51 @@
allow_reboot: false allow_reboot: false
manage_network: false manage_network: false
# Import my GPG key for git signature verification
root_gpgkeys:
- name: kris@lamoureux.io
id: 42A3A92C5DA0F3E5F71A3710105B748C1362EB96
# Older key, but still in use
- name: kris@lamoureux.io
id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925
server: keyserver.ubuntu.com
# proxy
proxy:
servers:
- domain: cloud.local.krislamo.org
proxy_pass: http://127.0.0.1:8000
# docker # docker
docker_official: true # docker's apt repos
docker_users: docker_users:
- vagrant - vagrant
docker_compose_env_nolog: false # dev only setting
docker_compose_deploy:
# Traefik
- name: traefik
url: https://github.com/krislamo/traefik
version: d62bd06b37ecf0993962b0449a9d708373f9e381
enabled: true
accept_newhostkey: true # Consider verifying manually instead
trusted_keys:
- FBF673CEEC030F8AECA814E73EDA9C3441EDA925
env:
DASHBOARD: true
# Nextcloud
- name: nextcloud
url: https://github.com/krislamo/nextcloud
version: fe6d349749f178e91ae7ff726d557f48ebf84356
env:
DATA: ./data
# traefik # traefik
traefik_version: latest traefik:
traefik_dashboard: true ENABLE: true
traefik_domain: traefik.local.krislamo.org
traefik_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
traefik_web_entry: 0.0.0.0:80
traefik_websecure_entry: 0.0.0.0:443
#traefik_acme_email: realemail@example.com # Let's Encrypt settings
#traefik_production: true
#traefik_http_only: true # if behind reverse-proxy
# nextcloud # nextcloud
nextcloud_version: stable nextcloud:
nextcloud_admin: admin DOMAIN: cloud.local.krislamo.org
nextcloud_pass: password DB_PASSWD: password
nextcloud_domain: cloud.local.krislamo.org ADMIN_PASSWD: password
nextcloud_dbversion: latest
nextcloud_dbpass: password
# jenkins
jenkins_version: lts
jenkins_domain: jenkins.local.krislamo.org
# prometheus (includes grafana)
prom_version: latest
prom_domain: prom.local.krislamo.org
grafana_version: latest
grafana_domain: grafana.local.krislamo.org
prom_targets: "['10.0.2.15:9100']"
# nginx
nginx_domain: nginx.local.krislamo.org
nginx_name: staticsite
nginx_repo_url: https://git.krislamo.org/kris/example-website/
nginx_auth: admin:$apr1$T1l.BCFz$Jyg8msXYEAUi3LLH39I9d1 # admin:admin
nginx_version: latest

14
dev/host_vars/podman.yml Normal file
View File

@@ -0,0 +1,14 @@
# base
allow_reboot: false
manage_network: false
users:
kris:
uid: 1001
gid: 1001
home: true
# podman
user_namespaces:
- kris

8
dev/podman.yml Normal file
View File

@@ -0,0 +1,8 @@
- name: Install Podman server
hosts: all
become: true
vars_files:
- host_vars/podman.yml
roles:
- base
- podman

View File

@@ -4,4 +4,5 @@
roles: roles:
- base - base
- jenkins - jenkins
- proxy
- docker - docker

View File

@@ -3,9 +3,9 @@
become: true become: true
roles: roles:
- base - base
- jenkins
- docker - docker
- mariadb
- traefik - traefik
- nextcloud - nextcloud
- jenkins - proxy
- prometheus
- nginx

View File

@@ -26,7 +26,7 @@
ansible.builtin.template: ansible.builtin.template:
src: smb.conf.j2 src: smb.conf.j2
dest: /etc/samba/smb.conf dest: /etc/samba/smb.conf
mode: "700" mode: "644"
notify: restart_samba notify: restart_samba
- name: Start smbd and enable on boot - name: Start smbd and enable on boot

View File

@@ -80,8 +80,10 @@
state: present state: present
uid: "{{ item.value.uid }}" uid: "{{ item.value.uid }}"
group: "{{ item.value.gid }}" group: "{{ item.value.gid }}"
groups: "{{ item.value.groups | default([]) }}"
shell: "{{ item.value.shell | default('/bin/bash') }}" shell: "{{ item.value.shell | default('/bin/bash') }}"
create_home: "{{ item.value.home | default(false) }}" create_home: "{{ item.value.home | default(false) }}"
home: "{{ item.value.homedir | default('/home/' + item.key) }}"
system: "{{ item.value.system | default(false) }}" system: "{{ item.value.system | default(false) }}"
loop: "{{ users | dict2items }}" loop: "{{ users | dict2items }}"
loop_control: loop_control:

View File

@@ -18,6 +18,28 @@
src: /etc/wireguard/privatekey src: /etc/wireguard/privatekey
register: wgkey register: wgkey
- name: Check if WireGuard preshared key file exists
ansible.builtin.stat:
path: /etc/wireguard/presharedkey-{{ item.name }}
loop: "{{ wireguard.peers }}"
loop_control:
label: "{{ item.name }}"
register: presharedkey_files
- name: Grab WireGuard preshared key for configuration
ansible.builtin.slurp:
src: /etc/wireguard/presharedkey-{{ item.item.name }}
register: wgshared
loop: "{{ presharedkey_files.results }}"
loop_control:
label: "{{ item.item.name }}"
when: item.stat.exists
- name: Grab WireGuard private key for configuration
ansible.builtin.slurp:
src: /etc/wireguard/privatekey
register: wgkey
- name: Install WireGuard configuration - name: Install WireGuard configuration
ansible.builtin.template: ansible.builtin.template:
src: wireguard.j2 src: wireguard.j2

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,7 +1,10 @@
bitwarden_name: bitwarden bitwarden_name: bitwarden
bitwarden_root: "/var/lib/{{ bitwarden_name }}" bitwarden_user: bitwarden
bitwarden_root: /home/bitwarden
bitwarden_logs_identity: "{{ bitwarden_root }}/bwdata/logs/identity/Identity" bitwarden_logs_identity: "{{ bitwarden_root }}/bwdata/logs/identity/Identity"
bitwarden_logs_identity_date: "{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}" bitwarden_logs_identity_date:
"{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{
ansible_date_time.day }}"
bitwarden_database: "{{ bitwarden_name }}" bitwarden_database: "{{ bitwarden_name }}"
bitwarden_realips: "172.16.0.0/12" bitwarden_realips: "172.16.0.0/12"
bitwarden_standalone: false bitwarden_standalone: false

View File

@@ -3,35 +3,39 @@
name: expect name: expect
state: present state: present
- name: Create Bitwarden directory
ansible.builtin.file:
path: "{{ bitwarden_root }}"
state: directory
mode: "755"
- name: Download Bitwarden script - name: Download Bitwarden script
ansible.builtin.get_url: ansible.builtin.get_url:
url: "https://raw.githubusercontent.com/\ url: "https://raw.githubusercontent.com/\
bitwarden/self-host/master/bitwarden.sh" bitwarden/self-host/master/bitwarden.sh"
dest: "{{ bitwarden_root }}" dest: "{{ bitwarden_root }}"
owner: "{{ bitwarden_user }}"
group: "{{ bitwarden_user }}"
mode: u+x mode: u+x
- name: Install Bitwarden script wrapper - name: Install Bitwarden script wrapper
ansible.builtin.template: ansible.builtin.template:
src: bw_wrapper.j2 src: bw_wrapper.j2
dest: "{{ bitwarden_root }}/bw_wrapper" dest: "{{ bitwarden_root }}/bw_wrapper"
owner: "{{ bitwarden_user }}"
group: "{{ bitwarden_user }}"
mode: u+x mode: u+x
- name: Run Bitwarden installation script - name: Run Bitwarden installation script
ansible.builtin.command: "{{ bitwarden_root }}/bw_wrapper" ansible.builtin.command: "{{ bitwarden_root }}/bw_wrapper"
args: args:
creates: "{{ bitwarden_root }}/bwdata/config.yml" creates: "{{ bitwarden_root }}/bwdata/config.yml"
become_user: "{{ bitwarden_user }}"
become: true
- name: Install compose override - name: Install compose override
ansible.builtin.template: ansible.builtin.template:
src: compose.override.yml.j2 src: compose.override.yml.j2
dest: "{{ bitwarden_root }}/bwdata/docker/docker-compose.override.yml" dest: "{{ bitwarden_root }}/bwdata/docker/docker-compose.override.yml"
owner: "{{ bitwarden_user }}"
group: "{{ bitwarden_user }}"
mode: "644" mode: "644"
become_user: "{{ bitwarden_user }}"
become: true
when: bitwarden_override | default(true) when: bitwarden_override | default(true)
notify: rebuild_bitwarden notify: rebuild_bitwarden
@@ -40,6 +44,8 @@
path: "{{ bitwarden_root }}/bwdata/config.yml" path: "{{ bitwarden_root }}/bwdata/config.yml"
regexp: "^http_port: 80$" regexp: "^http_port: 80$"
replace: "http_port: {{ bitwarden_http_port | default('127.0.0.1:9080') }}" replace: "http_port: {{ bitwarden_http_port | default('127.0.0.1:9080') }}"
become_user: "{{ bitwarden_user }}"
become: true
when: not bitwarden_standalone when: not bitwarden_standalone
notify: rebuild_bitwarden notify: rebuild_bitwarden
@@ -47,7 +53,10 @@
ansible.builtin.replace: ansible.builtin.replace:
path: "{{ bitwarden_root }}/bwdata/config.yml" path: "{{ bitwarden_root }}/bwdata/config.yml"
regexp: "^https_port: 443$" regexp: "^https_port: 443$"
replace: "https_port: {{ bitwarden_https_port | default('127.0.0.1:9443') }}" replace:
"https_port: {{ bitwarden_https_port | default('127.0.0.1:9443') }}"
become_user: "{{ bitwarden_user }}"
become: true
when: not bitwarden_standalone when: not bitwarden_standalone
notify: rebuild_bitwarden notify: rebuild_bitwarden
@@ -56,6 +65,8 @@
path: "{{ bitwarden_root }}/bwdata/config.yml" path: "{{ bitwarden_root }}/bwdata/config.yml"
regexp: "^ssl_managed_lets_encrypt: true$" regexp: "^ssl_managed_lets_encrypt: true$"
replace: "ssl_managed_lets_encrypt: false" replace: "ssl_managed_lets_encrypt: false"
become_user: "{{ bitwarden_user }}"
become: true
when: not bitwarden_standalone or not bitwarden_production when: not bitwarden_standalone or not bitwarden_production
notify: rebuild_bitwarden notify: rebuild_bitwarden
@@ -64,6 +75,8 @@
path: "{{ bitwarden_root }}/bwdata/config.yml" path: "{{ bitwarden_root }}/bwdata/config.yml"
regexp: "^ssl: true$" regexp: "^ssl: true$"
replace: "ssl: false" replace: "ssl: false"
become_user: "{{ bitwarden_user }}"
become: true
when: not bitwarden_standalone when: not bitwarden_standalone
notify: rebuild_bitwarden notify: rebuild_bitwarden
@@ -72,12 +85,16 @@
path: "{{ bitwarden_root }}/bwdata/config.yml" path: "{{ bitwarden_root }}/bwdata/config.yml"
line: "- {{ bitwarden_realips }}" line: "- {{ bitwarden_realips }}"
insertafter: "^real_ips" insertafter: "^real_ips"
become_user: "{{ bitwarden_user }}"
become: true
notify: rebuild_bitwarden notify: rebuild_bitwarden
- name: Install Bitwarden systemd service - name: Install Bitwarden systemd service
ansible.builtin.template: ansible.builtin.template:
src: bitwarden.service.j2 src: bitwarden.service.j2
dest: "/etc/systemd/system/{{ bitwarden_name }}.service" dest: "/etc/systemd/system/{{ bitwarden_name }}.service"
owner: "{{ bitwarden_user }}"
group: "{{ bitwarden_user }}"
mode: "644" mode: "644"
register: bitwarden_systemd register: bitwarden_systemd
notify: rebuild_bitwarden notify: rebuild_bitwarden
@@ -86,6 +103,8 @@
ansible.builtin.file: ansible.builtin.file:
path: "{{ bitwarden_logs_identity }}" path: "{{ bitwarden_logs_identity }}"
state: directory state: directory
owner: "{{ bitwarden_user }}"
group: "{{ bitwarden_user }}"
mode: "755" mode: "755"
notify: touch_bitwarden notify: touch_bitwarden

View File

@@ -24,15 +24,21 @@
- name: Install/uninstall Docker from Debian repositories - name: Install/uninstall Docker from Debian repositories
ansible.builtin.apt: ansible.builtin.apt:
name: ['docker.io', 'docker-compose', 'containerd', 'runc'] name: ["docker.io", "docker-compose", "containerd", "runc"]
state: "{{ 'absent' if docker_official else 'present' }}" state: "{{ 'absent' if docker_official else 'present' }}"
autoremove: true autoremove: true
update_cache: true update_cache: true
- name: Install/uninstall Docker from Docker repositories - name: Install/uninstall Docker from Docker repositories
ansible.builtin.apt: ansible.builtin.apt:
name: ['docker-ce', 'docker-ce-cli', 'containerd.io', name:
'docker-buildx-plugin', 'docker-compose-plugin'] [
"docker-ce",
"docker-ce-cli",
"containerd.io",
"docker-buildx-plugin",
"docker-compose-plugin",
]
state: "{{ 'present' if docker_official else 'absent' }}" state: "{{ 'present' if docker_official else 'absent' }}"
autoremove: true autoremove: true
update_cache: true update_cache: true
@@ -135,14 +141,6 @@
label: "{{ item.name }}" label: "{{ item.name }}"
when: docker_compose_deploy is defined and item.env is defined when: docker_compose_deploy is defined and item.env is defined
- name: Add users to docker group
ansible.builtin.user:
name: "{{ item }}"
groups: docker
append: true
loop: "{{ docker_users }}"
when: docker_users is defined
- name: Start Docker and enable on boot - name: Start Docker and enable on boot
ansible.builtin.service: ansible.builtin.service:
name: docker name: docker

View File

@@ -15,7 +15,7 @@ services:
networks: networks:
- traefik - traefik
labels: labels:
- "traefik.http.routers.{{ jellyfin_router }}.rule=Host(`{{ jellyfin_domain }}`)" - "traefik.http.routers.{{ jellyfin_router }}.rule=Host({{ jellyfin_domains }})"
{% if traefik_http_only %} {% if traefik_http_only %}
- "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web" - "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web"
{% else %} {% else %}

View File

@@ -16,6 +16,12 @@
regex: "^bind-address" regex: "^bind-address"
line: "bind-address = {{ ansible_facts.docker0.ipv4.address }}" line: "bind-address = {{ ansible_facts.docker0.ipv4.address }}"
notify: restart_mariadb notify: restart_mariadb
when: ansible_facts.docker0 is defined
- name: Flush handlers to ensure MariaDB restarts immediately
ansible.builtin.meta: flush_handlers
tags: restart_mariadb
when: ansible_facts.docker0 is defined
- name: Allow database connections from Docker - name: Allow database connections from Docker
community.general.ufw: community.general.ufw:

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,62 @@
- name: Create Nextcloud network - name: Install MySQL module for Ansible
community.general.docker_network: ansible.builtin.apt:
name: "{{ nextcloud_container }}" name: python3-pymysql
state: present
- name: Start Nextcloud's database container - name: Create Nextcloud database
community.general.docker_container: community.mysql.mysql_db:
name: "{{ nextcloud_dbcontainer }}" name: "{{ nextcloud.DB_NAME | default('nextcloud') }}"
image: mariadb:{{ nextcloud_dbversion }} state: present
login_unix_socket: /var/run/mysqld/mysqld.sock
- name: Create Nextcloud database user
community.mysql.mysql_user:
name: "{{ nextcloud.DB_USER | default('nextcloud') }}"
password: "{{ nextcloud.DB_PASSWD }}"
host: '%'
state: present
priv: "{{ nextcloud.DB_NAME | default('nextcloud') }}.*:ALL"
login_unix_socket: /var/run/mysqld/mysqld.sock
- name: Start Nextcloud service and enable on boot
ansible.builtin.service:
name: "{{ docker_compose_service }}@{{ nextcloud_name }}"
state: started state: started
restart_policy: always enabled: true
volumes: "{{ nextcloud_dbroot }}:/var/lib/mysql" when: nextcloud.ENABLE | default('false')
networks_cli_compatible: true
networks:
- name: "{{ nextcloud_container }}"
env:
MYSQL_RANDOM_ROOT_PASSWORD: "true"
MYSQL_DATABASE: "{{ nextcloud_dbname }}"
MYSQL_USER: "{{ nextcloud_dbuser }}"
MYSQL_PASSWORD: "{{ nextcloud_dbpass }}"
- name: Start Nextcloud container
community.general.docker_container:
name: "{{ nextcloud_container }}"
image: nextcloud:{{ nextcloud_version }}
state: started
restart_policy: always
volumes: "{{ nextcloud_root }}:/var/www/html"
networks_cli_compatible: true
networks:
- name: "{{ nextcloud_container }}"
- name: traefik
env:
PHP_MEMORY_LIMIT: 1024M
labels:
traefik.http.routers.nextcloud.rule: "Host(`{{ nextcloud_domain }}`)"
traefik.http.routers.nextcloud.entrypoints: websecure
traefik.http.routers.nextcloud.tls.certresolver: letsencrypt
traefik.http.routers.nextcloud.middlewares: "securehttps@file,nextcloud-webdav"
traefik.http.middlewares.nextcloud-webdav.redirectregex.regex: "https://(.*)/.well-known/(card|cal)dav"
traefik.http.middlewares.nextcloud-webdav.redirectregex.replacement: "https://${1}/remote.php/dav/"
traefik.http.middlewares.nextcloud-webdav.redirectregex.permanent: "true"
traefik.docker.network: traefik
traefik.enable: "true"
- name: Grab Nextcloud database container information
community.general.docker_container_info:
name: "{{ nextcloud_dbcontainer }}"
register: nextcloud_dbinfo
- name: Grab Nextcloud container information - name: Grab Nextcloud container information
community.general.docker_container_info: community.general.docker_container_info:
name: "{{ nextcloud_container }}" name: "{{ nextcloud_name }}"
register: nextcloud_info register: nextcloud_info
- name: Wait for Nextcloud to become available - name: Wait for Nextcloud to become available
ansible.builtin.wait_for: ansible.builtin.wait_for:
host: "{{ nextcloud_info.container.NetworkSettings.Networks.traefik.IPAddress }}" host: "{{ nextcloud_info.container.NetworkSettings.Networks.traefik.IPAddress }}"
delay: 10
port: 80 port: 80
- name: Check Nextcloud status - name: Check Nextcloud status
ansible.builtin.command: "docker exec --user www-data {{ nextcloud_container }} ansible.builtin.command: >
php occ status" docker exec --user www-data "{{ nextcloud_name }}" php occ status
register: nextcloud_status register: nextcloud_status
args: changed_when: false
removes: "{{ nextcloud_root }}/config/CAN_INSTALL"
- name: Wait for Nextcloud database to become available
ansible.builtin.wait_for:
host: "{{ nextcloud_dbinfo.container.NetworkSettings.Networks.nextcloud.IPAddress }}"
port: 3306
- name: Install Nextcloud - name: Install Nextcloud
ansible.builtin.command: 'docker exec --user www-data {{ nextcloud_container }} ansible.builtin.command: >
php occ maintenance:install docker exec --user www-data {{ nextcloud_name }}
--database "mysql" php occ maintenance:install
--database-host "{{ nextcloud_dbcontainer }}" --database "mysql"
--database-name "{{ nextcloud_dbname }}" --database-host "{{ nextcloud.DB_HOST | default('host.docker.internal') }}"
--database-user "{{ nextcloud_dbuser }}" --database-name "{{ nextcloud.DB_NAME | default('nextcloud') }}"
--database-pass "{{ nextcloud_dbpass }}" --database-user "{{ nextcloud.DB_USER | default('nextcloud') }}"
--admin-user "{{ nextcloud_admin }}" --database-pass "{{ nextcloud.DB_PASSWD }}"
--admin-pass "{{ nextcloud_pass }}"' --admin-user "{{ nextcloud.ADMIN_USER | default('admin') }}"
--admin-pass "{{ nextcloud.ADMIN_PASSWD }}"
register: nextcloud_install register: nextcloud_install
when: when: nextcloud_status.stderr[:26] == "Nextcloud is not installed"
- nextcloud_status.stdout[:26] == "Nextcloud is not installed" changed_when: nextcloud_install.stdout == "Nextcloud was successfully installed"
- nextcloud_domain is defined notify: install_nextcloud
- name: Set Nextcloud's Trusted Proxy
ansible.builtin.command: 'docker exec --user www-data {{ nextcloud_container }}
php occ config:system:set trusted_proxies 0
--value="{{ traefik_name }}"'
when: nextcloud_install.changed
- name: Set Nextcloud's Trusted Domain
ansible.builtin.command: 'docker exec --user www-data {{ nextcloud_container }}
php occ config:system:set trusted_domains 0
--value="{{ nextcloud_domain }}"'
when: nextcloud_install.changed
- name: Preform Nextcloud database maintenance
ansible.builtin.command: "docker exec --user www-data {{ nextcloud_container }} {{ item }}"
loop:
- "php occ maintenance:mode --on"
- "php occ db:add-missing-indices"
- "php occ db:convert-filecache-bigint"
- "php occ maintenance:mode --off"
when: nextcloud_install.changed
- name: Install Nextcloud background jobs cron - name: Install Nextcloud background jobs cron
ansible.builtin.cron: ansible.builtin.cron:
@@ -111,8 +64,3 @@
minute: "*/5" minute: "*/5"
job: "/usr/bin/docker exec -u www-data nextcloud /usr/local/bin/php -f /var/www/html/cron.php" job: "/usr/bin/docker exec -u www-data nextcloud /usr/local/bin/php -f /var/www/html/cron.php"
user: root user: root
- name: Remove Nextcloud's CAN_INSTALL file
ansible.builtin.file:
path: "{{ nextcloud_root }}/config/CAN_INSTALL"
state: absent

View File

@@ -0,0 +1,62 @@
- name: Install Podman
ansible.builtin.apt:
name: ["podman", "podman-compose", "podman-docker"]
state: present
- name: Get user info for namespace users
ansible.builtin.getent:
database: passwd
key: "{{ item }}"
loop: "{{ user_namespaces }}"
register: user_info
- name: Configure /etc/subuid for rootless users
ansible.builtin.lineinfile:
path: "/etc/subuid"
line:
"{{ item.item }}:{{ 100000 +
((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536)
}}:65536"
regexp: "^{{ item.item }}:"
create: true
backup: true
mode: "0644"
loop: "{{ user_info.results }}"
- name: Configure /etc/subgid for rootless users
ansible.builtin.lineinfile:
path: "/etc/subgid"
line:
"{{ item.item }}:{{ 100000 +
((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536)
}}:65536"
regexp: "^{{ item.item }}:"
create: true
backup: true
mode: "0644"
loop: "{{ user_info.results }}"
- name: Create nodocker file to disable Docker CLI emulation message
ansible.builtin.file:
path: /etc/containers/nodocker
state: touch
owner: root
group: root
mode: "0644"
- name: Create global containers config directory
ansible.builtin.file:
path: /etc/containers
state: directory
mode: "0755"
- name: Configure global containers.conf for rootless
ansible.builtin.copy:
content: |
[engine]
cgroup_manager = "cgroupfs"
events_logger = "journald"
runtime = "crun"
dest: /etc/containers/containers.conf
mode: "0644"
backup: true

View File

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

View File

@@ -10,6 +10,19 @@
state: started state: started
enabled: true enabled: true
- name: Check for cached dhparams.pem file
ansible.builtin.stat:
path: "{{ cached_dhparams_pem }}"
register: dhparams_file
- name: Copy cached dhparams.pem to /etc/ssl/
ansible.builtin.copy:
src: "{{ cached_dhparams_pem }}"
dest: /etc/ssl/dhparams.pem
mode: "600"
remote_src: true
when: dhparams_file.stat.exists
- name: Generate DH Parameters - name: Generate DH Parameters
community.crypto.openssl_dhparam: community.crypto.openssl_dhparam:
path: /etc/ssl/dhparams.pem path: /etc/ssl/dhparams.pem
@@ -32,10 +45,11 @@
register: nginx_sites register: nginx_sites
- name: Generate self-signed certificate - name: Generate self-signed certificate
ansible.builtin.command: 'openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes \ ansible.builtin.command:
-subj "/C=US/ST=Local/L=Local/O=Org/OU=IT/CN=example.com" \ 'openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes \
-keyout /etc/ssl/private/nginx-selfsigned.key \ -subj "/C=US/ST=Local/L=Local/O=Org/OU=IT/CN=example.com" \
-out /etc/ssl/certs/nginx-selfsigned.crt' -keyout /etc/ssl/private/nginx-selfsigned.key \
-out /etc/ssl/certs/nginx-selfsigned.crt'
args: args:
creates: /etc/ssl/certs/nginx-selfsigned.crt creates: /etc/ssl/certs/nginx-selfsigned.crt
when: proxy.production is not defined or not proxy.production when: proxy.production is not defined or not proxy.production
@@ -43,15 +57,22 @@
- name: Install LE's certbot - name: Install LE's certbot
ansible.builtin.apt: ansible.builtin.apt:
name: ['certbot', 'python3-certbot-dns-cloudflare'] name: ["certbot", "python3-certbot-dns-cloudflare"]
state: present state: present
when: proxy.production is defined and proxy.production when: proxy.production is defined and proxy.production
- name: Grab Cloudflare API token for configuration
ansible.builtin.slurp:
src: /root/.cloudflare-api
register: cfapi
when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined
- name: Install Cloudflare API token - name: Install Cloudflare API token
ansible.builtin.template: ansible.builtin.template:
src: cloudflare.ini.j2 src: cloudflare.ini.j2
dest: /root/.cloudflare.ini dest: /root/.cloudflare.ini
mode: "400" mode: "400"
diff: false
when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined
- name: Create nginx post renewal hook directory - name: Create nginx post renewal hook directory
@@ -65,19 +86,19 @@
ansible.builtin.copy: ansible.builtin.copy:
src: reload-nginx.sh src: reload-nginx.sh
dest: /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh dest: /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
mode: '0755' mode: "0755"
when: proxy.production is defined and proxy.production when: proxy.production is defined and proxy.production
- name: Run Cloudflare DNS-01 challenges on wildcard domains - name: Run Cloudflare DNS-01 challenges on wildcard domains
ansible.builtin.shell: '/usr/bin/certbot certonly \ ansible.builtin.shell: '/usr/bin/certbot certonly \
--non-interactive \ --non-interactive \
--agree-tos \ --agree-tos \
--email "{{ proxy.dns_cloudflare.email }}" \ --email "{{ proxy.dns_cloudflare.email }}" \
--dns-cloudflare \ --dns-cloudflare \
--dns-cloudflare-credentials /root/.cloudflare.ini \ --dns-cloudflare-credentials /root/.cloudflare.ini \
-d "*.{{ item }}" \ -d "*.{{ item }}" \
-d "{{ item }}" \ -d "{{ item }}" \
{{ proxy.dns_cloudflare.opts | default("") }}' {{ proxy.dns_cloudflare.opts | default("") }}'
args: args:
creates: "/etc/letsencrypt/live/{{ item }}/fullchain.pem" creates: "/etc/letsencrypt/live/{{ item }}/fullchain.pem"
loop: "{{ proxy.dns_cloudflare.wildcard_domains }}" loop: "{{ proxy.dns_cloudflare.wildcard_domains }}"

View File

@@ -1,2 +1,2 @@
# Cloudflare API token used by Certbot # Cloudflare API token used by Certbot
dns_cloudflare_api_token = {{ proxy.dns_cloudflare.api_token }} dns_cloudflare_api_token = {{ cfapi['content'] | b64decode | trim }}

View File

@@ -28,14 +28,20 @@ server {
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
{% endif %} {% endif %}
{% if item.hsts is defined %}
add_header Strict-Transport-Security "max-age={{ item.hsts }}" always;
{% endif %}
{% if item.client_max_body_size is defined %} {% if item.client_max_body_size is defined %}
client_max_body_size {{ item.client_max_body_size }}; client_max_body_size {{ item.client_max_body_size }};
{% endif %} {% endif %}
location / { location / {
{% if item.restrict is defined and item.restrict %} {% if item.hsts is defined %}
add_header Strict-Transport-Security "max-age={{ item.hsts }}" always;
{% endif %}
{% if item.allowedips is defined %}
{% for ip in item.allowedips %}
allow {{ ip }};
{% endfor %}
deny all;
{% endif %}
{% if item.restrict is defined and item.restrict %}
auth_basic "{{ item.restrict_name | default('Restricted Access') }}"; auth_basic "{{ item.restrict_name | default('Restricted Access') }}";
auth_basic_user_file {{ item.restrict_file | default('/etc/nginx/.htpasswd') }}; auth_basic_user_file {{ item.restrict_file | default('/etc/nginx/.htpasswd') }};
proxy_set_header Authorization ""; proxy_set_header Authorization "";
@@ -43,6 +49,7 @@ server {
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass {{ item.proxy_pass }}; proxy_pass {{ item.proxy_pass }};
{% if item.proxy_ssl_verify is defined and item.proxy_ssl_verify is false %} {% if item.proxy_ssl_verify is defined and item.proxy_ssl_verify is false %}
proxy_ssl_verify off; proxy_ssl_verify off;

View File

@@ -21,20 +21,6 @@
loop: "{{ traefik_external }}" loop: "{{ traefik_external }}"
when: traefik_external is defined when: traefik_external is defined
- name: Install Traefik's docker-compose file
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ traefik_root }}/docker-compose.yml"
mode: 0400
notify: restart_traefik
- name: Install Traefik's docker-compose variables
ansible.builtin.template:
src: compose-env.j2
dest: "{{ traefik_root }}/.env"
mode: 0400
notify: restart_traefik
- name: Install static Traefik configuration - name: Install static Traefik configuration
ansible.builtin.template: ansible.builtin.template:
src: traefik.yml.j2 src: traefik.yml.j2
@@ -42,8 +28,9 @@
mode: 0400 mode: 0400
notify: restart_traefik notify: restart_traefik
- name: Start and enable Traefik service - name: Start Traefik service and enable on boot
ansible.builtin.service: ansible.builtin.service:
name: "{{ docker_compose_service }}@{{ traefik_name }}" name: "{{ docker_compose_service }}@{{ traefik_name }}"
state: started state: started
enabled: true enabled: true
when: traefik.ENABLED | default('false')