stuff
This commit is contained in:
@@ -4,5 +4,6 @@ registry/
|
||||
.vault-password
|
||||
*.private
|
||||
*.secret
|
||||
playbooks/wireguard-ingress/clients/
|
||||
mail.txt
|
||||
containers/opentogethertube
|
||||
Vendored
+30
@@ -170,6 +170,36 @@
|
||||
"panel": "dedicated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Deploy: vaultwarden",
|
||||
"type": "shell",
|
||||
"command": "make deploy-vaultwarden",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Deploy: hetzner",
|
||||
"type": "shell",
|
||||
"command": "make deploy-hetzner",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Deploy: ingress-hardening",
|
||||
"type": "shell",
|
||||
"command": "make deploy-ingress-hardening",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build & Push: ott",
|
||||
"type": "shell",
|
||||
|
||||
@@ -8,4 +8,4 @@ push-%: build-%
|
||||
podman push $(REGISTRY)/bee/$*:latest
|
||||
|
||||
deploy-%:
|
||||
ansible-playbook -i $(INVENTORY) playbooks/$*/$*.yml --vault-password-file .vault-password
|
||||
ansible-playbook -i $(INVENTORY) playbooks/$*/$*.yml --vault-password-file .vault-password $(ARGS)
|
||||
@@ -12,7 +12,9 @@
|
||||
tasks:
|
||||
- name: Install rsync
|
||||
ansible.builtin.apt:
|
||||
name: rsync
|
||||
name:
|
||||
- rsync
|
||||
- sqlite3
|
||||
state: present
|
||||
|
||||
- name: Create backup directory
|
||||
@@ -33,6 +35,12 @@
|
||||
dest: /opt/backup/backupWeekly.sh
|
||||
mode: '0700'
|
||||
|
||||
- name: Copy restore test
|
||||
ansible.builtin.copy:
|
||||
src: restoreTest.sh
|
||||
dest: /opt/backup/restoreTest.sh
|
||||
mode: '0700'
|
||||
|
||||
- name: Copy passphrase
|
||||
ansible.builtin.template:
|
||||
src: passphrase.txt.j2
|
||||
@@ -61,3 +69,12 @@
|
||||
hour: '5'
|
||||
weekday: '0'
|
||||
job: /opt/backup/backupWeekly.sh >> /var/log/beepi-backup.log 2>&1
|
||||
|
||||
- name: Schedule weekly restore test
|
||||
ansible.builtin.cron:
|
||||
name: beepi restore test
|
||||
user: root
|
||||
minute: '0'
|
||||
hour: '6'
|
||||
weekday: '0'
|
||||
job: /opt/backup/restoreTest.sh >> /var/log/beepi-backup.log 2>&1
|
||||
|
||||
@@ -28,6 +28,7 @@ restore() {
|
||||
|
||||
systemctl --user --machine gitea@.host start gitea-db.service gitea-server.service || true
|
||||
systemctl --user --machine immich@.host start immich-db.service immich-redis.service immich-server.service || true
|
||||
systemctl --user --machine vaultwarden@.host start vaultwarden.service || true
|
||||
rm -f /home/immich/systemd-immich-*.tar
|
||||
}
|
||||
|
||||
@@ -69,4 +70,17 @@ systemctl --user --machine immich@.host start immich-db.service immich-redis.ser
|
||||
mkdir -p /opt/backup/beeserver/immich/
|
||||
mv /home/immich/systemd-immich-*.tar /opt/backup/beeserver/immich/
|
||||
|
||||
tar -czf - /opt/backup/beeserver | gpg --batch --passphrase-file /opt/backup/passphrase.txt -c -o /home/beeshare/raid/serverBackup/beeserver_daily_${now}.tar.gz.gpg
|
||||
systemctl --user --machine vaultwarden@.host stop vaultwarden.service
|
||||
rsync -aH /home/vaultwarden/data /opt/backup/beeserver/vaultwarden
|
||||
systemctl --user --machine vaultwarden@.host start vaultwarden.service
|
||||
|
||||
archive=/home/beeshare/raid/serverBackup/beeserver_daily_${now}.tar.gz.gpg
|
||||
|
||||
tar -czf - /opt/backup/beeserver | gpg --batch --passphrase-file /opt/backup/passphrase.txt -c -o ${archive}
|
||||
|
||||
if ! gpg --batch --passphrase-file /opt/backup/passphrase.txt -d ${archive} | tar -tzf - >/dev/null
|
||||
then
|
||||
echo "[${now}] verify failed, discarding ${archive}"
|
||||
rm -f ${archive}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -4,12 +4,18 @@ set -euo pipefail
|
||||
|
||||
now=$(date +"%Y%m%d%H%M")
|
||||
|
||||
tar -czf - /opt/backup/beeserver | gpg --batch --passphrase-file /opt/backup/passphrase.txt -c -o /home/beeshare/raid/serverBackup/beeserver_weekly_${now}.tar.gz.gpg
|
||||
archive=/home/beeshare/raid/serverBackup/beeserver_weekly_${now}.tar.gz.gpg
|
||||
|
||||
if [ -s /home/beeshare/raid/serverBackup/beeserver_weekly_${now}.tar.gz.gpg ]
|
||||
tar -czf - /opt/backup/beeserver | gpg --batch --passphrase-file /opt/backup/passphrase.txt -c -o ${archive}
|
||||
|
||||
if ! gpg --batch --passphrase-file /opt/backup/passphrase.txt -d ${archive} | tar -tzf - >/dev/null
|
||||
then
|
||||
rm -rf /opt/backup/beeserver
|
||||
echo "[${now}] verify failed, discarding ${archive} and keeping staging"
|
||||
rm -f ${archive}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf /opt/backup/beeserver
|
||||
|
||||
find /home/beeshare/raid/serverBackup -maxdepth 1 -name 'beeserver_weekly_*.tar.gz.gpg' -mtime +30 -delete
|
||||
find /home/beeshare/raid/serverBackup -maxdepth 1 -name 'beeserver_daily_*.tar.gz.gpg' -mtime +7 -delete
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
now=$(date +"%Y%m%d%H%M")
|
||||
backup_dir=/home/beeshare/raid/serverBackup
|
||||
image=docker.io/vaultwarden/server:1.37.1
|
||||
container=vaultwarden-restoretest
|
||||
port=18222
|
||||
work=$(mktemp -d)
|
||||
|
||||
cleanup() {
|
||||
podman rm -f ${container} >/dev/null 2>&1 || true
|
||||
rm -rf "${work}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
latest=$(ls -1t ${backup_dir}/beeserver_*.tar.gz.gpg | head -1)
|
||||
echo "[${now}] restore test using ${latest}"
|
||||
|
||||
gpg --batch --passphrase-file /opt/backup/passphrase.txt -d "${latest}" \
|
||||
| tar -xzf - -C "${work}" opt/backup/beeserver/vaultwarden
|
||||
|
||||
data="${work}/opt/backup/beeserver/vaultwarden/data"
|
||||
|
||||
[[ -s "${data}/db.sqlite3" ]]
|
||||
[[ -s "${data}/rsa_key.pem" ]]
|
||||
echo " db and rsa_key present"
|
||||
|
||||
integrity=$(sqlite3 "${data}/db.sqlite3" "PRAGMA integrity_check;")
|
||||
[[ "${integrity}" == "ok" ]]
|
||||
echo " integrity_check ok"
|
||||
|
||||
users=$(sqlite3 "${data}/db.sqlite3" "select count(*) from users;")
|
||||
[[ "${users}" -ge 1 ]]
|
||||
echo " users ${users}"
|
||||
|
||||
email=$(sqlite3 "${data}/db.sqlite3" "select email from users limit 1;")
|
||||
|
||||
podman run -d --rm --name ${container} -p 127.0.0.1:${port}:80 -v "${data}":/data ${image} >/dev/null
|
||||
|
||||
for _ in $(seq 60)
|
||||
do
|
||||
if curl -sf http://127.0.0.1:${port}/api/config >/dev/null 2>&1
|
||||
then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
config=$(curl -sf http://127.0.0.1:${port}/api/config)
|
||||
[[ "${config}" == *'"version"'* ]]
|
||||
echo " api/config ok"
|
||||
|
||||
prelogin=$(curl -sf -X POST http://127.0.0.1:${port}/identity/accounts/prelogin \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"email\":\"${email}\"}")
|
||||
[[ "${prelogin}" == *[Kk]df* ]]
|
||||
echo " prelogin ok for ${email}"
|
||||
|
||||
echo "[${now}] restore test PASSED"
|
||||
@@ -97,14 +97,14 @@
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ user_info.uid }}/bus"
|
||||
ansible.builtin.systemd:
|
||||
name: gitea-server.service
|
||||
state: started
|
||||
state: restarted
|
||||
scope: user
|
||||
|
||||
- name: Debug
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Service status: systemctl --user --machine {{ user_info.name }}@.host status gitea-server"
|
||||
- "Service status: sudo systemctl --user --machine {{ user_info.name }}@.host status gitea-server"
|
||||
- "Read logs: sudo journalctl _UID={{ user_info.uid }} -n 200 --no-pager"
|
||||
- "Shell: machinectl shell {{ user_info.name }}@.host /bin/bash"
|
||||
- "Shell: sudo machinectl shell {{ user_info.name }}@.host /bin/bash"
|
||||
tags:
|
||||
- always
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
- name: Hetzner
|
||||
hosts: beepi
|
||||
become: true
|
||||
vars:
|
||||
user: hetzner
|
||||
user_home: /home/hetzner
|
||||
|
||||
hetzner_raid_mount: /home/beeshare/raid
|
||||
hetzner_port: 23
|
||||
|
||||
hetzner_paths:
|
||||
- src: /home/beeshare/raid/serverBackup
|
||||
dest: ./beepi
|
||||
- src: /home/beeshare/raid/foundry/backup
|
||||
dest: ./foundry
|
||||
|
||||
# Fill in after creating the storage box sub-account, then re-run
|
||||
hetzner_host: "u651287.your-storagebox.de"
|
||||
hetzner_user: "u651287"
|
||||
|
||||
tasks:
|
||||
- name: Install rsync
|
||||
ansible.builtin.apt:
|
||||
name: rsync
|
||||
state: present
|
||||
|
||||
- name: Create user
|
||||
ansible.builtin.user:
|
||||
name: "{{ user }}"
|
||||
home: "{{ user_home }}"
|
||||
shell: /usr/sbin/nologin
|
||||
create_home: true
|
||||
|
||||
- name: Create ssh directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ user_home }}/.ssh"
|
||||
state: directory
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: '0700'
|
||||
|
||||
- name: Generate ssh key
|
||||
ansible.builtin.command:
|
||||
cmd: "ssh-keygen -t ed25519 -N '' -C beepi-hetzner -f {{ user_home }}/.ssh/id_ed25519"
|
||||
creates: "{{ user_home }}/.ssh/id_ed25519"
|
||||
|
||||
- name: Set key ownership
|
||||
ansible.builtin.file:
|
||||
path: "{{ user_home }}/.ssh/{{ item.name }}"
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: "{{ item.mode }}"
|
||||
loop:
|
||||
- name: id_ed25519
|
||||
mode: '0600'
|
||||
- name: id_ed25519.pub
|
||||
mode: '0644'
|
||||
|
||||
- name: Scan storage box host key
|
||||
ansible.builtin.command:
|
||||
cmd: "ssh-keyscan -p {{ hetzner_port }} {{ hetzner_host }}"
|
||||
register: hetzner_hostkey
|
||||
changed_when: false
|
||||
when: hetzner_host | length > 0
|
||||
|
||||
- name: Pin known hosts
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ user_home }}/.ssh/known_hosts"
|
||||
content: "{{ hetzner_hostkey.stdout }}\n"
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: '0600'
|
||||
when: hetzner_host | length > 0
|
||||
|
||||
- name: Copy sync script
|
||||
ansible.builtin.template:
|
||||
src: hetznerSync.sh.j2
|
||||
dest: /opt/backup/hetznerSync.sh
|
||||
mode: '0700'
|
||||
when: hetzner_host | length > 0
|
||||
|
||||
- name: Schedule daily sync
|
||||
ansible.builtin.cron:
|
||||
name: beepi hetzner sync
|
||||
user: root
|
||||
minute: '0'
|
||||
hour: '7'
|
||||
job: /opt/backup/hetznerSync.sh >> /var/log/beepi-backup.log 2>&1
|
||||
when: hetzner_host | length > 0
|
||||
|
||||
- name: Debug
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Test manually: sudo /opt/backup/hetznerSync.sh"
|
||||
- "Read logs: sudo tail -50 /var/log/beepi-backup.log"
|
||||
tags:
|
||||
- always
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
now=$(date +"%Y%m%d%H%M")
|
||||
|
||||
if ! mountpoint -q {{ hetzner_raid_mount }}
|
||||
then
|
||||
echo "[${now}] {{ hetzner_raid_mount }} not mounted, refusing to sync"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sync_path() {
|
||||
local src=$1
|
||||
local dest=$2
|
||||
|
||||
if [ -z "$(ls -A ${src} 2>/dev/null)" ]
|
||||
then
|
||||
echo "[${now}] ${src} empty, refusing to sync"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[${now}] syncing ${src} to ${dest}"
|
||||
sudo -u {{ user }} rsync -a --delete --partial \
|
||||
-e "ssh -p {{ hetzner_port }} -i {{ user_home }}/.ssh/id_ed25519 -o UserKnownHostsFile={{ user_home }}/.ssh/known_hosts -o StrictHostKeyChecking=yes" \
|
||||
${src}/ \
|
||||
{{ hetzner_user }}@{{ hetzner_host }}:${dest}/
|
||||
}
|
||||
|
||||
echo "[${now}] offsite sync start"
|
||||
{% for path in hetzner_paths %}
|
||||
sync_path {{ path.src }} {{ path.dest }}
|
||||
{% endfor %}
|
||||
echo "[${now}] offsite sync done"
|
||||
@@ -5,7 +5,7 @@ After=immich-db.service immich-redis.service
|
||||
|
||||
[Container]
|
||||
ContainerName=immich-server
|
||||
Image=ghcr.io/immich-app/immich-server:release
|
||||
Image=ghcr.io/immich-app/immich-server:v3.1.0
|
||||
Network=immich.network
|
||||
PublishPort=127.0.0.1:2283:2283
|
||||
Volume=immich-upload.volume:/usr/src/app/upload
|
||||
|
||||
@@ -107,12 +107,12 @@
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ immich_user_info.uid }}/bus"
|
||||
ansible.builtin.systemd:
|
||||
name: immich-server.service
|
||||
state: started
|
||||
state: restarted
|
||||
scope: user
|
||||
|
||||
- name: Debug
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Service status: systemctl --user --machine {{ immich_user_info.name }}@.host status immich-server"
|
||||
- "Service status: sudo systemctl --user --machine {{ immich_user_info.name }}@.host status immich-server"
|
||||
- "Read logs: sudo journalctl _UID={{ immich_user_info.uid }} -n 200 --no-pager"
|
||||
- "Shell: machinectl shell {{ immich_user_info.name }}@.host /bin/bash"
|
||||
- "Shell: sudo machinectl shell {{ immich_user_info.name }}@.host /bin/bash"
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
- name: Ingress-hardening
|
||||
hosts: animeistrash
|
||||
become: true
|
||||
tasks:
|
||||
- name: Check for an authorized key
|
||||
become: false
|
||||
ansible.builtin.stat:
|
||||
path: "~/.ssh/authorized_keys"
|
||||
register: authorized_keys
|
||||
|
||||
- name: Refuse to lock out
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- authorized_keys.stat.exists
|
||||
- authorized_keys.stat.size > 0
|
||||
fail_msg: "No authorized_keys for the connecting user, refusing to disable password auth"
|
||||
|
||||
- name: Install packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- unattended-upgrades
|
||||
- needrestart
|
||||
state: present
|
||||
|
||||
- name: Harden sshd
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/ssh/sshd_config.d/00-hardening.conf
|
||||
content: |
|
||||
PermitRootLogin prohibit-password
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
MaxAuthTries 3
|
||||
LoginGraceTime 30
|
||||
X11Forwarding no
|
||||
AllowAgentForwarding no
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
validate: /usr/sbin/sshd -t -f %s
|
||||
notify: Reload sshd
|
||||
|
||||
- name: Enable unattended upgrades
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||
content: |
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
APT::Periodic::AutocleanInterval "7";
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Configure unattended upgrades
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/apt/apt.conf.d/52unattended-upgrades-local
|
||||
content: |
|
||||
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
Unattended-Upgrade::Automatic-Reboot "false";
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Restart services after library upgrades
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/needrestart/conf.d/99-auto.conf
|
||||
content: "$nrconf{restart} = 'a';\n"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Enable apt timers
|
||||
ansible.builtin.service:
|
||||
name: "{{ item }}"
|
||||
state: started
|
||||
enabled: true
|
||||
loop:
|
||||
- apt-daily.timer
|
||||
- apt-daily-upgrade.timer
|
||||
|
||||
- name: Debug
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Effective sshd config: sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|maxauthtries'"
|
||||
- "Dry-run upgrades: sudo unattended-upgrade --dry-run --debug"
|
||||
- "Read logs: sudo tail -50 /var/log/unattended-upgrades/unattended-upgrades.log"
|
||||
tags:
|
||||
- always
|
||||
|
||||
handlers:
|
||||
- name: Reload sshd
|
||||
ansible.builtin.service:
|
||||
name: ssh
|
||||
state: reloaded
|
||||
@@ -1,12 +1,30 @@
|
||||
- name: Letsencrypt
|
||||
hosts: beepi
|
||||
become: true
|
||||
vars:
|
||||
njalla_api_token: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
65666463616462633533663835383164353566326437333336616266333864333465613732346633
|
||||
6534633837373937393563633966343738316562653930610a346461613236653266303237306663
|
||||
66663234313832373939346539386633316465373861663862646537303662313564363038303164
|
||||
3865666132613130380a623737663837343438333837626338346565653735613435313164373663
|
||||
33316231366334623461303263386136656234613133373361353262346366636133396134663838
|
||||
3733353465643235653337306434396366623935303862633737
|
||||
|
||||
tasks:
|
||||
- name: Install Certbot
|
||||
ansible.builtin.apt:
|
||||
name: python3-certbot-nginx
|
||||
name:
|
||||
- python3-certbot-nginx
|
||||
- python3-pip
|
||||
state: present
|
||||
|
||||
- name: Install Njalla DNS plugin
|
||||
ansible.builtin.pip:
|
||||
name: certbot-dns-njalla
|
||||
state: present
|
||||
extra_args: --break-system-packages
|
||||
|
||||
- name: Request root certificates
|
||||
changed_when: true
|
||||
ansible.builtin.command: "certbot certonly --nginx -m secretbumblebee@proton.me --agree-tos -n --domains {{ item }}"
|
||||
@@ -19,6 +37,22 @@
|
||||
- gallery.secretbee.buzz
|
||||
- ott.secretbee.buzz
|
||||
|
||||
- name: Copy njalla credentials
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/letsencrypt/njalla.ini
|
||||
content: "dns_njalla_token={{ njalla_api_token }}\n"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
|
||||
- name: Request vault certificate
|
||||
changed_when: true
|
||||
ansible.builtin.command: >-
|
||||
certbot certonly -a dns-njalla
|
||||
--dns-njalla-credentials /etc/letsencrypt/njalla.ini
|
||||
-m secretbumblebee@proton.me --agree-tos -n
|
||||
--domains vault.secretbee.buzz
|
||||
|
||||
- name: Change permission on live
|
||||
ansible.builtin.file:
|
||||
path: /etc/letsencrypt/live/
|
||||
|
||||
@@ -71,7 +71,7 @@ services:
|
||||
restart: always
|
||||
|
||||
podman-exporter:
|
||||
image: quay.io/navidys/prometheus-podman-exporter:1.21.2
|
||||
image: quay.io/navidys/prometheus-podman-exporter:v1.21.2
|
||||
container_name: podman-exporter
|
||||
pull_policy: always
|
||||
restart: always
|
||||
|
||||
@@ -28,6 +28,14 @@
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Copy ssl.conf
|
||||
ansible.builtin.copy:
|
||||
src: ssl.conf
|
||||
dest: /etc/nginx/ssl.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Copy html content
|
||||
ansible.builtin.copy:
|
||||
src: www/
|
||||
@@ -36,7 +44,17 @@
|
||||
group: www-data
|
||||
mode: '0644'
|
||||
|
||||
- name: Restart nginx
|
||||
- name: Validate config
|
||||
ansible.builtin.command: nginx -t
|
||||
changed_when: false
|
||||
|
||||
- name: Start nginx
|
||||
ansible.builtin.service:
|
||||
name: nginx
|
||||
state: restarted
|
||||
state: started
|
||||
enabled: true
|
||||
|
||||
- name: Reload nginx
|
||||
ansible.builtin.service:
|
||||
name: nginx
|
||||
state: reloaded
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
server {
|
||||
listen 443 ssl default_server;
|
||||
listen [::]:443 ssl default_server;
|
||||
include /etc/nginx/ssl.conf;
|
||||
ssl_reject_handshake on;
|
||||
}
|
||||
@@ -15,8 +15,7 @@ server {
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/gallery.secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/gallery.secretbee.buzz/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
include /etc/nginx/ssl.conf;
|
||||
|
||||
# allow large file uploads
|
||||
client_max_body_size 50000M;
|
||||
|
||||
@@ -17,8 +17,7 @@ server {
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/git.secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/git.secretbee.buzz/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
include /etc/nginx/ssl.conf;
|
||||
|
||||
location / {
|
||||
client_max_body_size 512M;
|
||||
|
||||
@@ -26,8 +26,7 @@ server {
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/grafana.secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/grafana.secretbee.buzz/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
include /etc/nginx/ssl.conf;
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
|
||||
@@ -17,8 +17,7 @@ server {
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/lounge.secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/lounge.secretbee.buzz/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
include /etc/nginx/ssl.conf;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
|
||||
@@ -7,6 +7,7 @@ server {
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/matrix.secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/matrix.secretbee.buzz/privkey.pem;
|
||||
include /etc/nginx/ssl.conf;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
|
||||
@@ -9,6 +9,7 @@ server {
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/ott.secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/ott.secretbee.buzz/privkey.pem;
|
||||
include /etc/nginx/ssl.conf;
|
||||
#deny all;
|
||||
|
||||
location / {
|
||||
|
||||
@@ -28,8 +28,7 @@ server {
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/secretbee.buzz/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
include /etc/nginx/ssl.conf;
|
||||
|
||||
location /.well-known/matrix/server {
|
||||
default_type application/json;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name vault.secretbee.buzz;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/vault.secretbee.buzz/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/vault.secretbee.buzz/privkey.pem;
|
||||
include /etc/nginx/ssl.conf;
|
||||
|
||||
allow 10.10.1.0/24;
|
||||
allow 192.168.178.0/24;
|
||||
deny all;
|
||||
|
||||
client_max_body_size 128M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8222;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /admin {
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
@@ -144,14 +144,14 @@
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ user_info.uid }}/bus"
|
||||
ansible.builtin.systemd:
|
||||
name: ott-server.service
|
||||
state: started
|
||||
state: restarted
|
||||
scope: user
|
||||
|
||||
- name: Debug
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Service status: systemctl --user --machine {{ user_info.name }}@.host status ott-server"
|
||||
- "Service status: sudo systemctl --user --machine {{ user_info.name }}@.host status ott-server"
|
||||
- "Read logs: sudo journalctl _UID={{ user_info.uid }} -n 200 --no-pager"
|
||||
- "Shell: machinectl shell {{ user_info.name }}@.host /bin/bash"
|
||||
- "Shell: sudo machinectl shell {{ user_info.name }}@.host /bin/bash"
|
||||
tags:
|
||||
- always
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
[Unit]
|
||||
Description=Vaultwarden
|
||||
|
||||
[Container]
|
||||
ContainerName=vaultwarden
|
||||
Image=docker.io/vaultwarden/server:1.37.1
|
||||
PublishPort=127.0.0.1:8222:80
|
||||
Volume={{ user_home }}/data:/data
|
||||
Environment=DOMAIN=https://{{ vaultwarden_domain }}
|
||||
Environment=SIGNUPS_ALLOWED={{ vaultwarden_signups_allowed | string | lower }}
|
||||
Environment=INVITATIONS_ALLOWED=false
|
||||
Environment=ROCKET_PORT=80
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,101 @@
|
||||
- name: Vaultwarden
|
||||
hosts: beepi
|
||||
become: true
|
||||
vars:
|
||||
recovery_2fa: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
33656334663834356232623236316238396630656530363332353566363433356133313932613230
|
||||
3063613030363566376635363830336466333237633063310a666236333335363566343237646135
|
||||
65656466363833373231653565306563333036373664316535366339393531363434386336303563
|
||||
6636396665316634320a643966313338633564363830663263666461303635623164376265633631
|
||||
39633162323130663533343734303538636433323632316131373531376438633432323433303234
|
||||
3162626630373264356338356638323364656563666635393636
|
||||
|
||||
user: vaultwarden
|
||||
user_home: /home/vaultwarden
|
||||
vaultwarden_domain: vault.secretbee.buzz
|
||||
|
||||
# Bootstrap = -e vaultwarden_signups_allowed=true
|
||||
vaultwarden_signups_allowed: false
|
||||
|
||||
tasks:
|
||||
- name: Install dependencies
|
||||
ansible.builtin.apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
loop:
|
||||
- podman
|
||||
- systemd-container
|
||||
- passt
|
||||
|
||||
- name: Create user
|
||||
ansible.builtin.user:
|
||||
name: "{{ user }}"
|
||||
home: "{{ user_home }}"
|
||||
shell: /usr/sbin/nologin
|
||||
create_home: true
|
||||
register: user_info
|
||||
|
||||
- name: Enable linger
|
||||
ansible.builtin.command:
|
||||
cmd: "loginctl enable-linger {{ user }}"
|
||||
creates: "/var/lib/systemd/linger/{{ user }}"
|
||||
|
||||
- name: Create quadlet directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ user_home }}/.config/containers/systemd"
|
||||
state: directory
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Create data directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ user_home }}/data"
|
||||
state: directory
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: '0700'
|
||||
|
||||
- name: Deploy server quadlet
|
||||
ansible.builtin.template:
|
||||
src: vaultwarden.container.j2
|
||||
dest: "{{ user_home }}/.config/containers/systemd/vaultwarden.container"
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: '0600'
|
||||
|
||||
- name: Reload user systemd
|
||||
become: true
|
||||
become_user: "{{ user }}"
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ user_info.uid }}"
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ user_info.uid }}/bus"
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
scope: user
|
||||
|
||||
- name: Start user manager
|
||||
ansible.builtin.systemd:
|
||||
name: "user@{{ user_info.uid }}.service"
|
||||
state: started
|
||||
|
||||
- name: Start vaultwarden
|
||||
become: true
|
||||
become_user: "{{ user }}"
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ user_info.uid }}"
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ user_info.uid }}/bus"
|
||||
ansible.builtin.systemd:
|
||||
name: vaultwarden.service
|
||||
state: restarted
|
||||
scope: user
|
||||
|
||||
- name: Debug
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Service status: sudo systemctl --user --machine {{ user_info.name }}@.host status vaultwarden"
|
||||
- "Read logs: sudo journalctl _UID={{ user_info.uid }} -n 200 --no-pager"
|
||||
- "Shell: sudo machinectl shell {{ user_info.name }}@.host /bin/bash"
|
||||
tags:
|
||||
- always
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = {{ lookup('file', wireguard_client_dir ~ '/' ~ item.item.name ~ '.private') }}
|
||||
Address = {{ item.item.ip }}/32
|
||||
|
||||
[Peer]
|
||||
PublicKey = {{ wireguard_server_public_key }}
|
||||
PresharedKey = {{ lookup('file', wireguard_client_dir ~ '/' ~ item.item.name ~ '.psk.private') }}
|
||||
Endpoint = {{ wireguard_ingress_endpoint }}:{{ wireguard_ingress_port }}
|
||||
AllowedIPs = {{ item.item.allowed_ips | default(wireguard_client_allowed_ips) }}
|
||||
PersistentKeepalive = 25
|
||||
@@ -1,36 +1,26 @@
|
||||
[Interface]
|
||||
PrivateKey = {{ wireguard_server_private_key }}
|
||||
Address = 10.10.1.1/24
|
||||
ListenPort = 41194
|
||||
Address = {{ wireguard_ingress_address }}
|
||||
ListenPort = {{ wireguard_ingress_port }}
|
||||
PostUp = sysctl -w net.ipv4.ip_forward=1
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 10.10.1.2:25
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 10.10.1.2:25
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 993 -j DNAT --to-destination 10.10.1.2:993
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 993 -j DNAT --to-destination 10.10.1.2:993
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 587 -j DNAT --to-destination 10.10.1.2:587
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 587 -j DNAT --to-destination 10.10.1.2:587
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 465 -j DNAT --to-destination 10.10.1.2:465
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 465 -j DNAT --to-destination 10.10.1.2:465
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.10.1.2:80
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.10.1.2:80
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 10.10.1.2:443
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 10.10.1.2:443
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8448 -j DNAT --to-destination 10.10.1.2:8448
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 8448 -j DNAT --to-destination 10.10.1.2:8448
|
||||
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 4444 -j DNAT --to-destination 10.10.1.2:4444
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 4444 -j DNAT --to-destination 10.10.1.2:4444
|
||||
{% for port in wireguard_dnat_ports %}
|
||||
PreUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport {{ port }} -j DNAT --to-destination {{ wireguard_beepi_ip }}:{{ port }}
|
||||
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport {{ port }} -j DNAT --to-destination {{ wireguard_beepi_ip }}:{{ port }}
|
||||
{% endfor %}
|
||||
|
||||
#PreUp = iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
|
||||
#PostDown = iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE
|
||||
|
||||
|
||||
# ----- site-to-site: beepi -----
|
||||
[Peer]
|
||||
PublicKey = oI69uWkbkwtpuIYxDNGmzg4nRjY1BIZFVFjZwguIvwE=
|
||||
AllowedIPs = 10.10.1.2/32
|
||||
PublicKey = {{ wireguard_beepi_public_key }}
|
||||
AllowedIPs = {{ wireguard_beepi_ip }}/32
|
||||
|
||||
{% for peer in client_public_keys.results %}
|
||||
# ----- road-warrior: {{ peer.item.name }} -----
|
||||
[Peer]
|
||||
PublicKey = {{ peer.stdout }}
|
||||
PresharedKey = {{ lookup('file', wireguard_client_dir ~ '/' ~ peer.item.name ~ '.psk.private') }}
|
||||
AllowedIPs = {{ peer.item.ip }}/32
|
||||
{% endfor %}
|
||||
|
||||
@@ -10,23 +10,163 @@
|
||||
3239666637326337650a636433616264386162326535306461326233323961643664373134363634
|
||||
35633238393933386231373535353635646462383763613362363761363935363965383836366431
|
||||
3766343166643632306162343761613030653631353361373936
|
||||
|
||||
wireguard_ingress_address: 10.10.1.1/24
|
||||
wireguard_ingress_port: 41194
|
||||
wireguard_ingress_endpoint: 192.3.44.243
|
||||
wireguard_server_public_key: r0XaxIE3AVud9Z42UPZF3mwoh2R0B0M1EUDY9cvuyDA=
|
||||
|
||||
wireguard_beepi_ip: 10.10.1.2
|
||||
wireguard_beepi_public_key: oI69uWkbkwtpuIYxDNGmzg4nRjY1BIZFVFjZwguIvwE=
|
||||
|
||||
wireguard_dnat_ports:
|
||||
- 25 # mail
|
||||
- 80
|
||||
- 443
|
||||
- 465 # mail
|
||||
- 587 # mail
|
||||
- 993 # mail
|
||||
- 4444 # backup ssh
|
||||
- 8448 # matrix federation
|
||||
|
||||
wireguard_clients:
|
||||
- name: phone
|
||||
ip: 10.10.1.3
|
||||
|
||||
wireguard_client_allowed_ips: 10.10.1.2/32
|
||||
|
||||
wireguard_client_dir: "{{ playbook_dir }}/clients"
|
||||
|
||||
# Changes to Address, ListenPort or wireguard_dnat_ports = -e wireguard_full_restart=true
|
||||
wireguard_full_restart: false
|
||||
|
||||
tasks:
|
||||
- name: Install wireguard
|
||||
ansible.builtin.apt:
|
||||
name: wireguard
|
||||
state: present
|
||||
|
||||
- name: Down wg0
|
||||
changed_when: true
|
||||
failed_when: false
|
||||
ansible.builtin.command: wg-quick down wg0
|
||||
- name: Create local client key directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ wireguard_client_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Generate client private keys
|
||||
ansible.builtin.shell:
|
||||
cmd: "umask 077 && wg genkey > {{ wireguard_client_dir }}/{{ item.name }}.private"
|
||||
creates: "{{ wireguard_client_dir }}/{{ item.name }}.private"
|
||||
loop: "{{ wireguard_clients }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Generate client preshared keys
|
||||
ansible.builtin.shell:
|
||||
cmd: "umask 077 && wg genpsk > {{ wireguard_client_dir }}/{{ item.name }}.psk.private"
|
||||
creates: "{{ wireguard_client_dir }}/{{ item.name }}.psk.private"
|
||||
loop: "{{ wireguard_clients }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Derive client public keys
|
||||
ansible.builtin.command:
|
||||
cmd: "wg pubkey"
|
||||
stdin: "{{ lookup('file', wireguard_client_dir ~ '/' ~ item.name ~ '.private') }}"
|
||||
loop: "{{ wireguard_clients }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
register: client_public_keys
|
||||
changed_when: false
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Copy wg0.conf
|
||||
ansible.builtin.template:
|
||||
src: wg0.conf.j2
|
||||
dest: /etc/wireguard/wg0.conf
|
||||
mode: '0600'
|
||||
register: wg0_config
|
||||
|
||||
- name: Up wg0
|
||||
- name: Check whether wg0 is up
|
||||
ansible.builtin.command:
|
||||
cmd: wg show wg0
|
||||
register: wg0_state
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Sync peers without dropping the tunnel
|
||||
ansible.builtin.shell:
|
||||
cmd: "wg syncconf wg0 <(wg-quick strip wg0)"
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
ansible.builtin.command: wg-quick up wg0
|
||||
when:
|
||||
- wg0_config.changed
|
||||
- wg0_state.rc == 0
|
||||
- not wireguard_full_restart | bool
|
||||
|
||||
- name: Bounce wg0
|
||||
ansible.builtin.shell:
|
||||
cmd: "wg-quick down wg0 || true; wg-quick up wg0"
|
||||
changed_when: true
|
||||
when: wg0_state.rc != 0 or wireguard_full_restart | bool
|
||||
|
||||
- name: Enable wg-quick@wg0 on boot
|
||||
ansible.builtin.service:
|
||||
name: wg-quick@wg0
|
||||
enabled: true
|
||||
|
||||
- name: Render client configs
|
||||
ansible.builtin.template:
|
||||
src: client.conf.j2
|
||||
dest: "{{ wireguard_client_dir }}/{{ item.item.name }}.conf"
|
||||
mode: '0600'
|
||||
loop: "{{ client_public_keys.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.name }}"
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Check for qrencode
|
||||
ansible.builtin.command:
|
||||
cmd: "which qrencode"
|
||||
register: qrencode_check
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Render QR codes for mobile enrolment
|
||||
ansible.builtin.command:
|
||||
cmd: "qrencode -t ansiutf8 -r {{ wireguard_client_dir }}/{{ item.item.name }}.conf"
|
||||
loop: "{{ client_public_keys.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.name }}"
|
||||
register: client_qr
|
||||
changed_when: false
|
||||
when: qrencode_check.rc == 0
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Show QR codes
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ (item.stdout | default('')).split('\n') }}"
|
||||
loop: "{{ client_qr.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.item.name | default('') }}"
|
||||
when: qrencode_check.rc == 0
|
||||
|
||||
- name: Show peer status
|
||||
ansible.builtin.command:
|
||||
cmd: wg show wg0
|
||||
register: wg0_final
|
||||
changed_when: false
|
||||
|
||||
- name: Report
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ wg0_final.stdout_lines }}"
|
||||
|
||||
Reference in New Issue
Block a user