created major large-scale changes

This commit is contained in:
2026-07-12 15:27:58 -04:00
parent e8b29bb8e8
commit e53d6255e0
99 changed files with 4183 additions and 2093 deletions

View File

@@ -0,0 +1,70 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Informing user of requirement of two main domains
when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
ansible.builtin.fail:
msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
ansible.builtin.fail:
msg: At least one of the FQDNs must have a wildcard
# - name: Setting the FQDN for development
# when: compose.mode == "dev"
# ansible.builtin.set_fact:
# web_fqdn: "{{ (certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Setting the FQDN
# when: compose.mode == "prod"
ansible.builtin.set_fact:
web_fqdn: "{{ (certbot.domains | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Creating directory to store configuration file
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.aria2"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "755"
state: directory
- name: Configuring Aria2
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/aria2/aria2.conf.j2
dest: "{{ ansible_user_home.stdout }}/.aria2/aria2.conf"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
# validate: "aria2c --check"
- name: Setting up Aria2 as a service
when: aria.rpc.enabled and not aria.containerized
block:
- name: Creating a user SystemD service unit for Aria2
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.copy:
src: user/config/systemd/user/aria2cd.service
dest: "{{ ansible_user_home.stdout }}/.config/systemd/user/aria2cd.service"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
- name: Starting and enabling user SystemD service unit for Aria2
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.systemd_service:
name: aria2cd
scope: user
enabled: true
state: started
daemon_reload: true

View File

@@ -0,0 +1,166 @@
---
- name: Informing user of requirement of two main domains
when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
ansible.builtin.fail:
msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
ansible.builtin.fail:
msg: At least one of the FQDNs must have a wildcard
# - name: Modifying FQDN list for development
# when: "certbot.mode == 'dev'"
# ansible.builtin.set_fact:
# web_fqdns: "{{ certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | list }}"
- name: Modifying FQDN list for development
# when: "certbot.mode == 'prod'"
ansible.builtin.set_fact:
web_fqdns: "{{ certbot.domains }}"
- name: Creating domain arguments for certbot
ansible.builtin.set_fact:
certbot_domains: "{{ ['-d'] | product(web_fqdns) | map('join', '=') | list }}"
- name: Getting public IP
community.general.ipify_facts:
validate_certs: false
timeout: 20
- name: Starting domain name registration with standalone DNS
when: "certbot.auth_method == 'dns' and not certbot.containerized"
ignore_errors: true
block:
- name: Opening port 53
become: true
ansible.builtin.iptables:
chain: INPUT
protocol: tcp
destination_port: 53
jump: ACCEPT
comment: Opening up port 53
# @NOTE https://github.com/siilike/certbot-dns-standalone
- name: Exemplifying needed ACME record
ansible.builtin.set_fact:
acme_record: |
{{ inventory_hostname }} IN A {{ ipify_public_ip }}
_acme-challenge.{{ inventory_hostname }} IN CNAME {{ inventory_hostname }}.acme.{{ inventory_hostname }}.
acme.{{ inventory_hostname }} IN NS ns.acme.{{ inventory_hostname }}.
ns.acme.{{ inventory_hostname }} IN A {{ ipify_public_ip }}
- name: Informing user of need to set up ACME record
ansible.builtin.debug:
msg: "Please set ACME record in domain name provider:\n {{ acme_record }}"
- name: Waiting for user to set up ACME records
ansible.builtin.pause:
- name: Running certbot to authenticate and acquire domain name certificates
become: true
when: "certbot.mode == 'dev'"
ansible.builtin.command:
argv:
- certbot
- certonly
- "--staging"
- "--debug"
- "--authenticator=dns-standalone"
- "--email={{ certbot.email }}"
- "--agree-tos"
- "--non-interactive"
- "--dns-standalone-address={{ ipify_public_ip }}"
# - "--dns-standalone-ipv6-address={{ ansible_default_ipv6.address | default(ansible_all_ipv6_addresses[0]) }}"
- "--dns-standalone-port={{ certbot.port }}"
- "{{ certbot_domains[0] }}"
- "{{ certbot_domains[1] }}"
- name: Running certbot to authenticate and acquire domain name certificates
become: true
when: "certbot.mode == 'prod'"
ansible.builtin.command:
argv:
- certbot
- certonly
- "--authenticator=dns-standalone"
- "--email={{ certbot.email }}"
- "--agree-tos"
- "--non-interactive"
- "--dns-standalone-address={{ ipify_public_ip }}"
# - "--dns-standalone-ipv6-address={{ ansible_default_ipv6.address | default(ansible_all_ipv6_addresses[0]) }}"
- "--dns-standalone-port={{ certbot.port }}"
- "{{ certbot_domains[0] }}"
- "{{ certbot_domains[1] }}"
- name: Starting domain name registration with standalone option
when: "certbot.auth_method == 'standalone' and not certbot.containerized"
ignore_errors: true
block:
- name: Opening port 80
become: true
ansible.builtin.iptables:
chain: INPUT
protocol: tcp
destination_port: 80
jump: ACCEPT
comment: Open up port 80
- name: Acquiring domain certificates
become: true
when: "certbot.mode == 'dev'"
ansible.builtin.command:
argv:
- certbot
- certonly
- "--staging"
- "--debug"
- "--standalone"
- "--preferred-challenges=http-01"
- "--email={{ certbot.email }}"
- "--agree-tos"
- "--non-interactive"
- "{{ certbot_domains[0] }}"
- "{{ certbot_domains[1] }}"
- name: Acquiring domain certificates
become: true
when: "certbot.mode == 'dev'"
ansible.builtin.command:
argv:
- certbot
- certonly
- "--standalone"
- "--email {{ certbot.email }}"
- "--agree-tos"
- "--non-interactive"
- "--preferred-challenges http-01"
- "{{ certbot_domains[0] }}"
- "{{ certbot_domains[1] }}"
- name: Creating needed directory for renewal pre- hooks
become: true
ansible.builtin.file:
path: /etc/letsencrypt/renewal-hooks/pre
recurse: true
owner: root
group: root
mode: "755"
state: directory
- name: Copying renewal pre- hook to renewal pre- hook path
become: true
ansible.builtin.copy:
src: letsencrypt/renewal-hooks/pre/down-dependents.sh
dest: /etc/letsencrypt/renewal-hooks/pre/
owner: root
group: root
mode: "755"
force: true
backup: true
- name: Creating needed directory for renewal post- hooks
become: true
ansible.builtin.file:
path: /etc/letsencrypt/renewal-hooks/post
recurse: true
owner: root
group: root
mode: "755"
state: directory
- name: Copying renewal post- hook to renewal post- hook path
become: true
ansible.builtin.copy:
src: letsencrypt/renewal-hooks/post/up-dependents.sh
dest: /etc/letsencrypt/renewal-hooks/post/
owner: root
group: root
mode: "755"
force: true
backup: true
- name: Starting domain name registration with webroot option
when: "certbot.auth_method == 'webroot' and not certbot.containerized"
block: []

View File

@@ -1,40 +1,65 @@
- name: Restarting SystemD service
become: true
ansible.builtin.systemd_service:
name: crowdsec
scope: system
enabled: true
state: started
- name: Changing the address and port of the Crowdsec server
become: true
ansible.builtin.lineinfile:
path: /etc/crowdsec/config.yaml
regexp: "^ {4}listen_uri"
line: " listen_uri: localhost:{{ crowdsec.port }}"
owner: root
group: root
mode: "644"
- name: Changing the address of the Crowdsec Prometheus server
become: true
ansible.builtin.lineinfile:
path: /etc/crowdsec/config.yaml
regexp: "^ {2}listen_addr"
line: " listen_addr: localhost"
owner: root
group: root
mode: "644"
- name: Changing target or expected address for credentials of the Crowdsec local API
become: true
ansible.builtin.lineinfile:
path: /etc/crowdsec/local_api_credentials.yaml
regexp: "^url"
line: "url: http://localhost:{{ crowdsec.port }}"
owner: root
group: root
mode: "644"
- name: Restarting SystemD service
become: true
ansible.builtin.systemd_service:
name: crowdsec
scope: system
state: restarted
- name: Preparing non-containerized Crowdsec
when: not crowdsec.containerized
block:
- name: Changing the address and port of the Crowdsec server
become: true
ansible.builtin.lineinfile:
path: /etc/crowdsec/config.yaml
insertafter: EOF
regexp: "^ {4}listen_uri"
line: " listen_uri: localhost:{{ crowdsec.port }}"
owner: root
group: root
mode: "644"
- name: Changing the address of the Crowdsec Prometheus server
become: true
ansible.builtin.lineinfile:
path: /etc/crowdsec/config.yaml
regexp: "^ {2}listen_addr"
insertafter: EOF
line: " listen_addr: localhost"
owner: root
group: root
mode: "644"
- name: Changing target or expected address for credentials of the Crowdsec local API
become: true
ansible.builtin.lineinfile:
path: /etc/crowdsec/local_api_credentials.yaml
insertafter: EOF
regexp: "^url"
line: "url: http://localhost:{{ crowdsec.port }}"
owner: root
group: root
mode: "644"
- name: Restarting SystemD service
become: true
ansible.builtin.systemd_service:
name: crowdsec
scope: system
state: restarted
- name: Adding remediation component or bouncer
ansible.builtin.command:
cmd: "cscli bouncers add {{ item }}"
loop: "{{ crowdsec.bouncers }}"
- name: Installing Crowdsec collections
ansible.builtin.command:
cmd: "cscli collections install {{ item }}"
loop: "{{ crowdsec.colls }}"
- name: Installing Crowdsec parsers
ansible.builtin.command:
cmd: "cscli parsers install {{ item }}"
loop: "{{ crowdsec.parsers }}"
- name: Installing Crowdsec scenarios
ansible.builtin.command:
cmd: "cscli scenarios install {{ item }}"
loop: "{{ crowdsec.scenarios }}"
- name: Installing Crowdsec postoverflows
ansible.builtin.command:
cmd: "cscli postoverflows install {{ item }}"
loop: "{{ crowdsec.postoverflows }}"
- name: Restarting SystemD service
become: true
ansible.builtin.systemd_service:
name: crowdsec
scope: system
state: restarted

