Archive Legacy Setup And Add Ansible Control Plane
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
- name: Configure OpenVPN on ru-vps and VPN LXC
|
||||
hosts: vpn_openvpn
|
||||
gather_facts: true
|
||||
become: true
|
||||
roles:
|
||||
- openvpn_gateway
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
Reference in New Issue
Block a user