diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index b24358c..6023103 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -14,6 +14,16 @@ on:
workflow_dispatch:
jobs:
+ lint:
+ runs-on: ubuntu-24.04
+ steps:
+ - name: Check out the repository
+ uses: actions/checkout@v4
+ - name: Run ansible-lint
+ uses: ansible/ansible-lint@v25
+ with:
+ args: "-c ansible-lint.yml"
+
encoding:
runs-on: ubuntu-24.04
steps:
diff --git a/Folder.DotSettings b/Folder.DotSettings
new file mode 100644
index 0000000..385f3df
--- /dev/null
+++ b/Folder.DotSettings
@@ -0,0 +1,8 @@
+
+ True
+ True
+ True
+ True
+ True
+ True
+ True
\ No newline at end of file
diff --git a/README.md b/README.md
index d18859b..e287c5d 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@ Host specification
- [codingteam.org.ru][hosts/ctor]
- [cthulhu-3][hosts/cthulhu-3]
- [omnissiah][hosts/omnissiah]
+- [xmpp2][hosts.xmpp2]
Documentation
-------------
@@ -40,6 +41,7 @@ The license indication in the project's sources is compliant with the [REUSE spe
[codingteam.org.ru]: https://codingteam.org.ru
[devops]: https://ru.wikipedia.org/wiki/DevOps
[docs.license]: LICENSES/MIT.txt
+[host.xmpp2]: xmpp2/README.md
[hosts/cthulhu-3]: cthulhu-3/Host.md
[hosts/ctor]: ctor/Host.md
[hosts/omnissiah]: omnissiah/Host.md
diff --git a/REUSE.toml b/REUSE.toml
new file mode 100644
index 0000000..7bd1cfb
--- /dev/null
+++ b/REUSE.toml
@@ -0,0 +1,10 @@
+version = 1
+SPDX-PackageName = "devops"
+SPDX-PackageSupplier = "codingteam/devops contributors "
+SPDX-PackageDownloadLocation = "https://github.com/codingteam/devops"
+
+[[annotations]]
+path = "**.DotSettings"
+precedence = "aggregate"
+SPDX-FileCopyrightText = "2025 Friedrich von Never "
+SPDX-License-Identifier = "MIT"
diff --git a/ansible-lint.yml b/ansible-lint.yml
new file mode 100644
index 0000000..87c7275
--- /dev/null
+++ b/ansible-lint.yml
@@ -0,0 +1,7 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+exclude_paths:
+ - .github/ # no Ansible plays in there
+ - xmpp2/default.yml # just a list of other files
diff --git a/requirements.yml b/requirements.yml
new file mode 100644
index 0000000..5b744d9
--- /dev/null
+++ b/requirements.yml
@@ -0,0 +1,12 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+---
+collections:
+ - name: ansible.posix
+ version: 1.5.4
+ - name: community.docker
+ version: 3.7.0
+ - name: community.general
+ version: 8.3.0
diff --git a/xmpp2/.gitignore b/xmpp2/.gitignore
new file mode 100644
index 0000000..fb781b9
--- /dev/null
+++ b/xmpp2/.gitignore
@@ -0,0 +1,8 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+hosts.ini
+
+vars/secrets.yml
+vars/vars.yml
diff --git a/xmpp2/README.md b/xmpp2/README.md
new file mode 100644
index 0000000..5fcef69
--- /dev/null
+++ b/xmpp2/README.md
@@ -0,0 +1,39 @@
+
+
+xmpp2 host
+==========
+- **Provider:** Digital Ocean
+- **OS**: Ubuntu 24.04
+
+How to Deploy
+-------------
+1. Copy `hosts.example.ini` to `hosts.ini`, fix the host connection details if needed.
+2. Copy `vars/vars.example.yml` to `vars/vars.yml` and adjust it accordingly.
+3. Copy `vars/secrets.example.yml` to `vars/secrets.yml` and adjust it accordingly.
+4. `ansible-vault encrypt vars/secrets.yml`
+5. To **check the results** without applying, run `ansible-playbook --ask-vault-pass --ask-become-pass --check --diff default.yml`.
+
+ To **deploy**, run `ansible-playbook --ask-vault-pass --ask-become-pass default.yml`.
+
+If on Windows, feel free to use scripts `ansible-vault.ps1`, `ansible-playbook.ps1` as a substitute to use Ansible from WSL.
+
+If running deployment for the first time, then run `ansible-playbook --ask-vault-pass auth.yml` to set up the user accounts and access properly.
+
+Standard Operating Procedures
+-----------------------------
+
+### Dump Database Backup for LogList
+```console
+$ docker exec -i loglist.postgresql pg_dump -d loglist -U postgres -F custom --no-acl > loglist.dmp
+```
+
+### Restore Database Backup for LogList
+```console
+$ docker cp loglist.dmp loglist.postgresql:/loglist.dmp
+$ docker exec -i loglist.postgresql pg_restore -d loglist -U loglist --clean --no-owner -1 /loglist.dmp
+$ docker exec -i loglist.postgresql rm /loglist.dmp
+```
diff --git a/xmpp2/ansible-playbook.ps1 b/xmpp2/ansible-playbook.ps1
new file mode 100644
index 0000000..4e40c4e
--- /dev/null
+++ b/xmpp2/ansible-playbook.ps1
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+wsl --distribution Ubuntu ansible-playbook --inventory hosts.ini @args -e 'ansible_ssh_pipelining=True'
diff --git a/xmpp2/ansible-vault.ps1 b/xmpp2/ansible-vault.ps1
new file mode 100644
index 0000000..f818024
--- /dev/null
+++ b/xmpp2/ansible-vault.ps1
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+wsl --distribution Ubuntu ansible-vault @args
diff --git a/xmpp2/auth.yml b/xmpp2/auth.yml
new file mode 100644
index 0000000..157f2bf
--- /dev/null
+++ b/xmpp2/auth.yml
@@ -0,0 +1,45 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+---
+- name: Set up the users and authentication
+ hosts: xmpp2
+ become: true
+
+ vars_files:
+ - secrets.yml
+ - vars.yml
+
+ handlers:
+ - name: Reload sshd
+ ansible.builtin.service:
+ name: ssh
+ state: reloaded
+
+ tasks:
+ - name: Ensure a group exists for those who can connect with SSH
+ ansible.builtin.group:
+ name: sshuser
+
+ - name: Ensure a user exists and can SSH into the machine
+ ansible.builtin.user:
+ name: '{{ user.name }}'
+ shell: /bin/bash
+ groups: ['sudo', 'sshuser']
+ append: true
+ home: '/home/{{ user.name }}'
+ password_lock: false
+ password: '{{ user_secrets.password_hash }}'
+
+ - name: Ensure the user can use SSH
+ ansible.posix.authorized_key:
+ user: '{{ user.name }}'
+ key: '{{ user.ssh_public_key }}'
+
+ - name: Ensure only members of sshuser group can connect via SSH
+ ansible.builtin.lineinfile:
+ path: /etc/ssh/sshd_config
+ line: 'AllowGroups sshuser'
+ validate: 'sshd -f %s -t'
+ notify: Reload sshd
diff --git a/xmpp2/certbot.yml b/xmpp2/certbot.yml
new file mode 100644
index 0000000..d89ee39
--- /dev/null
+++ b/xmpp2/certbot.yml
@@ -0,0 +1,23 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+---
+- name: Configure Certbot for certificate renewal
+ hosts: xmpp2
+ become: true
+
+ tasks:
+ - name: Install certbot
+ community.general.snap:
+ name: certbot
+ classic: true
+
+ # One-time setup should be performed manually, see the documentation:
+ # https://certbot.eff.org/instructions?ws=nginx&os=snap&tab=standard
+ #
+ # sudo certbot --nginx -d codingteam.org.ru -d loglist.xyz -d www.loglist.xyz
+ #
+ # Verify the changes to the web server configuration files performed by this command.
+ #
+ # Further updates are done by snap.certbot.renew.timer — see `systemctl list-timers` for details.
diff --git a/xmpp2/codingteam.org.ru.yml b/xmpp2/codingteam.org.ru.yml
new file mode 100644
index 0000000..78e6ee0
--- /dev/null
+++ b/xmpp2/codingteam.org.ru.yml
@@ -0,0 +1,56 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+---
+- name: Main site for codingteam.org.ru
+ hosts: xmpp2
+ become: true
+
+ vars:
+ codingteam_org_ru_version: v1.2.1
+
+ handlers:
+ - name: Prune Docker
+ community.docker.docker_prune:
+ containers: true
+ images: true
+ images_filters:
+ dangling: false
+ networks: true
+ volumes: true
+ builder_cache: true
+
+ - name: Reload nginx
+ ansible.builtin.service:
+ name: nginx
+ state: reloaded
+
+ tasks:
+ - name: Set up the Docker container
+ community.docker.docker_container:
+ name: codingteam.org.ru
+ image_name_mismatch: recreate
+ image: codingteam/codingteam.org.ru:{{ codingteam_org_ru_version }}
+ published_ports:
+ - '5000:5000'
+ restart_policy: unless-stopped
+ default_host_ip: ''
+ env:
+ ASPNETCORE_URLS: "http://+:5000" # otherwise, it can't be reached (listens to "localhost" only?)
+ notify: Prune Docker
+
+ - name: Set up the nginx configuration file
+ ansible.builtin.copy:
+ src: nginx/conf.d/codingteam.org.ru.conf
+ dest: /etc/nginx/conf.d/codingteam.org.ru.conf
+ mode: "u=rx,go=rx"
+ notify: Reload nginx
+
+ - name: Create a directory for the old logs # uploaded manually
+ ansible.builtin.file:
+ path: /opt/codingteam/old-logs
+ state: directory
+ owner: www-data
+ group: www-data
+ mode: "u=rx,go=rx"
diff --git a/xmpp2/default.yml b/xmpp2/default.yml
new file mode 100644
index 0000000..69564ed
--- /dev/null
+++ b/xmpp2/default.yml
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+- import_playbook: auth.yml
+- import_playbook: nginx.yml
+- import_playbook: docker.yml
+- import_playbook: codingteam.org.ru.yml
+- import_playbook: loglist.yml
+- import_playbook: certbot.yml
diff --git a/xmpp2/docker.yml b/xmpp2/docker.yml
new file mode 100644
index 0000000..2eb9f84
--- /dev/null
+++ b/xmpp2/docker.yml
@@ -0,0 +1,24 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+---
+- name: Install Docker
+ hosts: xmpp2
+ become: true
+
+ vars_files:
+ - vars.yml
+
+ tasks:
+ - name: Install the Docker package
+ ansible.builtin.apt:
+ cache_valid_time: 86400
+ name: docker.io
+ state: present
+
+ - name: Add the admin user to docker group
+ ansible.builtin.user:
+ name: '{{ user.name }}'
+ groups: docker
+ append: true
diff --git a/xmpp2/files/loglist/application.conf b/xmpp2/files/loglist/application.conf
new file mode 100644
index 0000000..b8d5dd9
--- /dev/null
+++ b/xmpp2/files/loglist/application.conf
@@ -0,0 +1,31 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+play.http.secret.key = ${HTTP_SECRET_KEY}
+play.i18n.langs = ["en"]
+
+feed.limit = 30
+
+db.default.driver = org.postgresql.Driver
+db.default.url = ${DATABASE_URL}
+
+play.evolutions.autocommit = false
+play.evolutions.db.default.autoApply = ${APPLY_EVOLUTIONS_SILENTLY}
+
+recaptcha.publickey = ${RECAPTCHA_PUBLIC_KEY}
+recaptcha.privatekey = ${RECAPTCHA_PRIVATE_KEY}
+
+basicAuth.username = ${BASIC_AUTH_USERNAME}
+basicAuth.password = ${BASIC_AUTH_PASSWORD}
+
+approval.smtpHost = ${APPROVAL_SMTP_HOST}
+approval.email = ${APPROVAL_EMAIL}
+approval.emailPassword = ${APPROVAL_EMAIL_PASSWORD}
+
+play.modules.enabled += "scalikejdbc.PlayModule"
+
+play.filters.enabled += play.filters.hosts.AllowedHostsFilter
+play.filters.hosts {
+ allowed = ["loglist.xyz"]
+}
diff --git a/xmpp2/files/loglist/init_db.sql b/xmpp2/files/loglist/init_db.sql
new file mode 100644
index 0000000..24c1713
--- /dev/null
+++ b/xmpp2/files/loglist/init_db.sql
@@ -0,0 +1,5 @@
+-- SPDX-FileCopyrightText: 2025 Friedrich von Never
+--
+-- SPDX-License-Identifier: MIT
+
+CREATE EXTENSION pgcrypto;
diff --git a/xmpp2/files/nginx/conf.d/codingteam.org.ru.conf b/xmpp2/files/nginx/conf.d/codingteam.org.ru.conf
new file mode 100644
index 0000000..b6e5af8
--- /dev/null
+++ b/xmpp2/files/nginx/conf.d/codingteam.org.ru.conf
@@ -0,0 +1,32 @@
+# SPDX-FileCopyrightText: 2016-2025 codingteam/devops contributors
+#
+# SPDX-License-Identifier: MIT
+
+server {
+ listen 443 ssl http2;
+ server_name codingteam.org.ru;
+ include /etc/nginx/ssl.conf;
+
+ location /old-logs/ {
+ alias /opt/codingteam/old-logs/;
+ index index.html;
+ }
+
+ location / {
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Host codingteam.org.ru;
+ proxy_http_version 1.1;
+ proxy_pass http://localhost:5000/;
+ }
+}
+
+server {
+ listen 80;
+ server_name codingteam.org.ru;
+
+ location / {
+ rewrite ^(.*)$ https://codingteam.org.ru$1 permanent;
+ }
+}
diff --git a/xmpp2/files/nginx/conf.d/loglist.conf b/xmpp2/files/nginx/conf.d/loglist.conf
new file mode 100644
index 0000000..5440a9d
--- /dev/null
+++ b/xmpp2/files/nginx/conf.d/loglist.conf
@@ -0,0 +1,45 @@
+# SPDX-FileCopyrightText: 2016-2025 codingteam/devops contributors
+#
+# SPDX-License-Identifier: MIT
+
+server {
+ listen 443 ssl http2;
+ server_name loglist.xyz;
+ include /etc/nginx/ssl.conf;
+
+ location / {
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Host loglist.xyz;
+ proxy_http_version 1.1;
+ proxy_pass http://localhost:9000/;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ server_name *.loglist.xyz;
+ include /etc/nginx/ssl.conf;
+
+ location / {
+ return 301 https://loglist.xyz$request_uri;
+ }
+}
+
+server {
+ listen 80;
+ server_name loglist.xyz;
+
+ location / {
+ rewrite ^(.*)$ https://loglist.xyz$1 permanent;
+ }
+}
+
+server {
+ listen 80;
+ server_name *.loglist.xyz;
+ location / {
+ return 301 https://loglist.xyz$request_uri;
+ }
+}
diff --git a/xmpp2/files/nginx/nginx.conf b/xmpp2/files/nginx/nginx.conf
new file mode 100644
index 0000000..f9b0c9f
--- /dev/null
+++ b/xmpp2/files/nginx/nginx.conf
@@ -0,0 +1,30 @@
+# SPDX-FileCopyrightText: 2016-2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+error_log /var/log/nginx/error.log;
+
+events {
+ worker_connections 768;
+}
+
+http {
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 60;
+ types_hash_max_size 2048;
+
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+ ssl_prefer_server_ciphers on;
+
+ gzip on;
+
+ include /etc/nginx/conf.d/*.conf;
+}
diff --git a/xmpp2/files/nginx/ssl.conf b/xmpp2/files/nginx/ssl.conf
new file mode 100644
index 0000000..5e80eab
--- /dev/null
+++ b/xmpp2/files/nginx/ssl.conf
@@ -0,0 +1,9 @@
+# SPDX-FileCopyrightText: 2017-2025 codingteam/devops contributors
+#
+# SPDX-License-Identifier: MIT
+
+ssl_certificate /etc/letsencrypt/live/codingteam.org.ru/fullchain.pem;
+ssl_certificate_key /etc/letsencrypt/live/codingteam.org.ru/privkey.pem;
+ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ssl_ciphers "HIGH:!aNULL:!MD5:!kEDH";
+add_header Strict-Transport-Security 'max-age=15552000';
diff --git a/xmpp2/hosts.example.ini b/xmpp2/hosts.example.ini
new file mode 100644
index 0000000..512c65d
--- /dev/null
+++ b/xmpp2/hosts.example.ini
@@ -0,0 +1,6 @@
+; SPDX-FileCopyrightText: 2025 Friedrich von Never
+;
+; SPDX-License-Identifier: MIT
+
+[xmpp2]
+xmpp2 ansible_user=mario ansible_ssh_private_key_file=/home/mario/.ssh/xmpp2
diff --git a/xmpp2/loglist.yml b/xmpp2/loglist.yml
new file mode 100644
index 0000000..f25e6fe
--- /dev/null
+++ b/xmpp2/loglist.yml
@@ -0,0 +1,122 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+---
+- name: Application service for loglist.xyz
+ hosts: xmpp2
+ become: true
+
+ vars:
+ # Container versions:
+ postgresql_version: 9.3
+ loglist_version: 2.0.1
+
+ # Paths on host:
+ host_db_init_scripts_dir: /opt/codingteam/loglist/init_db_scripts
+ host_data_dir: /opt/codingteam/loglist/data
+ host_config_dir: /opt/codingteam/loglist/config
+
+ # Paths in containers:
+ container_data_dir: /data
+
+ vars_files:
+ - secrets.yml
+
+ handlers:
+ - name: Prune Docker
+ community.docker.docker_prune:
+ containers: true
+ images: true
+ images_filters:
+ dangling: false
+ networks: true
+ volumes: true
+ builder_cache: true
+
+ - name: Reload nginx
+ ansible.builtin.service:
+ name: nginx
+ state: reloaded
+
+ tasks:
+ - name: Create directories
+ ansible.builtin.file:
+ path: '{{ item }}'
+ state: directory
+ mode: 'u=rx,g,o=r'
+ loop:
+ - '{{ host_db_init_scripts_dir }}'
+ - '{{ host_data_dir }}'
+ - '{{ host_config_dir }}'
+
+ - name: Create the Docker network
+ community.docker.docker_network:
+ name: loglist
+
+ - name: Copy the database initialization script
+ ansible.builtin.copy:
+ src: loglist/init_db.sql
+ dest: '{{ host_db_init_scripts_dir }}/init_db.sql'
+ mode: 'u,g,o=rx'
+
+ - name: Set up the database container
+ community.docker.docker_container:
+ name: loglist.postgresql
+ image_name_mismatch: recreate
+ image: postgres:{{ postgresql_version }}
+ published_ports:
+ - '5423'
+ env:
+ POSTGRES_DB: loglist
+ POSTGRES_USER: loglist
+ POSTGRES_PASSWORD: '{{ loglist_secrets.db_password }}'
+ PGDATA: '{{ container_data_dir }}'
+ volumes:
+ - '{{ host_db_init_scripts_dir }}/:/docker-entrypoint-initdb.d/'
+ - '{{ host_data_dir }}/:/{{ container_data_dir }}/'
+ networks:
+ - name: loglist
+ default_host_ip: ''
+ notify: Prune Docker
+
+ - name: Copy the application configuration file
+ ansible.builtin.copy:
+ src: loglist/application.conf
+ dest: '{{ host_config_dir }}/application.conf'
+ mode: 'u,g,o=r'
+
+ - name: Set up the application container
+ community.docker.docker_container:
+ name: loglist.app
+ image_name_mismatch: recreate
+ image: codingteam/loglist:{{ loglist_version }}
+ published_ports:
+ - '9000:9000'
+ env:
+ APPLY_EVOLUTIONS_SILENTLY: 'true'
+ APPROVAL_EMAIL: '{{ loglist_secrets.approval_email.name }}'
+ APPROVAL_EMAIL_PASSWORD: '{{ loglist_secrets.approval_email.password }}'
+ APPROVAL_SMTP_HOST: '{{ loglist_secrets.approval_email.smtp_host }}'
+ BASIC_AUTH_PASSWORD: '{{ loglist_secrets.basic_auth.password }}'
+ BASIC_AUTH_USERNAME: '{{ loglist_secrets.basic_auth.username }}'
+ DATABASE_URL: 'jdbc:postgresql://loglist.postgresql/loglist?user=loglist&password={{ loglist_secrets.db_password }}'
+ JAVA_OPTS: '-Xmx200m -Xss512k -XX:+UseCompressedOops'
+ RECAPTCHA_PRIVATE_KEY: '{{ loglist_secrets.recaptcha.private_key }}'
+ RECAPTCHA_PUBLIC_KEY: '{{ loglist_secrets.recaptcha.public_key }}'
+ HTTP_SECRET_KEY: '{{ loglist_secrets.http_secret_key }}'
+ volumes:
+ - '{{ host_db_init_scripts_dir }}/:/docker-entrypoint-initdb.d/'
+ - '{{ host_data_dir }}/:/{{ container_data_dir }}/'
+ - '{{ host_config_dir }}/application.conf:/app/conf/application.conf'
+ networks:
+ - name: loglist
+ default_host_ip: ''
+ notify: Prune Docker
+
+ - name: Set up the nginx configuration file
+ ansible.builtin.copy:
+ src: nginx/conf.d/loglist.conf
+ dest: /etc/nginx/conf.d/loglist.conf
+ mode: "u=rx,go=rx"
+ notify: Reload nginx
diff --git a/xmpp2/nginx.yml b/xmpp2/nginx.yml
new file mode 100644
index 0000000..23b30a4
--- /dev/null
+++ b/xmpp2/nginx.yml
@@ -0,0 +1,41 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+---
+- name: Install and configure Nginx
+ hosts: xmpp2
+ become: true
+
+ handlers:
+ - name: Reload nginx
+ ansible.builtin.service:
+ name: nginx
+ state: reloaded
+
+ tasks:
+ - name: Install nginx package
+ ansible.builtin.apt:
+ cache_valid_time: 86400
+ name: nginx
+ state: present
+
+ - name: Remove the *-enabled and *-available directories
+ ansible.builtin.file:
+ path: '/etc/nginx/{{ item }}'
+ state: absent
+ loop:
+ - modules-available
+ - modules-enabled
+ - sites-available
+ - sites-enabled
+
+ - name: Set up the main nginx configuration file
+ ansible.builtin.copy:
+ src: 'nginx/{{ item }}'
+ dest: '/etc/nginx/{{ item }}'
+ mode: 'u=rw,go=r'
+ loop:
+ - nginx.conf
+ - ssl.conf
+ notify: Reload nginx
diff --git a/xmpp2/vars/secrets.example.yml b/xmpp2/vars/secrets.example.yml
new file mode 100644
index 0000000..6310a41
--- /dev/null
+++ b/xmpp2/vars/secrets.example.yml
@@ -0,0 +1,23 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+user_secrets:
+ password_hash: '' # Use `mkpasswd --method=sha-512` to generate.
+
+loglist_secrets:
+ db_password: ''
+ http_secret_key: ''
+
+ approval_email:
+ name: ''
+ password: ''
+ smtp_host: ''
+
+ basic_auth:
+ username: ''
+ password: ''
+
+ recaptcha:
+ private_key: ''
+ public_key: ''
diff --git a/xmpp2/vars/vars.example.yml b/xmpp2/vars/vars.example.yml
new file mode 100644
index 0000000..111a554
--- /dev/null
+++ b/xmpp2/vars/vars.example.yml
@@ -0,0 +1,7 @@
+# SPDX-FileCopyrightText: 2025 Friedrich von Never
+#
+# SPDX-License-Identifier: MIT
+
+user:
+ name: mario
+ ssh_public_key: 'ssh-ed25519 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXX/XXX username1@hostname'