View File

@@ -5,6 +5,7 @@
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Linking binaries to directories already in PATH environment variable
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/downloads/archives/released/difftastic/{{ item }}"
dest: "{{ ansible_user_home.stdout }}/.local/bin/{{ item }}"
@@ -13,6 +14,7 @@
- difft
- name: Linking binaries to directories already in PATH environment variable
become: true
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/downloads/archives/released/difftastic/{{ item }}"
dest: "/usr/bin/{{ item }}"

View File

@@ -29,7 +29,7 @@
ansible.builtin.shell:
cmd: "dsnet add {{ item.name }}{{ idx }} --owner {{ current_user.stdout }} --description 'For {{ item.name }}--{{ item.desc }}' --confirm > {{ ansible_user_home.stdout }}/.wg/authorized_clients.d/{{ item.name }}{{ (idx | string) }}.conf"
creates: "{{ ansible_user_home.stdout }}/.wg/authorized_clients.d/{{ item.name }}{{ idx }}.conf"
loop: "{{ vpn_server.clients }}"
loop: "{{ vpn.clients }}"
loop_control:
index_var: idx
- name: Changing ownership of consequent DSNet VPN service client configurations
@@ -37,8 +37,9 @@
path: "{{ ansible_user_home.stdout }}/.wg/authorized_clients.d/{{ item.name }}{{ (idx | string) }}.conf"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "600"
state: file
loop: "{{ vpn_server.clients }}"
loop: "{{ vpn.clients }}"
loop_control:
index_var: idx
- name: Pausing to inquire about how to proceed
@@ -52,30 +53,47 @@
- name: Acquiring contents of DSNet VPN service client configuration files
ansible.builtin.slurp:
src: "{{ ansible_user_home.stdout }}/.wg/authorized_clients.d/{{ item.name }}{{ (idx | string) }}.conf"
loop: "{{ vpn_server.clients }}"
loop: "{{ vpn.clients }}"
loop_control:
index_var: idx
register: vpn_client_configs
- name: Presenting contents of DSNet VPN service client configurations to control node
ansible.builtin.debug:
msg: "Copy this client configuration of the DSNet VPN service:\n {{ item.content }}"
msg: "Copy this client configuration of the DSNet VPN service:\n {{ item.content | b64decode }}"
loop: "{{ vpn_client_configs.results }}"
- name: Giving opportunity to manually copy contents of DSNet VPN service client configuration files
ansible.builtin.pause:
- name: Providing DSNet VPN service client configuration files to control node machine
when: data_method.user_input == "fetch"
block:
- name: Informing user of inventory requirements for VPN clients
when: not item.name in groups.homeserver
ansible.builtin.fail:
msg: The VPN client must be the name of an inventory host in a homeserver group
loop: "{{ vpn.clients }}"
- name: Dupliciating DSNet VPN service client configuration files to control node
when: item.name in groups.homeserver
ansible.builtin.fetch:
src: "{{ ansible_user_home.stdout }}/.wg/authorized_clients.d/{{ item.name }}{{ (idx | string) }}.conf"
dest: "./.tmp/{{ inventory_hostname }}-dsnet/"
flat: true
loop: "{{ vpn.clients }}"
loop_control:
index_var: idx
- name: Dupliciating DSNet VPN service client configuration files to control node
ansible.builtin.fetch:
src: "{{ ansible_user_home.stdout }}/.wg/authorized_clients.d/{{ item.name }}{{ (idx | string) }}.conf"
dest: "./.tmp/{{ inventory_hostname }}-dsnet/wg/"
dest: "./roles/init-server/files/user/wg/containerized/{{ item.name }}{{ (idx | string) }}.conf"
flat: true
loop: "{{ vpn_server.clients }}"
loop: "{{ vpn.clients }}"
loop_control:
index_var: idx
- name: Informing control node of acquired files
ansible.builtin.debug:
msg: "The DSNet VPS service client configuration files have been duplicated to '/var/tmp/{{ inventory_hostname }}/wg/' at the control node."
msg: "The DSNet VPS service client configuration files have been duplicated to \"{{ item }}\" at the control node."
loop:
- "./.tmp/{{ inventory_hostname }}-dsnet/"
- "./roles/init-server/files/user/wg/"
- name: Giving control node user time to read the aforementiioned message
ansible.builtin.pause:
seconds: 30
@@ -106,12 +124,12 @@
daemon_reload: true
- name: Copying script for DSNet iptables rules
become: true
ansible.builtin.copy:
src: usr/local/bin/dsnet-forward.sh
dest: /usr/local/bin/
ansible.builtin.template:
src: usr/local/bin/dsnet-forward.sh.j2
dest: /usr/local/bin/dsnet-forward.sh
owner: root
group: root
mode: "744"
mode: "755"
force: true
backup: true
- name: Creating SystemD unit for DSNet iptables rules
@@ -123,25 +141,19 @@
group: root
force: true
backup: true
- name: Reloading SystemD and enabling iptables rules SystemD unit
- name: Reloading SystemD
become: true
ansible.builtin.systemd_service:
name: thrunet
enabled: true
daemon_reload: true
- name: Forwarding network traffic on certain ports to Wireguard VPS service interface
- name: Opening port 51820
become: true
ansible.builtin.iptables:
chain: FORWARD
protocol: "{{ item[0][0] }}"
source_port: "{{ item[0][1] }}"
in_interface: "{{ item[1] }}"
chain: INPUT
protocol: "{{ item }}"
destination_port: 51820
jump: ACCEPT
loop: "{{ vpn_server.forwards | product([vpn_server.interface]) }}"
- name: Forwarding network traffic on certain ports to Wireguard VPS service interface
become: true
ansible.builtin.iptables:
table: nat
chain: POSTROUTING
out_interface: "{{ vpn_server.interface }}"
jump: MASQUERADE
comment: Open up port 51820
loop:
- udp
- tcp

View File

@@ -8,6 +8,23 @@
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Informing user of requirement of two main domains
when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
ansible.builtin.fail:
msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
ansible.builtin.fail:
msg: At least one of the FQDNs must have a wildcard
# - name: Setting the FQDN for development
# when: compose.mode == "dev"
# ansible.builtin.set_fact:
# web_fqdn: "{{ (certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Setting the FQDN
# when: compose.mode == "prod"
ansible.builtin.set_fact:
web_fqdn: "{{ (certbot.domains | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Configuring Headscale
become: true
ansible.builtin.template:
@@ -18,6 +35,7 @@
mode: "644"
force: true
backup: true
# validate: "headscale configtest"
- name: Starting SystemD service
become: true
ansible.builtin.systemd_service:
@@ -28,12 +46,55 @@
- name: Registering a headscale user
become: true
ansible.builtin.command:
# cmd: "headscale users create {{ item.username }} -d '{{ item.dname }}' -e '{{ item.email }}' -p '{{ pfp | default(default_pfp) }}'"
cmd: "headscale users create {{ item.username }} -d '{{ item.dname }}' -e '{{ item.email }}'"
# vars:
# default_pfp: ~
loop: "{{ tail.users }}"
cmd: "headscale users create {{ headscale.users.admin.username }} -d '{{ headscale.users.admin.dname }}' -e '{{ headscale.users.admin.email }}'"
register: headscale_registration
changed_when:
- "'User created' in headscale_registration.stdout"
- headscale_registration.rc == 0
- name: Creating an authentication key for this registered headscale user
become: true
ansible.builtin.command:
cmd: "headscale preauthkeys create -e 24h -u 1"
register: tailscale_admin_authkey
- name: Pausing to inquire about how to proceed
ansible.builtin.pause:
prompt: "Type \"fetch\" to get the DSNet VPN service client configuration files, or \"show\" to see their contents for manual copying instead"
echo: true
register: data_method
- name: Choosing Headscale authentication key to control node for copying
when: data_method.user_input == "show"
block:
- name: Presenting Headscale authentication key to Control Node
ansible.builtin.debug:
msg: "Copy this client configuration of the headscale service:\n {{ tailscale_admin_authkey.stdout }}"
- name: Giving opportunity to manually copy Headscale authentication key
ansible.builtin.pause:
- name: Choosing Headscale service client configuration files to control node machine
when: data_method.user_input == "fetch"
block:
- name: Creating temporary file on managed node that stores Headscale authentication key
ansible.builtin.copy:
content: "{{ tailscale_admin_authkey.stdout }}"
dest: "/tmp/headscale.key"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
register: tailscale_admin_authkey_file
- name: Placing Headscale authentication key into file on control node
ansible.builtin.fetch:
src: "{{ tailscale_admin_authkey_file.dest }}"
dest: "./.tmp/{{ inventory_hostname }}-{{ headscale.users.admin.username }}@headscale/headscale.key"
flat: true
- name: Placing Headscale authentication key into file on control node
ansible.builtin.fetch:
src: "{{ tailscale_admin_authkey_file.dest }}"
dest: "./roles/init-server/files/{{ item.name }}-{{ headscale.users.admin.username }}@headscale/headscale{{ (idx | string) }}.key"
flat: true
loop: "{{ headscale.clients }}"
loop_control:
index_var: idx
- name: Informing control node of acquired files
ansible.builtin.debug:
msg: "The Headscale authentication key files have been duplicated to './.tmp/{{ inventory_hostname }}-{{ headscale.users.admin.username }}@headscale/headscale.key' at the control node."
- name: Giving control node user time to read the aforementiioned message
ansible.builtin.pause:
seconds: 30

