Archive Legacy Setup And Add Ansible Control Plane

This commit is contained in:
Dmitry
2026-07-08 12:47:37 +03:00
parent 841d56380b
commit 4bafa7d09e
203 changed files with 1663 additions and 11 deletions
-16
View File
@@ -1,16 +0,0 @@
- name: Base server setup
hosts: servers
gather_facts: true
become: false
tasks:
- name: Ping hosts
ansible.builtin.ping:
- name: Check expected LAN IP
ansible.builtin.assert:
that:
- expected_lan_ip in ansible_all_ipv4_addresses
fail_msg: "{{ inventory_hostname }} must have {{ expected_lan_ip }}; found: {{ ansible_all_ipv4_addresses | join(', ') }}"
success_msg: "{{ inventory_hostname }} has {{ expected_lan_ip }}"
when: expected_lan_ip is defined
+6
View File
@@ -0,0 +1,6 @@
- name: Configure unified bash profile
hosts: shell_hosts
gather_facts: true
become: true
roles:
- bash_config
@@ -0,0 +1,38 @@
- name: Bootstrap Ansible service account
hosts: shell_hosts
gather_facts: true
become: true
vars:
ansible_service_user: ansible
ansible_service_public_key_file: ~/.ssh/id_ed25519_homelab_ansible.pub
ansible_service_sudoers_file: /etc/sudoers.d/99-ansible-service-user
tasks:
- name: Read local Ansible service public key
ansible.builtin.set_fact:
ansible_service_public_key: "{{ lookup('file', ansible_service_public_key_file) }}"
delegate_to: localhost
become: false
- name: Ensure Ansible service user exists
ansible.builtin.user:
name: "{{ ansible_service_user }}"
shell: /bin/bash
create_home: true
state: present
- name: Install Ansible service SSH key
ansible.posix.authorized_key:
user: "{{ ansible_service_user }}"
key: "{{ ansible_service_public_key }}"
state: present
exclusive: true
- name: Allow passwordless sudo for Ansible service user
ansible.builtin.copy:
dest: "{{ ansible_service_sudoers_file }}"
owner: root
group: root
mode: "0440"
content: "{{ ansible_service_user }} ALL=(ALL) NOPASSWD: ALL\n"
validate: /usr/sbin/visudo -cf %s
@@ -0,0 +1,53 @@
- name: Bootstrap Proxmox API token for Ansible
hosts: mini-pc
gather_facts: false
become: true
vars:
pve_api_user: ansible@pve
pve_api_token_id: homelab
pve_api_role: Administrator
tasks:
- name: Ensure Proxmox API user exists
ansible.builtin.command: "pveum user add {{ pve_api_user }} --comment 'Ansible automation user'"
register: pve_user_add
changed_when: pve_user_add.rc == 0
failed_when:
- pve_user_add.rc != 0
- "'already exists' not in (pve_user_add.stderr | lower)"
- name: Grant Proxmox API user permissions
ansible.builtin.command: "pveum aclmod / -user {{ pve_api_user }} -role {{ pve_api_role }}"
changed_when: true
- name: Remove old Ansible token if present
ansible.builtin.command: "pveum user token remove {{ pve_api_user }} {{ pve_api_token_id }}"
register: pve_token_remove
changed_when: pve_token_remove.rc == 0
failed_when: false
no_log: true
- name: Create Proxmox API token
ansible.builtin.command: "pveum user token add {{ pve_api_user }} {{ pve_api_token_id }} --privsep 0 --comment 'HomeLab Ansible token' --output-format json"
register: pve_token_add
changed_when: true
no_log: true
- name: Store token data
ansible.builtin.set_fact:
pve_token_data: "{{ pve_token_add.stdout | from_json }}"
no_log: true
- name: Write local ansible/.env
ansible.builtin.copy:
dest: "{{ playbook_dir }}/../.env"
mode: "0600"
content: |
export PROXMOX_HOST={{ ansible_host }}
export PROXMOX_USER='{{ pve_api_user }}'
export PROXMOX_TOKEN_ID='{{ pve_api_token_id }}'
export PROXMOX_TOKEN_SECRET='{{ pve_token_data.value }}'
export PROXMOX_VALIDATE_CERTS=false
export PVE_LXC_OSTEMPLATE='local:vztmpl/debian-13-standard_13.0-1_amd64.tar.zst'
delegate_to: localhost
become: false
no_log: true
-10
View File
@@ -1,10 +0,0 @@
# Запускать один раз на новом сервере от имени root или пользователя с полным sudo:
# ansible-playbook -i inventory/hosts.yml playbooks/bootstrap.yml -K
#
# После выполнения: Ansible-плейбуки всё равно требуют -K (become),
# но деплой через GitOps (docker compose) работает без пароля.
- name: Bootstrap servers
hosts: servers
become: true
roles:
- bootstrap
+15
View File
@@ -0,0 +1,15 @@
- name: Check HomeLab Ansible connectivity
hosts: servers
gather_facts: true
become: false
tasks:
- name: Ping host
ansible.builtin.ping:
- name: Check expected LAN IP when defined
ansible.builtin.assert:
that:
- expected_lan_ip in ansible_facts.all_ipv4_addresses
fail_msg: "{{ inventory_hostname }} must have {{ expected_lan_ip }}; found: {{ ansible_facts.all_ipv4_addresses | join(', ') }}"
success_msg: "{{ inventory_hostname }} has {{ expected_lan_ip }}"
when: expected_lan_ip is defined
-119
View File
@@ -1,119 +0,0 @@
- name: Directory structure — cloud-pc
hosts: cloud-pc
become: true
vars:
data_user: ada
data_group: ada
tasks:
- name: Create base mount points
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
owner: "{{ data_user }}"
group: "{{ data_group }}"
mode: "0755"
loop: "{{ storage_mounts | default([]) }}"
- name: Mount base storage disks
ansible.posix.mount:
path: "{{ item.path }}"
src: "{{ item.src }}"
fstype: "{{ item.fstype }}"
opts: "{{ item.opts | default('defaults,nofail') }}"
state: mounted
loop: "{{ storage_mounts | default([]) }}"
- name: Create service data and config directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ data_user }}"
group: "{{ data_group }}"
mode: "0755"
loop:
- /opt/data/postgres
- /opt/data/nextcloud
- /opt/data/gitea
- /opt/data/gitea-runner
- /opt/data/syncthing
- /opt/data/zerotier
- /opt/samba/media
- /opt/samba/documents
- /opt/samba/backups_win
- /opt/configs
- /opt/configs/nextcloud/app
- /opt/configs/syncthing
- name: Create /opt/services
ansible.builtin.file:
path: /opt/services
state: directory
owner: "{{ data_user }}"
group: "{{ data_group }}"
mode: "0755"
- name: Create backup directories (3TB)
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ data_user }}"
group: "{{ data_group }}"
mode: "0755"
loop:
- /mnt/backup/restic/services
- /mnt/backup/restic/samba
- /mnt/backup/devices/proxmox
- /mnt/backup/devices/ada-x1
- name: Directory structure — mini-pc
hosts: mini-pc
become: true
vars:
data_user: ada
data_group: ada
tasks:
- name: Create service directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ data_user }}"
group: "{{ data_group }}"
mode: "0755"
loop:
- /opt/services
- /opt/data
- /opt/configs
- /opt/data/vaultwarden
- /opt/data/adguard/work
- /opt/data/caddy
- /opt/data/gitea-runner
- /opt/data/npm
- /opt/data/uptime-kuma
- /opt/data/zerotier
- /opt/configs/adguard
- /opt/configs/caddy
- /opt/configs/caddy/lego
- /opt/configs/npm/letsencrypt
- name: Directory structure — ru-vps
hosts: ru-vps
become: true
vars:
data_user: ada
data_group: ada
tasks:
- name: Create service directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ data_user }}"
group: "{{ data_group }}"
mode: "0755"
loop:
- /opt/services
- /opt/data
- /opt/configs
- /opt/data/caddy
- /opt/data/gitea-runner
- /opt/data/zerotier
- /opt/configs/caddy
+19
View File
@@ -0,0 +1,19 @@
- name: Check OpenVPN tunnel from ru-vps
hosts: ru-vps
gather_facts: false
tasks:
- name: Ping VPN LXC OpenVPN address
ansible.builtin.command: ping -c 3 -W 2 10.78.0.2
changed_when: false
- name: Check mini-pc PVE port through OpenVPN gateway
ansible.builtin.command: nc -vz -w 5 192.168.1.10 8006
changed_when: false
- name: Check cloud-pc PVE port through OpenVPN gateway
ansible.builtin.command: nc -vz -w 5 192.168.1.5 8006
changed_when: false
- name: Check PBS port through OpenVPN gateway
ansible.builtin.command: nc -vz -w 5 192.168.1.20 8007
changed_when: false
+197
View File
@@ -0,0 +1,197 @@
- name: Configure OpenVPN laptop access through ru-vps
hosts: ru-vps
gather_facts: true
become: true
vars:
laptop_profile_name: ada-x1
laptop_openvpn_dir: /etc/openvpn/homelab-laptop
laptop_openvpn_config: /etc/openvpn/homelab-laptop/server.conf
laptop_openvpn_key: /etc/openvpn/homelab-laptop/static.key
laptop_openvpn_service: homelab-openvpn-laptop
laptop_openvpn_port: 9443
laptop_openvpn_interface: tun1
laptop_openvpn_site_interface: tun0
laptop_openvpn_network_cidr: 10.79.0.0/30
laptop_openvpn_server_ip: 10.79.0.1
laptop_openvpn_client_ip: 10.79.0.2
laptop_openvpn_remote: 157.22.231.198
laptop_openvpn_client_config_local: "{{ playbook_dir }}/../generated/{{ laptop_profile_name }}.ovpn"
laptop_openvpn_home_routes:
- network: 192.168.1.5
netmask: 255.255.255.255
- network: 192.168.1.6
netmask: 255.255.255.254
- network: 192.168.1.8
netmask: 255.255.255.248
- network: 192.168.1.16
netmask: 255.255.255.240
- network: 192.168.1.32
netmask: 255.255.255.248
- network: 192.168.1.40
netmask: 255.255.255.255
tasks:
- name: Install OpenVPN packages
ansible.builtin.apt:
name:
- openvpn
- iptables
state: present
update_cache: true
- name: Ensure laptop OpenVPN config directory exists
ansible.builtin.file:
path: "{{ laptop_openvpn_dir }}"
state: directory
owner: root
group: root
mode: "0700"
- name: Generate laptop static key if missing
ansible.builtin.command: "openvpn --genkey secret {{ laptop_openvpn_key }}"
args:
creates: "{{ laptop_openvpn_key }}"
no_log: true
- name: Enable IPv4 forwarding on ru-vps
ansible.posix.sysctl:
name: net.ipv4.ip_forward
value: "1"
state: present
reload: true
- name: Allow laptop OpenVPN TCP in UFW
ansible.builtin.command: "ufw allow {{ laptop_openvpn_port }}/tcp"
register: ufw_allow_laptop_openvpn
changed_when: "'Rule added' in ufw_allow_laptop_openvpn.stdout or 'Rules updated' in ufw_allow_laptop_openvpn.stdout"
failed_when: false
- name: Render laptop OpenVPN server config
ansible.builtin.copy:
dest: "{{ laptop_openvpn_config }}"
owner: root
group: root
mode: "0600"
content: |
dev {{ laptop_openvpn_interface }}
ifconfig {{ laptop_openvpn_server_ip }} {{ laptop_openvpn_client_ip }}
secret {{ laptop_openvpn_key }}
cipher AES-256-CBC
auth SHA256
proto tcp-server
port {{ laptop_openvpn_port }}
persist-key
persist-tun
verb 3
keepalive 10 60
notify: restart laptop openvpn
- name: Render laptop OpenVPN up script
ansible.builtin.copy:
dest: "{{ laptop_openvpn_dir }}/up.sh"
owner: root
group: root
mode: "0700"
content: |
#!/bin/sh
iptables -t nat -C POSTROUTING -s {{ laptop_openvpn_network_cidr }} -d {{ homelab_lan_cidr }} -o {{ laptop_openvpn_site_interface }} -j MASQUERADE 2>/dev/null || \
iptables -t nat -A POSTROUTING -s {{ laptop_openvpn_network_cidr }} -d {{ homelab_lan_cidr }} -o {{ laptop_openvpn_site_interface }} -j MASQUERADE
notify: restart laptop openvpn
- name: Render laptop OpenVPN down script
ansible.builtin.copy:
dest: "{{ laptop_openvpn_dir }}/down.sh"
owner: root
group: root
mode: "0700"
content: |
#!/bin/sh
iptables -t nat -D POSTROUTING -s {{ laptop_openvpn_network_cidr }} -d {{ homelab_lan_cidr }} -o {{ laptop_openvpn_site_interface }} -j MASQUERADE 2>/dev/null || true
notify: restart laptop openvpn
- name: Render laptop OpenVPN systemd service
ansible.builtin.copy:
dest: "/etc/systemd/system/{{ laptop_openvpn_service }}.service"
owner: root
group: root
mode: "0644"
content: |
[Unit]
Description=HomeLab OpenVPN laptop access
After=network-online.target homelab-openvpn.service
Wants=network-online.target
Requires=homelab-openvpn.service
[Service]
Type=simple
ExecStartPre={{ laptop_openvpn_dir }}/up.sh
ExecStart=/usr/sbin/openvpn --config {{ laptop_openvpn_config }}
ExecStopPost={{ laptop_openvpn_dir }}/down.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
notify:
- reload systemd
- restart laptop openvpn
- name: Flush handlers before starting laptop OpenVPN
ansible.builtin.meta: flush_handlers
- name: Enable and start laptop OpenVPN
ansible.builtin.systemd:
name: "{{ laptop_openvpn_service }}"
state: started
enabled: true
- name: Read laptop static key for client profile
ansible.builtin.slurp:
src: "{{ laptop_openvpn_key }}"
register: laptop_openvpn_static_key_raw
no_log: true
- name: Ensure local generated directory exists
ansible.builtin.file:
path: "{{ playbook_dir }}/../generated"
state: directory
mode: "0700"
become: false
delegate_to: localhost
- name: Write local laptop OpenVPN profile
ansible.builtin.copy:
dest: "{{ laptop_openvpn_client_config_local }}"
mode: "0600"
content: |
client
dev tun
proto tcp-client
remote {{ laptop_openvpn_remote }} {{ laptop_openvpn_port }}
ifconfig {{ laptop_openvpn_client_ip }} {{ laptop_openvpn_server_ip }}
cipher AES-256-CBC
auth SHA256
persist-key
persist-tun
resolv-retry infinite
nobind
verb 3
{% for route in laptop_openvpn_home_routes %}
route {{ route.network }} {{ route.netmask }}
{% endfor %}
<secret>
{{ laptop_openvpn_static_key_raw.content | b64decode }}
</secret>
become: false
delegate_to: localhost
no_log: true
handlers:
- name: reload systemd
ansible.builtin.systemd:
daemon_reload: true
- name: restart laptop openvpn
ansible.builtin.systemd:
name: "{{ laptop_openvpn_service }}"
state: restarted
+6
View File
@@ -0,0 +1,6 @@
- name: Configure OpenVPN on ru-vps and VPN LXC
hosts: vpn_openvpn
gather_facts: true
become: true
roles:
- openvpn_gateway
+197
View File
@@ -0,0 +1,197 @@
- name: Create Gitea LXC on cloud-pc
hosts: cloud-pc
gather_facts: false
vars:
gitea_vmid: 141
gitea_hostname: gitea
gitea_ip: 192.168.1.25/24
gitea_gateway: 192.168.1.1
gitea_bridge: vmbr0
gitea_rootfs: data:32
gitea_host_data_dir: /opt/data/gitea
gitea_host_data_uid: 101000
gitea_host_data_gid: 101000
gitea_container_data_dir: /opt/gitea/data
gitea_ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
gitea_pubkey_file: ~/.ssh/id_ed25519_homelab.pub
handlers:
- name: restart gitea lxc
ansible.builtin.shell: "pct stop {{ gitea_vmid }} || true; pct start {{ gitea_vmid }}"
changed_when: true
tasks:
- name: Check if Gitea LXC exists
ansible.builtin.command: "pct config {{ gitea_vmid }}"
register: gitea_pct_config
changed_when: false
failed_when: false
- name: Install Gitea LXC SSH public key on PVE host
ansible.builtin.copy:
dest: /tmp/gitea-lxc.pub
owner: root
group: root
mode: "0600"
content: "{{ lookup('file', gitea_pubkey_file) }}\n"
when: gitea_pct_config.rc != 0
- name: Create Gitea LXC
ansible.builtin.command: >-
pct create {{ gitea_vmid }} {{ gitea_ostemplate }}
--hostname {{ gitea_hostname }}
--rootfs {{ gitea_rootfs }}
--cores 2
--memory 2048
--swap 1024
--net0 name=eth0,bridge={{ gitea_bridge }},gw={{ gitea_gateway }},ip={{ gitea_ip }},firewall=1
--nameserver 1.1.1.1
--unprivileged 1
--features nesting=1,keyctl=1
--onboot 1
--startup order=50
--cmode shell
--ssh-public-keys /tmp/gitea-lxc.pub
when: gitea_pct_config.rc != 0
- name: Start Gitea LXC
ansible.builtin.command: "pct start {{ gitea_vmid }}"
register: gitea_pct_start
changed_when: gitea_pct_start.rc == 0
failed_when: gitea_pct_start.rc not in [0, 255]
- name: Allow FUSE device in Gitea LXC config
ansible.builtin.lineinfile:
path: "/etc/pve/lxc/{{ gitea_vmid }}.conf"
line: "lxc.cgroup2.devices.allow: c 10:229 rwm"
state: present
notify: restart gitea lxc
- name: Bind mount FUSE device in Gitea LXC config
ansible.builtin.lineinfile:
path: "/etc/pve/lxc/{{ gitea_vmid }}.conf"
line: "lxc.mount.entry: /dev/fuse dev/fuse none bind,create=file"
state: present
notify: restart gitea lxc
- name: Bind mount Gitea data directory in LXC config
ansible.builtin.lineinfile:
path: "/etc/pve/lxc/{{ gitea_vmid }}.conf"
line: "mp0: {{ gitea_host_data_dir }},mp={{ gitea_container_data_dir }}"
state: present
notify: restart gitea lxc
- name: Ensure Gitea host data directory ownership matches unprivileged LXC uid map
ansible.builtin.file:
path: "{{ gitea_host_data_dir }}"
state: directory
owner: "{{ gitea_host_data_uid }}"
group: "{{ gitea_host_data_gid }}"
recurse: true
- name: Apply pending LXC config changes
ansible.builtin.meta: flush_handlers
- name: Wait for Gitea SSH through ru-vps
ansible.builtin.wait_for_connection:
timeout: 120
delegate_to: gitea
vars:
ansible_become: false
- name: Configure Docker and Gitea inside LXC
hosts: gitea
gather_facts: true
vars:
ansible_become: false
gitea_data_dir: /opt/gitea/data
gitea_image: gitea/gitea:latest
gitea_container_name: gitea
gitea_http_port: 3000
gitea_ssh_port: 2222
tasks:
- name: Install Docker packages
ansible.builtin.apt:
name:
- docker.io
- fuse-overlayfs
- sqlite3
- rsync
- ca-certificates
- curl
state: present
update_cache: true
- name: Ensure Docker config directory exists
ansible.builtin.file:
path: /etc/docker
state: directory
owner: root
group: root
mode: "0755"
- name: Configure Docker storage driver for unprivileged LXC
ansible.builtin.copy:
dest: /etc/docker/daemon.json
owner: root
group: root
mode: "0644"
content: |
{
"storage-driver": "fuse-overlayfs"
}
register: docker_daemon_config
- name: Ensure Docker service is enabled and running
ansible.builtin.systemd:
name: docker
state: "{{ 'restarted' if docker_daemon_config.changed else 'started' }}"
enabled: true
- name: Ensure Gitea data directory has container ownership
ansible.builtin.file:
path: "{{ gitea_data_dir }}"
state: directory
owner: "1000"
group: "1000"
mode: "0750"
- name: Install Gitea systemd unit
ansible.builtin.copy:
dest: /etc/systemd/system/gitea.service
owner: root
group: root
mode: "0644"
content: |
[Unit]
Description=Gitea container
After=docker.service
Requires=docker.service
[Service]
Restart=always
RestartSec=10
ExecStartPre=-/usr/bin/docker rm -f {{ gitea_container_name }}
ExecStart=/usr/bin/docker run --rm \
--name {{ gitea_container_name }} \
--pull always \
-p {{ gitea_http_port }}:3000 \
-p {{ gitea_ssh_port }}:22 \
-v {{ gitea_data_dir }}:/data \
-e USER_UID=1000 \
-e USER_GID=1000 \
{{ gitea_image }}
ExecStop=/usr/bin/docker stop {{ gitea_container_name }}
[Install]
WantedBy=multi-user.target
register: gitea_unit
- name: Reload systemd when Gitea unit changes
ansible.builtin.systemd:
daemon_reload: true
when: gitea_unit.changed
- name: Enable and start Gitea
ansible.builtin.systemd:
name: gitea
state: started
enabled: true
+174
View File
@@ -0,0 +1,174 @@
- name: Create Vaultwarden LXC on mini-pc
hosts: mini-pc
gather_facts: false
vars:
vaultwarden_vmid: 140
vaultwarden_hostname: vaultwarden
vaultwarden_ip: 192.168.1.24/24
vaultwarden_gateway: 192.168.1.1
vaultwarden_bridge: vmbr0
vaultwarden_rootfs: local-lvm:16
vaultwarden_ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
vaultwarden_pubkey_file: ~/.ssh/id_ed25519_homelab.pub
handlers:
- name: restart vaultwarden lxc
ansible.builtin.shell: "pct stop {{ vaultwarden_vmid }} || true; pct start {{ vaultwarden_vmid }}"
changed_when: true
tasks:
- name: Check if Vaultwarden LXC exists
ansible.builtin.command: "pct config {{ vaultwarden_vmid }}"
register: vaultwarden_pct_config
changed_when: false
failed_when: false
- name: Install Vaultwarden LXC SSH public key on PVE host
ansible.builtin.copy:
dest: /tmp/vaultwarden-lxc.pub
owner: root
group: root
mode: "0600"
content: "{{ lookup('file', vaultwarden_pubkey_file) }}\n"
when: vaultwarden_pct_config.rc != 0
- name: Create Vaultwarden LXC
ansible.builtin.command: >-
pct create {{ vaultwarden_vmid }} {{ vaultwarden_ostemplate }}
--hostname {{ vaultwarden_hostname }}
--rootfs {{ vaultwarden_rootfs }}
--cores 2
--memory 1024
--swap 512
--net0 name=eth0,bridge={{ vaultwarden_bridge }},gw={{ vaultwarden_gateway }},ip={{ vaultwarden_ip }},firewall=1
--nameserver 1.1.1.1
--unprivileged 1
--features nesting=1,keyctl=1
--onboot 1
--startup order=40
--cmode shell
--ssh-public-keys /tmp/vaultwarden-lxc.pub
when: vaultwarden_pct_config.rc != 0
- name: Start Vaultwarden LXC
ansible.builtin.command: "pct start {{ vaultwarden_vmid }}"
register: vaultwarden_pct_start
changed_when: vaultwarden_pct_start.rc == 0
failed_when: vaultwarden_pct_start.rc not in [0, 255]
- name: Allow FUSE device in Vaultwarden LXC config
ansible.builtin.lineinfile:
path: "/etc/pve/lxc/{{ vaultwarden_vmid }}.conf"
line: "lxc.cgroup2.devices.allow: c 10:229 rwm"
state: present
notify: restart vaultwarden lxc
- name: Bind mount FUSE device in Vaultwarden LXC config
ansible.builtin.lineinfile:
path: "/etc/pve/lxc/{{ vaultwarden_vmid }}.conf"
line: "lxc.mount.entry: /dev/fuse dev/fuse none bind,create=file"
state: present
notify: restart vaultwarden lxc
- name: Apply pending LXC config changes
ansible.builtin.meta: flush_handlers
- name: Wait for Vaultwarden SSH through ru-vps
ansible.builtin.wait_for_connection:
timeout: 120
delegate_to: vaultwarden
vars:
ansible_become: false
- name: Configure Docker and Vaultwarden inside LXC
hosts: vaultwarden
gather_facts: true
vars:
ansible_become: false
vaultwarden_data_dir: /opt/vaultwarden/data
vaultwarden_image: vaultwarden/server:latest
vaultwarden_container_name: vaultwarden
vaultwarden_http_port: 80
tasks:
- name: Install Docker packages
ansible.builtin.apt:
name:
- docker.io
- fuse-overlayfs
- sqlite3
- ca-certificates
- curl
state: present
update_cache: true
- name: Ensure Docker config directory exists
ansible.builtin.file:
path: /etc/docker
state: directory
owner: root
group: root
mode: "0755"
- name: Configure Docker storage driver for unprivileged LXC
ansible.builtin.copy:
dest: /etc/docker/daemon.json
owner: root
group: root
mode: "0644"
content: |
{
"storage-driver": "fuse-overlayfs"
}
register: docker_daemon_config
- name: Ensure Docker service is enabled and running
ansible.builtin.systemd:
name: docker
state: "{{ 'restarted' if docker_daemon_config.changed else 'started' }}"
enabled: true
- name: Ensure Vaultwarden data directory exists
ansible.builtin.file:
path: "{{ vaultwarden_data_dir }}"
state: directory
owner: root
group: root
mode: "0750"
- name: Install Vaultwarden systemd unit
ansible.builtin.copy:
dest: /etc/systemd/system/vaultwarden.service
owner: root
group: root
mode: "0644"
content: |
[Unit]
Description=Vaultwarden container
After=docker.service
Requires=docker.service
[Service]
Restart=always
RestartSec=10
ExecStartPre=-/usr/bin/docker rm -f {{ vaultwarden_container_name }}
ExecStart=/usr/bin/docker run --rm \
--name {{ vaultwarden_container_name }} \
--pull always \
-p {{ vaultwarden_http_port }}:80 \
-v {{ vaultwarden_data_dir }}:/data \
-e WEBSOCKET_ENABLED=true \
{{ vaultwarden_image }}
ExecStop=/usr/bin/docker stop {{ vaultwarden_container_name }}
[Install]
WantedBy=multi-user.target
register: vaultwarden_unit
- name: Reload systemd when Vaultwarden unit changes
ansible.builtin.systemd:
daemon_reload: true
when: vaultwarden_unit.changed
- name: Enable and start Vaultwarden
ansible.builtin.systemd:
name: vaultwarden
state: started
enabled: true
+38
View File
@@ -0,0 +1,38 @@
- name: Create wg-mini LXC on mini-pc
hosts: localhost
connection: local
gather_facts: false
roles:
- role: pve_lxc
vars:
pve_lxc_vmid: 132
pve_lxc_node: mini-pc
pve_lxc_hostname: wg-mini
pve_lxc_ip: 192.168.1.23/24
pve_lxc_gateway: 192.168.1.1
pve_lxc_storage: local-lvm
pve_lxc_disk: local-lvm:8
pve_lxc_ostemplate: "{{ lookup('env', 'PVE_LXC_OSTEMPLATE') | default('local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst', true) }}"
- name: Allow TUN device in wg-mini LXC config
hosts: mini-pc
gather_facts: false
become: true
handlers:
- name: restart wg-mini lxc
ansible.builtin.shell: pct stop 132 || true; pct start 132
changed_when: true
tasks:
- name: Allow /dev/net/tun device
ansible.builtin.lineinfile:
path: /etc/pve/lxc/132.conf
line: "lxc.cgroup2.devices.allow: c 10:200 rwm"
state: present
notify: restart wg-mini lxc
- name: Bind mount /dev/net/tun
ansible.builtin.lineinfile:
path: /etc/pve/lxc/132.conf
line: "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file"
state: present
notify: restart wg-mini lxc
-9
View File
@@ -1,9 +0,0 @@
- name: Install rclone
hosts: servers
become: true
tasks:
- name: Install rclone package
ansible.builtin.apt:
name: rclone
state: present
update_cache: true
-36
View File
@@ -1,36 +0,0 @@
- name: Install resticprofile
hosts: servers
become: true
tasks:
- name: Install restic package
ansible.builtin.apt:
name: restic
state: present
update_cache: true
- name: Create restic config directory
ansible.builtin.file:
path: /etc/restic
state: directory
owner: root
group: root
mode: "0755"
- name: Create resticprofile log directory
ansible.builtin.file:
path: /var/log/resticprofile
state: directory
owner: root
group: root
mode: "0755"
- name: Download resticprofile install script
ansible.builtin.get_url:
url: https://raw.githubusercontent.com/creativeprojects/resticprofile/master/install.sh
dest: /tmp/resticprofile-install.sh
mode: "0755"
- name: Install resticprofile binary
ansible.builtin.command:
cmd: /tmp/resticprofile-install.sh -b /usr/local/bin
creates: /usr/local/bin/resticprofile
+65
View File
@@ -0,0 +1,65 @@
- name: Configure Gitea reverse proxy on ru-vps
hosts: ru-vps
gather_facts: false
vars:
caddy_dir: /opt/services/ru-vps/caddy
caddyfile_path: /opt/services/ru-vps/caddy/Caddyfile
gitea_domain: git.ada-dev.ru
gitea_upstream: 192.168.1.25:3000
tasks:
- name: Ensure Caddy service directory exists
ansible.builtin.file:
path: "{{ caddy_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Configure Gitea Caddy site
ansible.builtin.blockinfile:
path: "{{ caddyfile_path }}"
create: true
owner: root
group: root
mode: "0644"
marker: "# {mark} ANSIBLE MANAGED GITEA SITE"
block: |
{{ gitea_domain }} {
reverse_proxy {{ gitea_upstream }}
}
register: gitea_caddy_site
- name: Remove legacy unmanaged Gitea Caddy site
ansible.builtin.replace:
path: "{{ caddyfile_path }}"
regexp: '(?ms)^git\.ada-dev\.ru \{\n\s*reverse_proxy 10\.122\.62\.51:3002\n\}\n+'
replace: ''
register: gitea_legacy_site
- name: Validate host Caddy config
ansible.builtin.command: caddy validate --config {{ caddyfile_path }}
changed_when: false
- name: Check Caddy container mounted config
ansible.builtin.command: docker exec caddy grep -F 'reverse_proxy {{ gitea_upstream }}' /etc/caddy/Caddyfile
register: gitea_container_caddyfile
changed_when: false
failed_when: false
- name: Restart Caddy when config changed or bind mount is stale
ansible.builtin.command: docker restart caddy
when: >-
gitea_caddy_site.changed or
gitea_legacy_site.changed or
gitea_container_caddyfile.rc != 0
- name: Validate Caddy container config after restart
ansible.builtin.command: docker exec caddy caddy validate --config /etc/caddy/Caddyfile
changed_when: false
- name: Check Gitea upstream from ru-vps
ansible.builtin.command: curl -fsS -o /dev/null -w '%{http_code}' http://{{ gitea_upstream }}/
register: gitea_upstream_http
changed_when: false
failed_when: gitea_upstream_http.stdout != '200'
@@ -0,0 +1,65 @@
- name: Configure Vaultwarden reverse proxy on ru-vps
hosts: ru-vps
gather_facts: false
vars:
caddy_dir: /opt/services/ru-vps/caddy
caddyfile_path: /opt/services/ru-vps/caddy/Caddyfile
vaultwarden_domain: pass.ada-dev.ru
vaultwarden_upstream: 192.168.1.24:80
tasks:
- name: Ensure Caddy service directory exists
ansible.builtin.file:
path: "{{ caddy_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Configure Vaultwarden Caddy site
ansible.builtin.blockinfile:
path: "{{ caddyfile_path }}"
create: true
owner: root
group: root
mode: "0644"
marker: "# {mark} ANSIBLE MANAGED VAULTWARDEN SITE"
block: |
{{ vaultwarden_domain }} {
reverse_proxy {{ vaultwarden_upstream }}
}
register: vaultwarden_caddy_site
- name: Remove legacy unmanaged Vaultwarden Caddy site
ansible.builtin.replace:
path: "{{ caddyfile_path }}"
regexp: '(?ms)^pass\.ada-dev\.ru \{\n\s*reverse_proxy 10\.122\.62\.95:10380\n\}\n+'
replace: ''
register: vaultwarden_legacy_site
- name: Validate host Caddy config
ansible.builtin.command: caddy validate --config {{ caddyfile_path }}
changed_when: false
- name: Check Caddy container mounted config
ansible.builtin.command: docker exec caddy grep -F 'reverse_proxy {{ vaultwarden_upstream }}' /etc/caddy/Caddyfile
register: vaultwarden_container_caddyfile
changed_when: false
failed_when: false
- name: Restart Caddy when config changed or bind mount is stale
ansible.builtin.command: docker restart caddy
when: >-
vaultwarden_caddy_site.changed or
vaultwarden_legacy_site.changed or
vaultwarden_container_caddyfile.rc != 0
- name: Validate Caddy container config after restart
ansible.builtin.command: docker exec caddy caddy validate --config /etc/caddy/Caddyfile
changed_when: false
- name: Check Vaultwarden upstream from ru-vps
ansible.builtin.command: curl -fsS -o /dev/null -w '%{http_code}' http://{{ vaultwarden_upstream }}/
register: vaultwarden_upstream_http
changed_when: false
failed_when: vaultwarden_upstream_http.stdout != '200'