View File

@@ -15,13 +15,14 @@
ansible.builtin.shell:
cmd: "{{ ansible_user_home.stdout }}/.local/bin/julia-install.sh --yes"
creates: "{{ ansible_user_home.stdout }}/.juliaup/bin"
async: 900
poll: 5
- name: Linking binaries to directories already in PATH environment variable
become: true
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/.juliaup/bin/{{ item }}"
dest: "/usr/bin/{{ item }}"
owner: root
group: root
state: link
loop:
- julia

View File

@@ -0,0 +1,110 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Setting up TOTP using Google Authenticator
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
argv:
- "google-authenticator"
- "-t"
- "-d"
- "-f"
- "-C"
- "-q"
- "-l {{ ansible_user }}@{{ inventory_hostname }}"
- "-i {{ inventory_hostname }}"
- "--qr-mode=NONE"
- "-r 7"
- "-R 300"
- "-w 9"
creates: "{{ ansible_user_home.stdout }}/.google_authenticator"
- name: Pausing to inquire about how to proceed
ansible.builtin.pause:
prompt: "Type \"fetch\" to get the TOTP secret and backup codes, or \"show\" to see it for manual copying instead"
echo: true
register: data_method
- name: Choosing to present TOTP secret and backup codes to Control Node
when: data_method.user_input == "show"
block:
- name: Acquiring contents of file containing TOTP secret and backup codes
ansible.builtin.slurp:
src: "{{ ansible_user_home.stdout }}/.google_authenticator"
register: totp_token
- name: Presenting TOTP secret and backup codes to Control Node
ansible.builtin.debug:
msg: "Make sure to store the following TOTP secret and backup codes for Google Authenticator:\n {{ totp_token.content | b64decode }}"
- name: Giving opportunity to manually copy TOTP secret and backup codes
ansible.builtin.pause:
- name: Choosing to provide file on control node containing TOTP secret and backup codes
when: data_method.user_input == "fetch"
block:
- name: Placing TOTP secret and backup codes into file on control node
ansible.builtin.fetch:
src: "{{ ansible_user_home.stdout }}/.google_authenticator"
dest: "./.tmp/{{ inventory_hostname }}-google-auth/google_auth.secret"
flat: true
- name: Informing control node of acquired files
ansible.builtin.debug:
msg: "The TOTP secret and backup codes file has been duplicated to './.tmp/{{ inventory_hostname }}-google-auth/google-auth.secret' at the control node."
- name: Giving control node user time to read the aforementiioned message
ansible.builtin.pause:
seconds: 30
- name: Adding Google Authenticator OTP module PAM authentication line for SSH
become: true
ansible.builtin.lineinfile:
path: /etc/pam.d/sshd
line: "auth sufficient pam_google_authenticator.so nullok"
insertafter: "include common-auth$"
owner: root
group: root
mode: "644"
- name: Prioritizing authentication methods in SSH
become: true
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config.d/auth.conf
line: "KbdInteractiveAuthentication yes # enable if implementing TOTP 2FA"
regexp: "^KbdInteractiveAuthentication"
owner: root
group: root
mode: "644"
- name: Prioritizing authentication methods in SSH
become: true
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config.d/auth.conf
line: "AuthenticationMethods publickey keyboard-interactive:pam"
insertafter: "^KbdInteractiveAuthentication"
owner: root
group: root
mode: "644"
# - name: Adding Google Authenticator OTP module PAM authentication line for SSH
# become: true
# ansible.builtin.lineinfile:
# path: /etc/pam.d/sudo
# line: "auth required pam_google_authenticator.so nullok"
# insertafter: "include common-auth$"
# owner: root
# group: root
# mode: "644"
# - name: Adding Google Authenticator OTP module PAM authentication line for SSH
# become: true
# ansible.builtin.lineinfile:
# path: /etc/pam.d/su
# line: "auth required pam_google_authenticator.so nullok"
# insertafter: "include common-auth$"
# owner: root
# group: root
# mode: "644"
- name: Restarting SystemD SSH service
become: true
ansible.builtin.systemd_service:
name: sshd
state: restarted

View File

@@ -18,43 +18,38 @@
ansible.builtin.set_fact:
prebuilt_nodepaths: "{{ prebuilt_nodes.files | map(attribute='path') }}"
- name: Linking binaries to directories already in PATH environment variable
ignore_errors: true
ansible.builtin.file:
src: "{{ item[0] }}/bin/{{ item[1] }}"
dest: "/usr/bin/{{ item[1] }}"
owner: root
group: root
state: link
loop: "{{ prebuilt_nodepaths | product(['node']) }}"
- name: Linking binaries to directories already in PATH environment variable
ignore_errors: true
ansible.builtin.file:
src: "{{ item[0] }}/lib/node_modules/corepack/dist/{{ item[1] }}.js"
dest: "/usr/bin/{{ item[1] }}"
owner: root
group: root
state: link
loop: "{{ prebuilt_nodepaths | product(['corepack']) }}"
- name: Linking binaries to directories already in PATH environment variable
ignore_errors: true
ansible.builtin.file:
src: "{{ item[0] }}/lib/node_modules/npm/bin/{{ item[1] }}-cli.js"
dest: "/usr/bin/{{ item[1] }}"
owner: root
group: root
state: link
loop: "{{ prebuilt_nodepaths | product(['npm','npx']) }}"
- name: Link includes to directories already recognized by system
ignore_errors: true
ansible.builtin.file:
src: "{{ item[0] }}/include/{{ item[1] }}"
dest: "/usr/include/{{ item[1] }}"
owner: root
group: root
state: link
loop: "{{ prebuilt_nodepaths | product(['node']) }}"
- name: Link requisite libraries to directories already recognized by system
ignore_errors: true
ansible.builtin.file:
src: "{{ item[0] }}/lib/{{ item[1] }}"
dest: "/usr/lib/{{ item[1] }}"
owner: root
group: root
state: link
loop: "{{ prebuilt_nodepaths | product(['node_modules']) }}"
- name: Create man1 subdirectory for man pages
@@ -66,11 +61,10 @@
mode: "644"
state: directory
- name: Link shared resources to directories already recognized by system
ignore_errors: true
ansible.builtin.file:
src: "{{ item[0] }}/share/man/man1/{{ item[1] }}.1"
dest: "/usr/share/man/man1/{{ item[1] }}.1"
owner: root
group: root
state: link
loop: "{{ prebuilt_nodepaths | product(['node']) }}"
- name: Create man1 subdirectory for man pages
@@ -82,11 +76,10 @@
mode: "644"
state: directory
- name: Link shared resources to directories already recognized by system
ignore_errors: true
ansible.builtin.file:
src: "{{ item[0] }}/share/doc/{{ item[1] }}"
dest: "/usr/share/doc/{{ item[1] }}"
owner: root
group: root
state: link
loop: "{{ prebuilt_nodepaths | product(['node']) }}"
# - name: Reboot machine for shell environment change

View File

@@ -0,0 +1,65 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Ensuring user namespace support is enabled
become: true
ansible.posix.sysctl:
name: kernel.unprivileged_userns_clone
value: "1"
sysctl_set: true
state: present
- name: Ensuring user namespace support is enabled
become: true
ansible.posix.sysctl:
name: net.ipv4.ip_unprivileged_port_start
value: "0"
sysctl_set: true
state: present
- name: Creating container directory
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.config/containers"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "755"
state: directory
- name: Configuring container storage
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/config/containers/storage.conf.j2
dest: "{{ ansible_user_home.stdout }}/.config/containers/storage.conf"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
- name: Configuring container image registries
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.copy:
src: user/config/containers/registries.conf
dest: "{{ ansible_user_home.stdout }}/.config/containers/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
# @NOTE https://oneuptime.com/blog/post/2026-01-27-podman-rootless/view#configuring-registries
# @NOTE https://github.com/podman-container-tools/podman/blob/main/docs/tutorials/rootless_tutorial.md#using-volumes
# @NOTE https://github.com/containers/podman-compose/issues/166#issuecomment-1550515230
- name: Enabling and starting SystemD unit service for automatic restart of containers/pods
become: true
ansible.builtin.systemd_service:
name: podman-restart
scope: system
enabled: true
state: started

View File

@@ -4,23 +4,180 @@
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Informing user of requirement of two main domains
when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
ansible.builtin.fail:
msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
ansible.builtin.fail:
msg: At least one of the FQDNs must have a wildcard
# - name: Setting the FQDN for development
# when: compose.mode == "dev"
# ansible.builtin.set_fact:
# web_fqdn: "{{ (certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Setting the FQDN for production
# when: compose.mode == "prod"
ansible.builtin.set_fact:
web_fqdn: "{{ (certbot.domains | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Linking repository to another path
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/repos/.foreign/quartz"
dest: "{{ ansible_user_home.stdout }}/repos/skato-quartz"
state: link
- name: Installing NodeJS dependencies of quartz software
become: true
become_user: "{{ current_user.stdout }}"
community.general.npm:
path: "{{ ansible_user_home.stdout }}/repos/.foreign/quartz"
state: latest
- name: Configuring quartz software
block:
- name: Creating path for Quartz content files (path for Obsidian vaults)
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/journal/notes"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "755"
state: directory
- name: Creating some initial text content for Quartz
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: "user/journal/notes/index.md.j2"
dest: "{{ ansible_user_home.stdout }}/journal/notes/index.md"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
backup: true
- name: Creating some initial image content for Quartz
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.copy:
src: user/journal/mythe-sisyphus-klein.png
dest: "{{ ansible_user_home.stdout }}/journal/notes/mythe-sisyphus-klein.png"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
backup: true
- name: Initializing quartz website
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
argv:
- npx
- "-y"
- quartz
- create
- "-b"
- notes.{{ web_fqdn }}"
- "-t"
- obsidian
- "-s"
- "{{ ansible_user_home.stdout }}/journal/notes"
- "-X"
- symlink
chdir: "{{ ansible_user_home.stdout }}/repos/.foreign/quartz"
cmd: npx quartz create
creates: "{{ ansible_user_home.stdout }}/repos/.foreign/quartz/content/index.md"
- name: Installing quartz plugins referenced in website template
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
argv:
- npx
- "-y"
- quartz
- plugin
- install
chdir: "{{ ansible_user_home.stdout }}/repos/.foreign/quartz"
cmd: npx quartz plugin install --from-config
# - name: Starting quartz site web server
# ansible.builtin.command:
# chdir: "{{ ansible_user_home.stdout }}/repos/.foreign/quartz"
# cmd: npx quartz build --serve
# register: stdout
# changed_when: stdout
- name: Starting quartz site web server
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
argv:
- npx
- "-y"
- quartz
- build
- "-o"
- "{{ ansible_user_home.stdout }}/srv/notes.{{ web_fqdn }}"
- "--concurrency"
- "3"
chdir: "{{ ansible_user_home.stdout }}/repos/.foreign/quartz"
creates: "{{ ansible_user_home.stdout }}/srv/notes.{{ web_fqdn }}/index.html"
- name: Creating directory for caddy configuration
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.config/caddy"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Adding Caddyfile subdomain entry
when: "(caddy is defined and caddy != None) and caddy.containerized and mode == 'prod'"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
notes.{{ web_fqdn }} {
respond 503
# root /srv/notes.{{ web_fqdn }}
file_server
encode gzip
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
templates
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED NOTES DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
create: true
state: present
- name: Adding Caddyfile subdomain entry
when: "(caddy is defined and caddy != None) and caddy.containerized and (mode == 'dev' or caddy.scheme == 'http')"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
http://notes.{{ web_fqdn }} {
respond 503
# root /srv/notes.{{ web_fqdn }}
file_server
encode gzip
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
templates
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED NOTES DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
create: true
state: present
- name: Checking the status of podman containers
ansible.builtin.command:
argv:
- podman
- ps
register: podman_status
- name: Restarting webserver / reverse proxy container
become: true
become_user: "{{ current_user.stdout }}"
when: "'revproxy0' in podman_status.stdout and (caddy is defined and caddy != None) and caddy.containerized"
containers.podman.podman_container:
name: "{{ compose.containers.webserver.name }}"
state: started
force_restart: true

View File

@@ -15,10 +15,13 @@
ansible.builtin.shell:
cmd: "{{ ansible_user_home.stdout }}/.local/bin/radicle-install.sh"
creates: "{{ ansible_user_home.stdout }}/.radicle"
async: 600
poll: 5
- name: Bootstrapping Radicle
become: true
block:
- name: Linking binaries to directories already in PATH environment variable
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/.radicle/bin/{{ item }}"
dest: "/usr/bin/{{ item }}"
@@ -36,6 +39,7 @@
mode: "644"
state: directory
- name: Link manpages to Linux manpage directories
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/.radicle/man/man1/{{ item }}.1"
dest: "/usr/share/man/man1/{{ item }}.1"

View File

@@ -15,8 +15,11 @@
ansible.builtin.shell:
cmd: "{{ ansible_user_home.stdout }}/.local/bin/rustup-install.sh -yq"
creates: "{{ ansible_user_home.stdout }}/.cargo/bin"
async: 600
poll: 5
- name: Linking binaries to directories already in PATH environment variable
become: true
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/.cargo/bin/{{ item }}"
dest: "/usr/bin/{{ item }}"

View File

@@ -0,0 +1,171 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Informing user of requirement of two main domains
when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
ansible.builtin.fail:
msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
ansible.builtin.fail:
msg: At least one of the FQDNs must have a wildcard
# - name: Setting the FQDN for development
# when: compose.mode == "dev"
# ansible.builtin.set_fact:
# web_fqdn: "{{ (certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Setting the FQDN
# when: compose.mode == "prod"
ansible.builtin.set_fact:
web_fqdn: "{{ (certbot.domains | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Moving git repository from initial path
block:
- name: Recursively copying directory and its contents to elsewhere
ansible.builtin.copy:
src: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.blog.name }}"
remote_src: true
dest: "{{ ansible_user_home.stdout }}/repos/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
register: new_blog_path
- name: Deleting directory at previous path
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.blog.name }}"
state: absent
- name: Creating directory for new bare repository
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/src"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Creating bare repository
ansible.builtin.command:
cmd: "git init --bare {{ source_code.repos.blog.name }}.git"
chdir: "{{ ansible_user_home.stdout }}/src"
creates: "{{ ansible_user_home.stdout }}/src/{{ source_code.repos.blog.name }}.git"
- name: Running Hugo blog
when: source_code.repos.blog.run
block:
- name: Creating path for Hugo content files
when: caddy.containerized and (compose.containers.webserver is defined or compose.containers.webserver != None)
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/journal/blog"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "755"
state: directory
- name: Creating some initial text content for Hugo
become: true
become_user: "{{ current_user.stdout }}"
when: caddy.containerized and (compose.containers.webserver is defined or compose.containers.webserver != None)
ansible.builtin.template:
src: "user/journal/blog/_index.md.j2"
dest: "{{ ansible_user_home.stdout }}/journal/blog/index.md"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
backup: true
- name: Creating some initial image content for Hugo
become: true
become_user: "{{ current_user.stdout }}"
when: caddy.containerized and (compose.containers.webserver is defined or compose.containers.webserver != None)
ansible.builtin.copy:
src: "user/journal/mythe-sisyphus-klein.png"
dest: "{{ ansible_user_home.stdout }}/journal/blog/mythe-sisyphus-klein.png"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
backup: true
- name: Creating subdirectory for blog website root
when: caddy.containerized and (compose.containers.webserver is defined or compose.containers.webserver != None)
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/srv/blog.{{ web_fqdn }}"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "755"
state: directory
- name: Build Hugo blog at additional webroot
when: caddy.containerized and (compose.containers.webserver is defined or compose.containers.webserver != None)
ansible.builtin.command:
argv:
- hugo
- "--quiet"
- "-b"
- "https://blog.{{ web_fqdn }}/"
- "-c"
- "{{ ansible_user_home.stdout }}/journal/blog"
- "-d"
- "{{ ansible_user_home.stdout }}/srv/blog.{{ web_fqdn }}"
- "--cleanDestinationDir"
chdir: "{{ new_blog_path.dest }}"
creates: "{{ ansible_user_home.stdout }}/srv/blog.{{ web_fqdn }}/index.html"
# @TODO write error Caddy template HTML file at the blog's web root
- name: Adding Caddyfile subdomain entry
when: caddy.containerized and mode == 'prod' and (compose.containers.webserver is defined or compose.containers.webserver != None)
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
blog.{{ web_fqdn }} {
respond 503
# root /srv/blog.{{ web_fqdn }}
file_server
encode gzip
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
templates
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED BLOG DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
state: present
- name: Adding Caddyfile subdomain entry
when: caddy.containerized and (mode == 'dev' or caddy.scheme == 'http') and (compose.containers.webserver is defined or compose.containers.webserver != None)
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
http://blog.{{ web_fqdn }} {
respond 503
# root /srv/blog.{{ web_fqdn }}
file_server
encode gzip
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
templates
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED BLOG DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
state: present
- name: Checking the status of podman containers
ansible.builtin.command:
argv:
- podman
- ps
register: podman_status
- name: Restarting webserver / reverse proxy container
become: true
become_user: "{{ current_user.stdout }}"
when: "'revproxy0' in podman_status.stdout and (caddy is defined and caddy != None) and caddy.containerized"
containers.podman.podman_container:
name: "{{ compose.containers.webserver.name }}"
state: started
force_restart: true

View File

@@ -0,0 +1,45 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Moving git repository from initial path
block:
- name: Recursively copying directory and its contents to elsewhere
ansible.builtin.copy:
src: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.blog_theme.name }}"
remote_src: true
dest: "{{ ansible_user_home.stdout }}/repos/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
register: new_compose_path
- name: Deleting directory at previous path
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.blog_theme.name }}"
state: absent
- name: Creating directory for new bare repository
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/src"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Creating bare repository
ansible.builtin.command:
cmd: "git init --bare {{ source_code.repos.blog_theme.name }}.git"
chdir: "{{ ansible_user_home.stdout }}/src"
creates: "{{ ansible_user_home.stdout }}/src/{{ source_code.repos.blog_theme.name }}.git"
- name: Running Hugo blog theme
when: source_code.repos.blog_theme.run
# become: true
# become_user: "{{ current_user.stdout }}"
block:
- name: Warning about lack of implementation
ansible.builtin.debug:
msg: Not yet implemented

View File

@@ -0,0 +1,45 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Moving git repository from initial path
block:
- name: Recursively copying directory and its contents to elsewhere
ansible.builtin.copy:
src: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.cli.name }}"
remote_src: true
dest: "{{ ansible_user_home.stdout }}/repos/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
register: new_compose_path
- name: Deleting directory at previous path
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.cli.name }}"
state: absent
- name: Creating directory for new bare repository
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/src"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Creating bare repository
ansible.builtin.command:
cmd: "git init --bare {{ source_code.repos.cli.name }}.git"
chdir: "{{ ansible_user_home.stdout }}/src"
creates: "{{ ansible_user_home.stdout }}/src/{{ source_code.repos.cli.name }}.git"
- name: Running CLI utility
when: source_code.repos.cli.run
# become: true
# become_user: "{{ current_user.stdout }}"
block:
- name: Warning about lack of implementation
ansible.builtin.debug:
msg: Not yet implemented

View File

@@ -0,0 +1,836 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Informing user of requirement of two main domains
when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
ansible.builtin.fail:
msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
ansible.builtin.fail:
msg: At least one of the FQDNs must have a wildcard
# - name: Setting the FQDN for development
# when: compose.mode == "dev"
# ansible.builtin.set_fact:
# web_fqdn: "{{ (certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Setting the FQDN for production
# when: compose.mode == "prod"
ansible.builtin.set_fact:
web_fqdn: "{{ (certbot.domains | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Moving git repository from initial path
block:
- name: Recursively copying directory and its contents to elsewhere
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.copy:
src: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.compose.name }}"
remote_src: true
dest: "{{ ansible_user_home.stdout }}/repos/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
register: new_compose_path
- name: Deleting directory at previous path
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.compose.name }}"
state: absent
- name: Creating directory for new bare repository
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/src"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Creating bare repository
ansible.builtin.command:
cmd: "git init --bare {{ source_code.repos.compose.name }}.git"
chdir: "{{ ansible_user_home.stdout }}/src"
creates: "{{ ansible_user_home.stdout }}/src/{{ source_code.repos.compose.name }}.git"
- name: Creating required SMTP-related container secret
become: true
# become_user: "{{ current_user.stdout }}"
ansible.builtin.lineinfile:
line: "{{ email.smtp.password }}"
path: "{{ ansible_user_home.stdout }}/.podsecrets/email.pass"
insertafter: EOF
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
create: true
backup: true
- name: Creating environment file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/all.env.j2
dest: "{{ ansible_user_home.stdout }}/.all.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: environ
- name: Creating environment file for email
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/email.env.j2
dest: "{{ ansible_user_home.stdout }}/.email.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: email_environ
- name: Creating a directory for container secrets
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.podsecrets"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
state: directory
- name: Creating directory for DBMS server configuration
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.config/{{ item }}"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "755"
state: directory
loop:
- caddy
- letsencrypt
- mysql
- redis
- gitea
- opengist
- tailscale
- glance
- name: Creating directory for main website root
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/srv/{{ web_fqdn }}"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "755"
state: directory
- name: Creating directory for caddy configuration
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.config/caddy"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
# - name: Pulling all needed container images for Compose services
# become: true
# become_user: "{{ current_user.stdout }}"
# ansible.builtin.command:
# cmd: podman-compose pull
# chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Calculating desired container states
block:
- name: Calculating desired container state for VPN client
ansible.builtin.set_fact:
# @TODO write case of at least one vpn client having a boolean attribute declaring whether it is a container
vpn_run: "{{ source_code.repos.compose.run and (vpn.clients | selectattr('name', 'in', web_fqdn) | length) == 1 and (compose.containers.vpn is defined and compose.containers.vpn != None) }}"
- name: Calculating desired container state for web server or reverse proxy server
ansible.builtin.set_fact:
server_run: "{{ source_code.repos.compose.run and caddy.containerized and (compose.containers.webserver is defined and compose.containers.webserver != None) }}"
- name: Calculatng desired container state for ACME challenge
ansible.builtin.set_fact:
ssl_run: "{{ server_run and certbot.containerized and (compose.containers.ssl is defined and compose.containers.ssl != None) }}"
- name: Calculating desired container state for database management
ansible.builtin.set_fact:
dbms_run: "{{ source_code.repos.compose.run and mysql.containerized and (compose.containers.db is defined and compose.containers.db != None) }}"
- name: Calculating desired container state for caching server
ansible.builtin.set_fact:
cache_run: "{{ source_code.repos.compose.run and redis.containerized and (compose.containers.cache is defined and compose.containers.cache != None) }}"
- name: Calculating desired container state for cloud server
ansible.builtin.set_fact:
cloud_run: "{{ source_code.repos.compose.run and nextcloud.containerized and (compose.containers.cloud is defined and compose.containers.cloud != None) }}"
- name: Calculating desired container state for forge server
ansible.builtin.set_fact:
forge_run: "{{ source_code.repos.compose.run and gitea.containerized and (compose.containers.forge is defined and compose.containers.forge != None ) }}"
- name: Calculating desired container state for pastebin server
ansible.builtin.set_fact:
pbin_run: "{{ source_code.repos.compose.run and gist.containerized and (compose.containers.pastebin is defined and compose.containers.pastebin != None) }}"
- name: Calculating desired container state for tailnet client
ansible.builtin.set_fact:
tail_run: "{{ source_code.repos.compose.run and tailscale.containerized and (compose.containers.tail is defined and compose.containers.tail != None) }}"
- name: Calculating desired container state for tailnet dashboard
ansible.builtin.set_fact:
dash_run: "{{ source_code.repos.compose.run and glance.containerized and (compose.containers.dash is defined and compose.containers.dash != None) }}"
- name: Running VPN client Compose files
when: vpn_run
block:
- name: Creating subdirectory for VPN client container specified by Compose file
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.wg/containerized"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Copying VPN client configuration files
become: true
become_user: "{{ current_user.stdout }}"
when: item.name == inventory_hostname
ansible.builtin.copy:
src: "user/wg/containerized/{{ item.name }}{{ (idx | string) }}.conf"
dest: "{{ ansible_user_home.stdout }}/.wg/containerized/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
loop: "{{ vpn.clients }}"
loop_control:
index_var: idx
- name: Creating and deploying VPN client container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
when: source_code.repos.compose.run and (vpn.clients | selectattr("name", "in", web_fqdn) | length) == 1 and (compose.containers.vpn is defined and compose.containers.vpn != None)
ansible.builtin.command:
cmd: "podman-compose up -d {{ compose.containers.vpn.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Opening port 51820
become: true
ansible.builtin.iptables:
chain: INPUT
protocol: "{{ item }}"
destination_port: 51820
jump: ACCEPT
comment: Open up port 51820
loop:
- udp
- tcp
- name: Spinning up database management container specified by Compose file
when: dbms_run
block:
- name: Creating required container secret for DBMS server container's root account
become: true
# become_user: "{{ current_user.stdout }}"
ansible.builtin.lineinfile:
line: "{{ mysql.password }}"
path: "{{ ansible_user_home.stdout }}/.podsecrets/root-mysql.pass"
insertafter: EOF
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
create: true
backup: true
- name: Creatng required container secret for DBMS server container's primary non-root account
become: true
# become_user: "{{ current_user.stdout }}"
ansible.builtin.lineinfile:
line: "{{ mysql.users.admin.password }}"
path: "{{ ansible_user_home.stdout }}/.podsecrets/user-mysql.pass"
insertafter: EOF
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
create: true
backup: true
- name: Creating environment file for DBMS server container specified in Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/mysql.env.j2
dest: "{{ ansible_user_home.stdout }}/.mysql.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: mysql_environ
- name: Creating and deploying DBMS server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose --env-file {{ mysql_environ.dest }} --env-file {{ environ.dest }} up -d {{ compose.containers.db.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
# @TODO see if manual creation of additional databases is necessary for the DBMS server container
# REDIS
- name: Spinning up caching container specified by Compose file
when: cache_run
block:
- name: Creating environment file for DBMS server container specified in Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/redis.env.j2
dest: "{{ ansible_user_home.stdout }}/.redis.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: redis_environ
- name: Creating and deploying cache server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose --env-file {{ environ.dest }} up -d {{ compose.containers.cache.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Spinning up cloud container specified by Compose file
when: cloud_run
block:
- name: Creating database necessary for cloud server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
when: dbms_run
containers.podman.podman_container_exec:
name: "{{ compose.containers.db.name }}"
argv:
- mysql
- "-u"
- "{{ mysql.users.admin.username }}"
- "-p{{ mysql.users.admin.password }}"
- "-e"
- "'CREATE DATABASE IF NOT EXISTS {{ mysql.users.admin.databases.nextcloud.name }};'"
detach: true
- name: Creating required cache-related container secret for cloud server container specified by Compose file
become: true
# become_user: "{{ current_user.stdout }}"
when: cache_run
ansible.builtin.lineinfile:
line: "{{ redis.password }}"
dest: "{{ ansible_user_home.stdout }}/.podsecrets/redis.pass"
insertafter: EOF
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
create: true
backup: true
- name: Creating environment file for cloud server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/nextcloud.env.j2
dest: "{{ ansible_user_home.stdout }}/.nextcloud.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: nextcloud_environ
- name: Creating and deploying DBMS server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose --env-file {{ mysql_environ.dest }} --env-file {{ email_environ.dest }} --env-file {{ nextcloud_environ.dest }} --env-file {{ environ.dest }} up -d {{ compose.containers.cloud.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Adding Caddyfile subdomain entry
when: "server_run and mode == 'prod'"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
{{ nextcloud.subdomain }}.{{ web_fqdn }} {
root /srv/{{ nextcloud.subdomain }}.{{ web_fqdn }}
file_server
php_fastcgi localhost:9000
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
templates
encode gzip
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED CLOUD DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
create: true
mode: "644"
state: present
- name: Adding Caddyfile subdomain entry
when: "server_run and (mode == 'dev' or caddy.scheme == 'http')"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
http://{{ nextcloud.subdomain }}.{{ web_fqdn }} {
root /srv/{{ nextcloud.subdomain }}.{{ web_fqdn }}
file_server
php_fastcgi localhost:9000
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
templates
encode gzip
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED CLOUD DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
create: true
mode: "644"
state: present
# - name: Restarting webserver / reverse proxy container
# become: true
# become_user: "{{ current_user.stdout }}"
# when: server_run
# containers.podman.podman_container:
# name: "{{ compose.containers.webserver.name }}"
# state: started
# force_restart: true
- name: Spinning up forge container specified by Compose file
when: forge_run
block:
- name: Creating database necessary for forge server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
when: dbms_run
containers.podman.podman_container_exec:
name: "{{ compose.containers.db.name }}"
argv:
- mysql
- "-u"
- "{{ mysql.users.admin.username }}"
- "-p{{ mysql.users.admin.password }}"
- "-e"
- "'CREATE DATABASE IF NOT EXISTS {{ mysql.users.admin.databases.gitea.name }};'"
detach: true
- name: Creating environment file for forge server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/gitea.env.j2
dest: "{{ ansible_user_home.stdout }}/.gitea.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: gitea_environ
- name: Creating and deploying forge server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose --env-file {{ mysql_environ.dest }} --env-file {{ email_environ.dest }} --env-file {{ gitea_environ.dest }} --env-file {{ environ.dest }} up -d {{ compose.containers.forge.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Adding Caddyfile subdomain entry
when: "server_run and mode == 'prod'"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
{{ gitea.subdomain }}.{{ web_fqdn }} {
reverse_proxy localhost:3000
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
file_server
templates
encode gzip
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED CLOUD DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
create: true
mode: "644"
state: present
- name: Adding Caddyfile subdomain entry
when: "server_run and (mode == 'dev' or caddy.scheme == 'http')"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
http://{{ gitea.subdomain }}.{{ web_fqdn }} {
reverse_proxy localhost:3000
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
file_server
templates
encode gzip
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED CLOUD DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
create: true
mode: "644"
state: present
# - name: Restarting webserver / reverse proxy container
# become: true
# become_user: "{{ current_user.stdout }}"
# when: server_run
# containers.podman.podman_container:
# name: "{{ compose.containers.webserver.name }}"
# state: started
# force_restart: true
- name: Spinning up pastebin container specified by Compose file
when: pbin_run
block:
- name: Creating database necessary for pastebin server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
when: dbms_run
containers.podman.podman_container_exec:
name: "{{ compose.containers.db.name }}"
argv:
- mysql
- "-u"
- "{{ mysql.users.admin.username }}"
- "-p{{ mysql.users.admin.password }}"
- "-e"
- "'CREATE DATABASE IF NOT EXISTS {{ mysql.users.admin.databases.opengist.name }};'"
detach: true
- name: Creating environment file for pastebin server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
when: pbin_run
ansible.builtin.template:
src: user/opengist.env.j2
dest: "{{ ansible_user_home.stdout }}/.opengist.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: opengist_environ
- name: Creating gist configuration file
become: true
become_user: "{{ current_user.stdout }}"
when: pbin_run
ansible.builtin.template:
src: user/config/opengist/config.yml.j2
dest: "{{ ansible_user_home.stdout }}/.config/opengist/config.yml"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
- name: Creating and deploying pastebin server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
when: pbin_run
ansible.builtin.command:
cmd: "podman-compose --env-file {{ opengist_environ.dest }} --env-file {{ mysql_environ.dest }} --env-file {{ environ.dest }} up -d {{ compose.containers.pastebin.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Adding Caddyfile subdomain entry
when: "server_run and mode == 'prod'"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
{{ gist.subdomain }}.{{ web_fqdn }} {
reverse_proxy localhost:6157
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
file_server
templates
encode gzip
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED CLOUD DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
create: true
mode: "644"
state: present
- name: Adding Caddyfile subdomain entry
when: "server_run and (mode == 'dev' or caddy.scheme == 'http')"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
http://{{ gist.subdomain }}.{{ web_fqdn }} {
reverse_proxy localhost:6157
handle_errors {
root /srv/{{ web_fqdn }}
rewrite /error/{err.status_code}.html
file_server
templates
encode gzip
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED CLOUD DOMAIN -->"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
create: true
mode: "644"
state: present
# - name: Restarting webserver / reverse proxy container
# become: true
# become_user: "{{ current_user.stdout }}"
# when: server_run
# containers.podman.podman_container:
# name: "{{ compose.containers.webserver.name }}"
# state: started
# force_restart: true
- name: Spinning up web or reverse proxy server container specified by Compose file
when: server_run
block:
- name: Creating directory for website subdomains
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/srv/{{ item }}.{{ web_fqdn }}"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
loop:
- certbot
- notes
- blog
- name: Creating directory for Caddy configuration
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/.caddy"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Creating and deploying webserver / reverse proxy server container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose --env-file {{ environ.dest }} up -d {{ compose.containers.webserver.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Creating volume subdirectory for main website root's error pages
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/srv/{{ web_fqdn }}/error"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Creating image files for main website root's error path
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.copy:
src: "user/srv/domain-root/error/{{ item }}"
dest: "{{ ansible_user_home.stdout }}/srv/{{ web_fqdn }}/error/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
backup: true
mode: "644"
loop:
- 503.html
- "mythe-sisyphus-klein.png"
- "dark-matter.png"
- name: Creating or updating Caddyfile at directory
when: "mode == 'prod' and ssl_run"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
http://{{ web_fqdn }} {
handle /.well-known/acme-challenge/* {
reverse_proxy localhost:80
}
handle {
redir https://{host}{uri} 308
}
}
:80 {
root /srv/certbot.{{ web_fqdn }}
browse
}
{{ web_fqdn }} {
respond 503
# root /srv/{{ web_fqdn }}
file_server
header /.well-known/openpgpkey/* {
Content-Type application/octet-stream
Access-Control-Allow-Origin *
}
handle_errors {
rewrite /error/{err.status_code}.html
templates
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED ROOT DOMAIN -->"
create: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
state: present
- name: Creating or updating Caddyfile at directory
when: "mode == 'prod' and not ssl_run"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
{{ web_fqdn }} {
respond 503
# root /srv/{{ web_fqdn }}
file_server
header /.well-known/openpgpkey/* {
Content-Type application/octet-stream
Access-Control-Allow-Origin *
}
handle_errors {
rewrite /error/{err.status_code}.html
templates
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED ROOT DOMAIN -->"
create: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
state: present
- name: Creating or updating Caddyfile at directory
when: "mode == 'dev' or caddy.scheme == 'http'"
ansible.builtin.blockinfile:
path: "{{ ansible_user_home.stdout }}/.config/caddy/Caddyfile"
block: |
http://{{ web_fqdn }} {
respond 503
# root /srv/{{ web_fqdn }}
file_server
header /.well-known/openpgpkey/* {
Content-Type application/octet-stream
Access-Control-Allow-Origin *
}
handle_errors {
rewrite /error/{err.status_code}.html
templates
}
}
prepend_newline: true
marker: "# <-- {mark} ANSIBLE MANAGED ROOT DOMAIN -->"
create: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
state: present
- name: Opening port 443
become: true
ansible.builtin.iptables:
chain: INPUT
protocol: "{{ item }}"
destination_port: 443
jump: ACCEPT
comment: Open up port 443
loop:
- udp
- tcp
- name: Opening ports
become: true
ansible.builtin.iptables:
chain: INPUT
protocol: tcp
destination_port: "{{ item }}"
jump: ACCEPT
comment: "Open up port {{ (item | string) }}"
loop:
- 80
# - name: Restarting webserver / reverse proxy container
# become: true
# become_user: "{{ current_user.stdout }}"
# containers.podman.podman_container:
# name: "{{ compose.containers.webserver.name }}"
# state: started
# force_restart: true
- name: Spinning up ACME challenge container specified by Compose file
when: ssl_run
ignore_errors: true
block:
- name: Creating environment file for SSL/TLS certificate acquisition container specified in Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/certbot.env.j2
dest: "{{ ansible_user_home.stdout }}/.certbot.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
register: certbot_environ
- name: Creating and deploying SSL/TLS certificate acquisition container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose --env-file {{ certbot_environ.dest }} --env-file {{ environ.dest }} up -d {{ compose.containers.ssl.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Spinning up tailnet container specified by Compose file
when: tail_run
block:
- name: Creating required tailnet container secret for tailnet container specified by Compose file
become: true
# become_user: "{{ current_user.stdout }}"
when: item.name == inventory_hostname
ansible.builtin.copy:
src: "{{ item.name }}-{{ headscale.users.admin.username }}@headscale/headscale{{ (idx | string) }}.key"
dest: "{{ ansible_user_home.stdout }}/.podsecrets/headscale.key"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
loop: "{{ headscale.clients }}"
loop_control:
index_var: idx
- name: Creating tailnet configuration file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/config/tailscale/conf.json.j2
dest: "{{ ansible_user_home.stdout }}/.config/tailscale/conf.json"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
- name: Creating and deploying tailnet container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose --env-file {{ environ.dest }} up -d {{ compose.containers.tail.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Spinning up dashboard container specified by Compose file
when: tail_run and dash_run
block:
- name: Creating glance configuration file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/config/glance/glance.yml.j2
dest: "{{ ansible_user_home.stdout }}/.config/glance/glance.yml"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
force: true
backup: true
- name: Creating and deploying dashboard container specified by Compose file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.command:
cmd: "podman-compose up -d {{ compose.containers.dash.name }}"
chdir: "{{ new_compose_path.dest }}{{ source_code.repos.compose.rpath | default('/independent') }}"
- name: Restarting webserver / reverse proxy container
become: true
become_user: "{{ current_user.stdout }}"
when: server_run
containers.podman.podman_container:
name: "{{ compose.containers.webserver.name }}"
state: started
force_restart: true
- name: Making running containers persist on user logout
become: true
ansible.builtin.shell:
cmd: loginctl enable-linger $(whoami)

View File

@@ -0,0 +1,45 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Moving git repository from initial path
block:
- name: Recursively copying directory and its contents to elsewhere
ansible.builtin.copy:
src: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.site.name }}"
remote_src: true
dest: "{{ ansible_user_home.stdout }}/repos/"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
register: new_compose_path
- name: Deleting directory at previous path
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ source_code.repos.site.name }}"
state: absent
- name: Creating directory for new bare repository
ansible.builtin.file:
path: "{{ ansible_user_home.stdout }}/src"
recurse: true
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
state: directory
- name: Creating bare repository
ansible.builtin.command:
cmd: "git init --bare {{ source_code.repos.site.name }}.git"
chdir: "{{ ansible_user_home.stdout }}/src"
creates: "{{ ansible_user_home.stdout }}/src/{{ source_code.repos.site.name }}.git"
- name: Running website
when: source_code.repos.site.run
# become: true
# become_user: "{{ current_user.stdout }}"
block:
- name: Warning about lack of implementation
ansible.builtin.debug:
msg: Not yet implemented

View File

@@ -6,52 +6,81 @@
register: ansible_user_home
- name: Linking binaries to directories already in PATH environment variable
become: true
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/downloads/archives/released/surge/{{ item }}"
dest: "/usr/bin/{{ item }}"
state: link
loop:
- surge
- name: Installing accompanying complementary Surge system service
ansible.builtin.command:
cmd: surge service install
- name: Acquiring API token for remote Surge service control
ansible.builtin.command:
cmd: surge token
register: surge_token
- name: Pausing to inquire about how to proceed
ansible.builtin.pause:
prompt: "Type \"fetch\" to get the Surge API token, or \"show\" to see it for manual copying instead"
echo: true
register: data_method
- name: Choosing to present Surge API token to Control Node
when: data_method.user_input == "show"
- name: Starting to spin up the Surge service
when: surge.service.enabled and not surge.containerized
block:
- name: Installing accompanying complementary Surge system service
become: true
ansible.builtin.command:
cmd: surge service install
- name: Creating corresponding SystemD service unit
become: true
ansible.builtin.copy:
src: systemd/system/surge.service
dest: /etc/systemd/system/surge.service
owner: root
group: root
force: true
backup: true
- name: Acquiring API token for remote Surge service control
become: true
ansible.builtin.command:
cmd: surge token
register: surge_token
- name: Pausing to inquire about how to proceed
ansible.builtin.pause:
prompt: "Type \"fetch\" to get the Surge API token, or \"show\" to see it for manual copying instead"
echo: true
register: data_method
- name: Presenting Surge API token to Control Node
when: data_method.user_input == "show"
ansible.builtin.debug:
msg: "Make sure to store the following API token for Surge:\n {{ surge_token.stdout }}"
- name: Giving opportunity to manually copy Surge API token
when: data_method.user_input == "show"
ansible.builtin.pause:
- name: Choosing to provide file on control node containing Surge's API token
when: data_method.user_input == "fetch"
block:
- name: Creating temporary file on managed node that stores Surge API token
become: true
when: data_method.user_input == "fetch"
ansible.builtin.copy:
content: "{{ surge_token.stdout }}"
dest: /tmp/surge.token
dest: /tmp/surge.secret
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "644"
register: surge_token
- name: Placing Surge API token into file on control node
when: data_method.user_input == "fetch"
ansible.builtin.fetch:
src: "{{ surge_token.dest }}"
dest: "./.tmp/{{ inventory_hostname }}-surge/surge.secret"
flat: true
- name: Placing Surge API token into file on control node
when: data_method.user_input == "fetch"
ansible.builtin.fetch:
src: "{{ surge_token.dest }}"
dest: "./roles/init-server/files/{{ inventory_hostname }}-surge/surge.secret"
flat: true
- name: Informing control node of acquired files
when: data_method.user_input == "fetch"
ansible.builtin.debug:
msg: "The Surge API token file have been duplicated to '/var/tmp/{{ inventory_hostname }}/surge.token' at the control node."
msg: "The Surge API token file have been duplicated to './.tmp/{{ inventory_hostname }}-surge/surge.secret' at the control node."
- name: Giving control node user time to read the aforementiioned message
when: data_method.user_input == "fetch"
ansible.builtin.pause:
seconds: 30
seconds: 30
- name: Starting and enabling Surge SystemD service unit
become: true
ansible.builtin.systemd_service:
name: surge
scope: system
state: started
enabled: true
daemon_reload: true

View File

@@ -15,8 +15,11 @@
ansible.builtin.shell:
cmd: "{{ ansible_user_home.stdout }}/.local/bin/uv-install.sh"
creates: "{{ ansible_user_home.stdout }}/.local/bin/uv"
async: 600
poll: 5
- name: Linking binaries to directories already in PATH environment variable
become: true
ignore_errors: true
ansible.builtin.file:
src: "{{ ansible_user_home.stdout }}/.local/bin/{{ item }}"
dest: "/usr/bin/{{ item }}"

View File

@@ -37,6 +37,7 @@
force: true
mode: "644"
follow_redirects: safe
timeout: 300
- name: Configuring ViM
become: true
become_user: "{{ current_user.stdout }}"

View File

@@ -0,0 +1,57 @@
---
- name: Enabling Wireguard kernel module
become: true
community.general.modprobe:
name: wireguard
persistent: present
state: present
- name: Enable IP forwarding
become: true
when: wireguard.ip_forward
block:
- name: Enabling IPv4 forwarding
ansible.posix.sysctl:
name: net.ipv4.ip_forward
value: "1"
sysctl_set: true
state: present
- name: Marking IPv4 forwarded traffic as valid
ansible.posix.sysctl:
name: net.ipv4.conf.all.src_valid_mark
value: "1"
sysctl_set: true
state: present
- name: Enabling IPv6 forwarding
ansible.posix.sysctl:
name: net.ipv6.conf.all.forwarding
value: "1"
sysctl_set: true
state: present
- name: Marking IPv6 traffic as valid
ansible.posix.sysctl:
name: net.ipv6.conf.all.src_valid_mark
value: "1"
sysctl_set: true
state: present
- name: Preparing to allow Wireguard logging
when: "wireguard.debug"
block:
- name: Creating subdirectory for system kernel debugging
become: true
ansible.builtin.file:
path: /sys/kernel/debug/dynamic_debug
recurse: true
owner: root
group: root
mode: "755"
state: directory
- name: Enabling Wireguard system logging
become: true
ansible.builtin.copy:
content: "module wireguard +p"
dest: /sys/kernel/debug/dynamic_debug/control
owner: root
group: root
mode: "644"
force: true

View File

@@ -87,13 +87,6 @@
# @TODO uncomment below before continuing with testing previous task
# - name: Premature end of play
# ansible.builtin.meta: end_play
- name: Updating package cache
ansible.builtin.apt:
update_cache: true
- name: Updating package cache
ansible.builtin.apt:
upgrade: dist
autoremove: true
- name: Registering a package source
when: item.sources != None
ansible.builtin.deb822_repository:
@@ -108,6 +101,10 @@
- name: Updating package cache
ansible.builtin.apt:
update_cache: true
- name: Upgrading
ansible.builtin.apt:
upgrade: dist
autoremove: true
- name: Installing a local package in managed node
when: item.uri != None
ansible.builtin.apt:
@@ -121,6 +118,8 @@
name: "{{ item.name }}"
state: present
notify: "{{ item.handler | default('default') }}"
async: 600
poll: 5
loop: "{{ ((pkgs.mngr.core | default([]))) | rejectattr('uri', 'search', '\\.deb$') }}"
tags:
- get_mngr_pkgs
@@ -137,7 +136,8 @@
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
force: true
mode: "744"
mode: "755"
timeout: 300
notify: "{{ ((pkgs.script.core | default([])))[idx].handler | default('default') }}"
loop: "{{ (pkgs.script.core | default([])) }}"
loop_control:
@@ -206,7 +206,6 @@
dest: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ item.name }}"
version: "{{ item.branch }}"
clone: true
single_branch: true
notify: "{{ item.handler | default('default') }}"
loop: "{{ (pkgs.git_repos.core | default([])) }}"
register: installation_repos
@@ -225,9 +224,10 @@
dest: "/usr/bin/{{ item.name }}"
owner: root
group: root
mode: "744"
mode: "755"
force: true
backup: true
notify: "{{ item.handler }}"
timeout: 300
loop: "{{ (pkgs.binaries.core | default([])) }}"

View File

@@ -0,0 +1,20 @@
---
- name: Acquiring home of current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo ~{{ ansible_user }}"
register: ansible_user_home
- name: Acquiring current user
when: ansible_facts["system"] == "Linux"
ansible.builtin.shell:
cmd: "echo {{ ansible_user }}"
register: current_user
- name: Copying NetRC file
become: true
become_user: "{{ current_user.stdout }}"
ansible.builtin.template:
src: user/netrc.j2
dest: "{{ ansible_user_home.stdout }}/.netrc"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "600"

View File

@@ -2,6 +2,22 @@
---
# tasks file for roles/init-vps
# @NOTE server deployment method is based on task tags compiled herein
- name: Informing user of requirement of two main domains
when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
ansible.builtin.fail:
msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
ansible.builtin.fail:
msg: At least one of the FQDNs must have a wildcard
# - name: Setting the FQDN for development
# when: mode == "dev"
# ansible.builtin.set_fact:
# fqdn: "{{ (certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Setting the FQDN
# when: mode == "prod"
ansible.builtin.set_fact:
fqdn: "{{ (certbot.domains | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Finding SSH public keys for root
delegate_facts: true
delegate_to: localhost
@@ -44,7 +60,7 @@
- name: Creating the VPS
linode.cloud.instance:
api_token: "{{ token | prompted_token.user_input }}"
label: "{{ instance }}"
label: "{{ fqdn }}"
type: g6-standard-2
image: "{{ operating_system }}"
disk_encryption: enabled
@@ -86,7 +102,7 @@
ansible.builtin.wait_for_connection:
delay: 20
timeout: 300
loop: "{{ groups[instance] | default(hostvars[instance]) }}"
loop: "{{ groups[fqdn] | default(hostvars[fqdn]) }}"
- name: Checking if that server has required operating system
delegate_to: "{{ item }}"
delegate_facts: true
@@ -94,7 +110,7 @@
when: ansible_facts["system"] != "Linux" and item is ansible.utils['ip_pref']
ansible.builtin.fail:
msg: Unsupported operating system found
loop: "{{ groups[instance] | default(hostvars[instance]) }}"
loop: "{{ groups[fqdn] | default(hostvars[fqdn]) }}"
- name: Checking if that server has required Linux distro
delegate_to: "{{ item }}"
delegate_facts: true
@@ -102,7 +118,7 @@
when: ansible_facts["system"] == "Linux" and ansible_facts["os_family"] != "Debian" and item is ansible.utils['ip_pref']
ansible.builtin.fail:
msg: Unsupported Linux distro found
loop: "{{ groups[instance] | default(hostvars[instance]) }}"
loop: "{{ groups[fqdn] | default(hostvars[fqdn]) }}"
- name: Providing authorized keys for server root account
delegate_to: "{{ item[0] }}"
delegate_facts: true
@@ -112,6 +128,6 @@
user: "{{ ansible_user }}"
key: "{{ lookup('file', item[1]) }}"
state: present
loop: "{{ (groups[instance] | default(hostvars[instance])) | product(root_pubkey_paths) }}"
loop: "{{ (groups[fqdn] | default(hostvars[fqdn])) | product(root_pubkey_paths) }}"
tags:
- lan

View File

@@ -88,13 +88,6 @@
# @TODO uncomment below before continuing with testing previous task
# - name: Premature end of play
# ansible.builtin.meta: end_play
- name: Updating package cache
ansible.builtin.apt:
update_cache: true
- name: Updating package cache
ansible.builtin.apt:
upgrade: dist
autoremove: true
- name: Registering a package source
when: item.sources != None
ansible.builtin.deb822_repository:
@@ -109,6 +102,10 @@
- name: Updating package cache
ansible.builtin.apt:
update_cache: true
- name: Upgrading
ansible.builtin.apt:
upgrade: dist
autoremove: true
- name: Installing a local package in managed node
when: item.uri != None
ansible.builtin.apt:
@@ -122,6 +119,8 @@
name: "{{ item.name }}"
state: latest
notify: "{{ item.handler | default('default') }}" # @TODO create corresponding roles/init-vps handlers
async: 600
poll: 5
loop: "{{ (pkgs.mngr.userspace | default([])) | rejectattr('uri', 'search', '\\.deb$') }}"
tags:
- get_mngr_pkgs
@@ -138,7 +137,8 @@
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
force: true
mode: "744"
mode: "755"
timeout: 300
notify: "{{ (pkgs.script.userspace | default([]))[idx].handler | default('default') }}"
loop: "{{ (pkgs.script.userspace | default([])) }}"
loop_control:
@@ -206,7 +206,6 @@
dest: "{{ ansible_user_home.stdout }}/repos/.foreign/{{ item.name }}"
version: "{{ item.branch }}"
clone: true
single_branch: true
notify: "{{ item.handler | default('default') }}"
loop: "{{ (pkgs.git_repos.userspace | default([])) }}"
register: installation_repos
@@ -225,8 +224,9 @@
dest: "/usr/bin/{{ item.name }}"
owner: root
group: root
mode: "744"
mode: "755"
force: true
backup: true
notify: "{{ item.handler }}"
timeout: 300
loop: "{{ (pkgs.binaries.userspace | default([])) }}"