diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..c01a677 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Nutomic @dessalines @codyro @ticoombs diff --git a/.woodpecker.yml b/.woodpecker.yml index 678e0fe..932aa4e 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -2,10 +2,16 @@ pipeline: prettier_markdown_check: image: tmknom/prettier commands: - - prettier -c "*.md" "*.yml" + - prettier -c "*.md" "*.yml" "examples/vars.yml" check_ansible_format: image: alpine:3 commands: - apk add ansible - ansible-playbook lemmy.yml --syntax-check + - ansible-playbook lemmy-almalinux.yml --syntax-check - ansible-playbook uninstall.yml --syntax-check + ansible_lint: + image: alpine:3 + commands: + - apk add ansible ansible-lint + - ansible-lint --warn-list experimental lemmy.yml lemmy-almalinux.yml uninstall.yml examples/vars.yml diff --git a/README.md b/README.md index fdcbafe..c23c3bb 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,38 @@ # Lemmy-Ansible -This provides an easy way to install [Lemmy](https://github.com/LemmyNet/lemmy) on any server. It automatically sets up an nginx server, letsencrypt certificates, and email. +This provides an easy way to install [Lemmy](https://github.com/LemmyNet/lemmy) on any server. It automatically sets up an nginx server, letsencrypt certificates, docker containers, pict-rs, and email smtp. ## Requirements To run this ansible playbook, you need to: -- Have a Debian-based server / VPS where lemmy will run. +- Have a Debian/AlmaLinux 9-based server / VPS where lemmy will run. +- Supported CPU architectures are x86-64 and ARM64. - Configure a DNS `A` Record to point at your server's IP address. - Make sure you can ssh to it, with a sudo user: `ssh @` -- Install [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) on your **local** machine (do not install it on your destination server). +- Install [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) (>= `2.11.0` on your **local** machine (do not install it on your destination server). + +### Supported Distribution Playbook Matrix + +These are the distributions we currently support. Anything not listed here is currently not supported. +If you wish to see another distribution on the list, please test on the latest commit in `main` and report your findings via an Issue. + +| Distribution | Version | Playbook | +| ------------ | --------- | --------------------- | +| Debian | 10 | `lemmy.yml` | +| Debian | 11 | `lemmy.yml` | +| Debian | 12 | `lemmy.yml` | +| Ubuntu | 22.04 LTS | `lemmy.yml` | +| RHEL | 9 | `lemmy-almalinux.yml` | ## Install -1. Clone this repo: +1. Clone this repo & checkout latest tag ``` git clone https://github.com/LemmyNet/lemmy-ansible.git cd lemmy-ansible + git checkout $(git describe --tags) ``` 2. Make a directory to hold your config: @@ -44,7 +59,15 @@ To run this ansible playbook, you need to: You can use [the PGTune tool](https://pgtune.leopard.in.ua) to tune your postgres to meet your server memory and CPU. -6. Run the playbook: +6. Copy the sample `vars.yml` file + + `cp examples/vars.yml inventory/host_vars//vars.yml` + + Edit the `inventory/host_vars//vars.yml` file to your liking. + +7. Run the playbook: + + _Note_: See the "Supported Distribution Playbook Matrix" section above if you should use `lemmy.yml` or not `ansible-playbook -i inventory/hosts lemmy.yml` @@ -66,9 +89,85 @@ To run this ansible playbook, you need to: ## Upgrading -- Run `git pull` -- Check out the [Lemmy Releases Changelog](https://github.com/LemmyNet/lemmy/blob/main/RELEASES.md) to see if there are any config changes with the releases since your last. -- Run `ansible-playbook -i inventory/hosts lemmy.yml --become` +Since version `1.1.0` we no longer default to using `main` but use tags to make sure deployments are versioned. +With every new release all migration steps shall be written below so make sure you check out the [Lemmy Releases Changelog](https://github.com/LemmyNet/lemmy/blob/main/RELEASES.md) to see if there are any config changes with the releases since your last read. + +### Upgrading to 1.3.0 (Lemmy 0.19.0 & pictrs-0.4.7) + +This is a major change and has required reading! tl;dr + +- Lemmy has been upgraded to 0.19.0 +- pict-rs has been upgraded to 0.4.7 + - pict-rs has not been integrated with postgres yet +- "Optional Modules" are now available to be added to your lemmy install as provided by the community. + - The first being pictrs-safety + +#### Steps + +- Prepare to have downtime as the database needs to perform migrations! +- Run `git pull && git checkout 1.3.0` +- Run your regular deployment. Example: `ansible-playbook -i inventory/hosts lemmy.yml --become` +- Lemmy will now be down! In testing this takes from 20 to 60 minutes. + - If you are bored you can ssh into your server, and check the logs on postgres for updates + - `docker compose logs -f postgres` while ssh'd and in your Lemmy directory + +#### Update your pict-rs sled-database (Optional) + +If you are happy for pict-rs to be down _for a while_ go straight to our `1.3.1` git tag which updates pictrs to 0.5.0. Otherwise keep reading. +Starting with 0.5.0 your database will automatically upgrade to the latest version, which will cause downtime for your users. +As such there is an intermediary step where you can upgrade your database in the background to prepare for 0.5 (Reference documentation)[https://git.asonix.dog/asonix/pict-rs/releases#user-content-upgrade-preparation-endpoint]. This ensure no-one is caught out by unforseen downtime of multiple services. + +Once you have deployed lemmy-ansible `1.3.0` tag, please continue (if you want): + +- Take note of what your pict-rs API Key is under `vars.yml` +- Take note of what your docker network name is. (It's normally the domain without any extra characters) + - You should be able to find it via: `docker network ls | grep _default` if in doubt. +- Run the following command replacing `api-key` with the pict-rs api key, & `youdomain` with the network name. +- `docker run --network yourdomain_default --rm curlimages/curl:8.5.0 --silent -XPOST -H'X-Api-Token: api-key' 'http://pictrs:8080/internal/prepare_upgrade'` +- This will start the background process updating your database from 0.4 to 0.5 compatible. + +This is only Optional, and takes a shorter amount of time than the Lemmy database upgrade, but on huge installations it may take a lot longer. + +#### Optional Module(s) + +Our first optional module is [pictrs-safety](https://github.com/db0/pictrs-safety). See the repo linked for more information, especially for integration with pictrs (which is what it is for) Thanks to @db0 for their contribution. +See the `pictrs_safety_env_vars` under `examples/vars.yml` for relevant options (and the two password variables) +To enable this module to be used you must ADD `pictrs_safety: true` to your `vars.yml`. + +### Upgrading to 1.2.1 (Lemmy 0.18.5) + +This is a minor change which fixes the issue with the Postgres container not using the `customPostgres.conf` file. + +#### Steps + +- Please regenerate your `customPostgres.conf` from `examples/customPostgres.conf` +- **OR** +- Add the following block to your current customPostgres file. + +``` +# Listen beyond localhost +listen_addresses = '*' +``` + +### Upgrading to 1.2.0 (Lemmy 0.18.5) + +Major changes: + +- All variables are not under a singular file so you will not need to modify anything: `inventory/host_vars/{{ domain }}/vars.yml` +- `--become` is now optional instead of forced on + +#### Steps + +- Run `git pull && git checkout 1.2.0` +- When upgrading from older versions of these playbooks, you will need to do the following: + - Rename `inventory/host_vars/{{ domain }}/passwords/postgres` file to `inventory/host_vars/{{ domain }}/passwords/postgres.psk` + - Copy the `examples/vars.yml` file to `inventory/host_vars/{{ domain }}/vars.yml` + - Edit your variables as desired +- Run your regular deployment. Example: `ansible-playbook -i inventory/hosts lemmy.yml --become` + +### Upgrading to 1.1.0 (Lemmy 0.18.3) + +- No major changes should be required ## Migrating your existing install to use this deploy diff --git a/VERSION b/VERSION index 267d7e0..41915c7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.18.3 +0.19.1 diff --git a/ansible.cfg b/ansible.cfg index 08550db..87bdc5d 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -4,6 +4,3 @@ inventory = inventory [ssh_connection] pipelining = True - -[privilege_escalation] -become = True diff --git a/examples/customPostgresql.conf b/examples/customPostgresql.conf index 49428e4..66cbd87 100644 --- a/examples/customPostgresql.conf +++ b/examples/customPostgresql.conf @@ -24,7 +24,9 @@ max_parallel_workers = 4 max_parallel_maintenance_workers = 2 # Other custom params -temp_file_size=1GB synchronous_commit=off # This one shouldn't be on regularly, because DB migrations often take a long time # statement_timeout = 10000 + +# Listen beyond localhost +listen_addresses = '*' diff --git a/examples/hosts b/examples/hosts index 2b75109..49fd86c 100644 --- a/examples/hosts +++ b/examples/hosts @@ -1,6 +1,7 @@ [lemmy] # to get started, copy this file to `inventory` and adjust the values below. # - `myuser@example.com`: replace with the destination you use to connect to your server via ssh +# - `ansible_user=root`: replace `root` with your the username you use to connect to your ssh server # - `domain=example.com`: replace `example.com` with your lemmy domain # - `letsencrypt_contact_email=your@email.com` replace `your@email.com` with your email address, # to get notifications if your ssl cert expires @@ -8,7 +9,8 @@ # if you are upgrading from a previous version, set this to `/lemmy` # - `lemmy_version`: The back end version. # - `lemmy_ui_version`: overrides the front end version. -myuser@example.com domain=example.com letsencrypt_contact_email=your@email.com lemmy_base_dir=/srv/lemmy +# - `pictrs_safety`: If true, a docker container for pictrs-safety will be deployed and pict-rs will be configured to validate images through it. You will also need to set up a fedi-safety worker to validate the images. +example.com ansible_user=root domain=example.com letsencrypt_contact_email=your@email.com lemmy_base_dir=/srv/lemmy pictrs_safety=false [all:vars] ansible_connection=ssh diff --git a/examples/vars.yml b/examples/vars.yml new file mode 100644 index 0000000..6dfdd3c --- /dev/null +++ b/examples/vars.yml @@ -0,0 +1,51 @@ +postgres_password: "{{ lookup('password', 'inventory/host_vars/{{ domain }}/passwords/postgres.psk chars=ascii_letters,digits') }}" # noqa yaml[line-length]:w + +# Next two only relevant if pictrs_safety == True +pictrs_safety_worker_auth: "{{ lookup('password', 'inventory/host_vars/{{ domain }}/passwords/pictrs_safety_worker_auth.psk chars=ascii_letters,digits length=15') }}" # noqa yaml[line-length] +pictrs_safety_secret: "{{ lookup('password', 'inventory/host_vars/{{ domain }}/passwords/pictrs_safety_secret.psk chars=ascii_letters,digits length=80') }}" # noqa yaml[line-length] + +# You can set any pict-rs environmental variables here. They will populate the templates/docker-compose.yml file. +# https://git.asonix.dog/asonix/pict-rs +pictrs_env_vars: + - PICTRS__SERVER__API_KEY: "{{ postgres_password }}" + - PICTRS__MEDIA__VIDEO_CODEC: vp9 + - PICTRS__MEDIA__GIF__MAX_WIDTH: 256 + - PICTRS__MEDIA__GIF__MAX_HEIGHT: 256 + - PICTRS__MEDIA__GIF__MAX_AREA: 65536 + - PICTRS__MEDIA__GIF__MAX_FRAME_COUNT: 400 + - PICTRS_OPENTELEMETRY_URL: http://otel:4137 + - RUST_LOG: debug + - RUST_BACKTRACE: full +# - PICTRS__STORE__TYPE: object_storage +# - PICTRS__STORE__ENDPOINT: '' +# - PICTRS__STORE__BUCKET_NAME: '' +# - PICTRS__STORE__REGION: '' +# - PICTRS__STORE__USE_PATH_STYLE: false +# - PICTRS__STORE__ACCESS_KEY: '' +# - PICTRS__STORE__SECRET_KEY: '' + +postgres_env_vars: + - POSTGRES_USER: lemmy + - POSTGRES_PASSWORD: "{{ postgres_password }}" + - POSTGRES_DB: lemmy + +lemmy_env_vars: + - RUST_LOG: warn + - MAX_DB_CONNECTIONS=20 + +lemmyui_env_vars: + - LEMMY_UI_LEMMY_INTERNAL_HOST: lemmy:8536 + - LEMMY_UI_LEMMY_EXTERNAL_HOST: "{{ domain }}" + - LEMMY_UI_HTTPS: true + +postfix_env_vars: + - POSTFIX_myhostname: "{{ domain }}" + +pictrs_safety_env_vars: + # Use this in your fedi-safety to allow your worker to authenticate to pictrs-safety + - FEDIVERSE_SAFETY_WORKER_AUTH: "{{ pictrs_safety_worker_auth }}" + - FEDIVERSE_SAFETY_IMGDIR: "/tmp/images" + - USE_SQLITE: 1 + - secret_key: "{{ pictrs_safety_secret }}" + - SCAN_BYPASS_THRESHOLD: 10 + - MISSING_WORKER_THRESHOLD: 5 diff --git a/files/proxy_params b/files/proxy_params new file mode 100644 index 0000000..11c0f2c --- /dev/null +++ b/files/proxy_params @@ -0,0 +1,4 @@ +proxy_set_header Host $http_host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $scheme; \ No newline at end of file diff --git a/lemmy-almalinux.yml b/lemmy-almalinux.yml new file mode 100644 index 0000000..3cfb8a8 --- /dev/null +++ b/lemmy-almalinux.yml @@ -0,0 +1,296 @@ +--- +- name: Install Lemmy + hosts: all + gather_facts: true + vars_files: + - "inventory/host_vars/{{ domain }}/vars.yml" + pre_tasks: + - name: Assert that Ansible version is >= 2.11.0 + delegate_to: localhost + ansible.builtin.assert: + that: + - "ansible_version.full is version('2.11.0', '>=')" + fail_msg: "This playbook requires Ansible 2.11.0 or higher" + become: false + + # This is not needed for this playbook as it predates its existence + # But we're keeping it for funsies :) + - name: Check lemmy_base_dir + ansible.builtin.fail: + msg: "`lemmy_base_dir` is unset. if you are upgrading from an older version, add `lemmy_base_dir=/lemmy` to your inventory file." + when: lemmy_base_dir is not defined + + - name: Check for legacy passwords/postgres file + delegate_to: localhost + ansible.builtin.stat: + path: "inventory/host_vars/{{ domain }}/passwords/postgres" + register: postgres_password_file + become: false + + - name: Legacy use of passwords/postgres file + delegate_to: localhost + ansible.builtin.fail: + msg: >- + In current versions of the Lemmy Ansible playbooks, the passwords/postgres file must be renamed to passwords/postgres.psk. + See https://github.com/LemmyNet/lemmy-ansible#upgrading + when: postgres_password_file.stat.exists + become: false + + - name: Check for vars.yml file + delegate_to: localhost + ansible.builtin.stat: + path: "inventory/host_vars/{{ domain }}/vars.yml" + register: vars_file + become: false + + - name: Missing vars.yml file + delegate_to: localhost + ansible.builtin.fail: + msg: >- + Missing vars.yml file, please refer to the installations instructions. See https://github.com/LemmyNet/lemmy-ansible#install + and https://github.com/LemmyNet/lemmy-ansible#upgrading + when: not vars_file.stat.exists + become: false + handlers: + - name: Reload nginx + ansible.builtin.systemd: + name: nginx + state: reloaded + + - name: Reload firewalld + ansible.builtin.systemd: + name: firewalld + state: reloaded + vars: + lemmy_port: "{{ 32767 | random(start=1024) }}" + tasks: + - name: Ensure target system is >= EL9 + ansible.builtin.assert: + that: + - ansible_distribution in ['AlmaLinux', 'CentOS', 'RedHat', 'Rocky'] + - ansible_distribution_major_version | int >= 9 + fail_msg: "This playbook requires Enterprise Linux 9 or greater on the target server" + tags: + - always + + - name: Enable CRB repository + ansible.builtin.yum_repository: + name: almalinux-crb + description: AlmaLinux $releasever - CRB + mirrorlist: https://mirrors.almalinux.org/mirrorlist/$releasever/crb + gpgcheck: true + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 + enabled: true + tags: + - dependencies + + - name: Install epel-release + ansible.builtin.dnf: + state: present + name: epel-release + tags: + - dependencies + + - name: Install dependencies + ansible.builtin.dnf: + state: present + name: + - certbot + - curl + - nginx + - podman + - podman-compose + - podman-docker + - python3-certbot-nginx + - python3-docker + - python3-pip + - python3-podman + - python3-virtualenv + - python3-setuptools + tags: + - dependencies + + - name: Gather service facts + ansible.builtin.service_facts: + tags: + - firewalld + + - name: Allow http/httpd traffic to public zone in firewalld + ansible.posix.firewalld: + service: "{{ item }}" + state: enabled + zone: public + permanent: true + immediate: true + loop: + - http + - https + when: "'firewalld.service' in ansible_facts.services and ansible_facts.services['firewalld.service'].state == 'running'" + tags: + - firewalld + + # TODO: certbot logic needs to be re-worked + - name: Request initial letsencrypt certificate + ansible.builtin.command: certbot certonly --nginx --agree-tos --cert-name '{{ domain }}' -d '{{ domain }}' -m '{{ letsencrypt_contact_email }}' + args: + creates: "/etc/letsencrypt/live/{{ domain }}/privkey.pem" + tags: + - certbot + - certbot_initial + - ssl + + - name: Create lemmy folder + ansible.builtin.file: + path: "{{ item.path }}" + owner: "{{ item.owner }}" + state: directory + mode: "0755" + loop: + - path: "{{ lemmy_base_dir }}/{{ domain }}/" + owner: "root" + - path: "{{ lemmy_base_dir }}/{{ domain }}/volumes/" + owner: "root" + - path: "{{ lemmy_base_dir }}/{{ domain }}/volumes/pictrs/" + owner: "991" # Matches docker-compose UID in docker-compose.yml + + - name: Set lemmy_port fact + ansible.builtin.set_fact: + lemmy_port: "{{ 32767 | random(start=1024) }}" + tags: + - always + + - name: Distribute docker/podman templates + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + loop: + - src: "templates/docker-compose.yml" + dest: "{{ lemmy_base_dir }}/{{ domain }}/docker-compose.yml" + mode: "0600" + - src: "templates/nginx_internal.conf" + dest: "{{ lemmy_base_dir }}/{{ domain }}/nginx_internal.conf" + mode: "0644" + vars: + lemmy_docker_image: "docker.io/dessalines/lemmy:{{ lemmy_version | default(lookup('file', 'VERSION')) }}" + lemmy_docker_ui_image: "docker.io/dessalines/lemmy-ui:{{ lemmy_ui_version | default(lemmy_version | default(lookup('file', 'VERSION'))) }}" + tags: + - docker + - podman + + # TODO: Move to templates/, keeping consistent with upstream currently + # to ensure documentation is accurate + - name: Add the config.hjson + ansible.builtin.template: + # src: "templates/{{ domain }}/config.hjson" + src: "inventory/host_vars/{{ domain }}/config.hjson" + dest: "{{ lemmy_base_dir }}/{{ domain }}/lemmy.hjson" + mode: "0600" + owner: "1000" # Match UID in container + group: "1000" # Match GID in container + tags: + - configs + + # TODO: Move to files/, keeping consistent with upstream currently + # to ensure documentation is accurate + - name: Add the customPostgresql.conf + ansible.builtin.template: + # src: "files/{{ domain }}/customPostgresql.conf" + src: "inventory/host_vars/{{ domain }}/customPostgresql.conf" + dest: "{{ lemmy_base_dir }}/{{ domain }}/customPostgresql.conf" + mode: "0644" + owner: root + group: root + tags: + - configs + - postgresql + + - name: Distribute nginx proxy_params configuration + ansible.builtin.copy: + src: files/proxy_params + dest: "{{ lemmy_base_dir }}/{{ domain }}/proxy_params" + owner: root + group: root + mode: "0644" + tags: + - nginx + + - name: Distribute nginx site templates + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + loop: + - src: "templates/nginx.conf" + dest: "/etc/nginx/conf.d/{{ domain }}.conf" + mode: "0644" + notify: Reload nginx + tags: + - nginx + + # TODO: Check if this is necessary with EL & podman + # - name: Copy docker config + # ansible.builtin.copy: + # src: "{{ ansible_playbook }}/files/docker-daemon.json" + # dest: /etc/docker/daemon.json + # mode: '0644' + + # TODO: podman-compose should wrap this safely + # TODO: This was an incorrect assumption, module uses docker python module, not cli + # - name: Run podman-compose + # docker_compose: + # project_src: "{{ lemmy_base_dir }}/{{ domain }}" + # state: present + # pull: yes + # remove_orphans: yes + # tags: + # - docker + # - docker_compose + # - podman + # - podman_compose + + - name: Start and enable podman service + ansible.builtin.systemd: + name: podman.service + state: started + enabled: true + tags: + - docker + - podman + + - name: Run podman-compose pull + ansible.builtin.command: podman-compose pull + args: + chdir: "{{ lemmy_base_dir }}/{{ domain }}" + changed_when: true + tags: + - docker + - podman + + - name: Run podman-compose up + ansible.builtin.command: podman-compose up -d + args: + chdir: "{{ lemmy_base_dir }}/{{ domain }}" + changed_when: true + tags: + - docker + - podman + + # This isn't using any jinja2 templating currently + - name: Distribute /etc/sysconfig/certbot + ansible.builtin.template: + src: "templates/sysconfig-certbot.j2" + dest: "/etc/sysconfig/certbot" + mode: "0644" + tags: + - certbot + - ssl + + - name: Enable certbot-renew.timer + ansible.builtin.systemd: + name: certbot-renew.timer + state: started + enabled: true + tags: + - certbot + - ssl diff --git a/lemmy.yml b/lemmy.yml index e8e0e3c..4ffc8ac 100644 --- a/lemmy.yml +++ b/lemmy.yml @@ -1,35 +1,92 @@ --- -- hosts: all +- name: Install Lemmy + hosts: all # Install python if required # https://www.josharcher.uk/code/ansible-python-connection-failure-ubuntu-server-1604/ - gather_facts: False + gather_facts: false + vars_files: + - "inventory/host_vars/{{ domain }}/vars.yml" pre_tasks: - - name: check lemmy_base_dir - fail: + - name: Assert that Ansible version is >= 2.11.0 + delegate_to: localhost + ansible.builtin.assert: + that: + - "ansible_version.full is version('2.11.0', '>=')" + fail_msg: "This playbook requires Ansible 2.11.0 or higher" + become: false + + - name: Check lemmy_base_dir + ansible.builtin.fail: msg: "`lemmy_base_dir` is unset. if you are upgrading from an older version, add `lemmy_base_dir=/lemmy` to your inventory file." when: lemmy_base_dir is not defined - - name: install python for Ansible + - name: Check for legacy passwords/postgres file + delegate_to: localhost + ansible.builtin.stat: + path: "inventory/host_vars/{{ domain }}/passwords/postgres" + register: postgres_password_file + become: false + + - name: Legacy use of passwords/postgres file + delegate_to: localhost + ansible.builtin.fail: + msg: >- + In current versions of the Lemmy Ansible playbooks, the passwords/postgres file must be renamed to passwords/postgres.psk. + See https://github.com/LemmyNet/lemmy-ansible#upgrading + when: postgres_password_file.stat.exists + become: false + + - name: Check for vars.yml file + delegate_to: localhost + ansible.builtin.stat: + path: "inventory/host_vars/{{ domain }}/vars.yml" + register: vars_file + become: false + + - name: Missing vars.yml file + delegate_to: localhost + ansible.builtin.fail: + msg: >- + Missing vars.yml file, please refer to the installations instructions. See https://github.com/LemmyNet/lemmy-ansible#install + and https://github.com/LemmyNet/lemmy-ansible#upgrading + when: not vars_file.stat.exists + become: false + + - name: Install python for Ansible # python2-minimal instead of python-minimal for ubuntu 20.04 and up - raw: test -e /usr/bin/python || (apt -y update && apt install -y python3-minimal python3-setuptools) + ansible.builtin.raw: test -e /usr/bin/python || test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal python3-setuptools) args: executable: /bin/bash register: output changed_when: output.stdout != '' - - setup: # gather facts - + - name: Gather facts + ansible.builtin.setup: + handlers: + - name: Reload nginx + ansible.builtin.systemd: + name: nginx + state: reloaded tasks: + - name: Check hostname resolution + ansible.builtin.ping: + + - name: Ensure target system is Debian or Ubuntu + ansible.builtin.assert: + that: + - ansible_distribution in ['Debian', 'Ubuntu'] + fail_msg: "This playbook requires Debian or Ubuntu on the target server" + - name: Install aptitude - apt: + ansible.builtin.apt: name: aptitude state: latest update_cache: true - - name: install dependencies - apt: - state: latest + - name: Install dependencies + ansible.builtin.apt: + state: present update_cache: true pkg: - "nginx" @@ -44,129 +101,153 @@ - "virtualenv" - "python3-setuptools" - - name: Configure Docker apt repo before Jammy + - name: Configure Docker apt repo for Ubuntu < 22.04 when: ansible_distribution == 'Ubuntu' and ansible_distribution_version < '22.04' block: - name: Add Docker GPG apt Key - apt_key: + ansible.builtin.apt_key: url: https://download.docker.com/linux/ubuntu/gpg state: present - name: Add Docker Repository - apt_repository: + ansible.builtin.apt_repository: repo: deb https://download.docker.com/linux/ubuntu focal stable state: present - - name: Configure Docker apt repo on Jammy++ - when: ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '22.04' + - name: Get architecture using dpkg + when: (ansible_distribution == 'Debian') or + (ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '22.04') + ansible.builtin.command: dpkg --print-architecture + register: dpkg_output + changed_when: false + + # based on https://docs.docker.com/engine/install/debian/ + # and https://docs.docker.com/engine/install/ubuntu/ + # note that Debian and Ubuntu use the same key + - name: Configure Docker apt repo for Debian or Ubuntu >= 22.04 + when: (ansible_distribution == 'Debian') or + (ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '22.04') block: - name: Download Docker GPG Key - get_url: - url: https://download.docker.com/linux/ubuntu/gpg - dest: /etc/apt/keyrings/docker.asc + ansible.builtin.get_url: + url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg + dest: /etc/apt/trusted.gpg.d/docker.asc checksum: sha256:1500c1f56fa9e26b9b8f42452a553675796ade0807cdce11975eb98170b3a570 - - name: Add Docker to apt - apt_repository: - repo: "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" + mode: "0644" + - name: Add Docker apt repo + ansible.builtin.apt_repository: + repo: >- + deb [arch={{ dpkg_output.stdout }} signed-by=/etc/apt/trusted.gpg.d/docker.asc] + https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable state: present - - name: Update apt and install docker-ce - apt: - name: docker-ce - state: latest - update_cache: true - - - name: Install Docker Module and docker-compose for Python - pip: + - name: Install docker-ce and docker-compose + ansible.builtin.apt: name: - - docker + - docker-ce - docker-compose - state: latest + state: present + update_cache: true - - name: copy docker config - copy: src='../files/docker-daemon.json' dest='/etc/docker/daemon.json' mode='0644' + - name: Copy docker config + ansible.builtin.copy: + src: files/docker-daemon.json + dest: /etc/docker/daemon.json + mode: "0644" - - name: request initial letsencrypt certificate - command: certbot certonly --nginx --agree-tos --cert-name '{{ domain }}' -d '{{ domain }}' -m '{{ letsencrypt_contact_email }}' + - name: Request initial letsencrypt certificate + ansible.builtin.command: certbot certonly --nginx --agree-tos --cert-name '{{ domain }}' -d '{{ domain }}' -m '{{ letsencrypt_contact_email }}' args: - creates: "/etc/letsencrypt/live/{{domain}}/privkey.pem" + creates: "/etc/letsencrypt/live/{{ domain }}/privkey.pem" - - name: create lemmy folder - file: - path: "{{item.path}}" - owner: "{{item.owner}}" + - name: Create lemmy folder + ansible.builtin.file: + path: "{{ item.path }}" + owner: "{{ item.owner }}" state: directory - with_items: - - path: "{{lemmy_base_dir}}/{{domain}}/" + mode: "0755" + loop: + - path: "{{ lemmy_base_dir }}/{{ domain }}/" owner: "root" - - path: "{{lemmy_base_dir}}/{{domain}}/volumes/" + - path: "{{ lemmy_base_dir }}/{{ domain }}/volumes/" owner: "root" - - path: "{{lemmy_base_dir}}/{{domain}}/volumes/pictrs/" + - path: "{{ lemmy_base_dir }}/{{ domain }}/volumes/pictrs/" owner: "991" - - block: - - set_fact: - lemmy_port: "{{ 32767 |random(start=1024) }}" + - name: Deploy configuration files + block: + - name: Generate random port for lemmy service + ansible.builtin.set_fact: + lemmy_port: "{{ 32767 | random(start=1024) }}" + + - name: Distribute nginx proxy_params configuration + ansible.builtin.copy: + src: files/proxy_params + dest: "{{ lemmy_base_dir }}/{{ domain }}/proxy_params" + owner: root + group: root + mode: "0644" + notify: Reload nginx - - name: add template files - template: - src: "{{item.src}}" - dest: "{{item.dest}}" - mode: "{{item.mode}}" - with_items: + - name: Add template files + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + loop: - src: "templates/docker-compose.yml" - dest: "{{lemmy_base_dir}}/{{domain}}/docker-compose.yml" + dest: "{{ lemmy_base_dir }}/{{ domain }}/docker-compose.yml" mode: "0600" - src: "templates/nginx_internal.conf" - dest: "{{lemmy_base_dir}}/{{domain}}/nginx_internal.conf" + dest: "{{ lemmy_base_dir }}/{{ domain }}/nginx_internal.conf" mode: "0644" - src: "templates/nginx.conf" - dest: "/etc/nginx/sites-available/{{domain}}.conf" + dest: "/etc/nginx/sites-available/{{ domain }}.conf" mode: "0644" + notify: Reload nginx vars: - lemmy_docker_image: "dessalines/lemmy:{{ lemmy_version | default( lookup('file', 'VERSION') )}}" - lemmy_docker_ui_image: "dessalines/lemmy-ui:{{ lemmy_ui_version | default(lemmy_version | default(lookup('file', 'VERSION')))}}" + lemmy_docker_image: "dessalines/lemmy:{{ lemmy_version | default(lookup('file', 'VERSION')) }}" + lemmy_docker_ui_image: "dessalines/lemmy-ui:{{ lemmy_ui_version | default(lemmy_version | default(lookup('file', 'VERSION'))) }}" - - block: - - name: gather stats on site enabled config - stat: - path: "/etc/nginx/sites-enabled/{{domain}}.conf" + - name: Set up nginx sites-enabled symlink + notify: Reload nginx + block: + - name: Gather stats on site enabled config + ansible.builtin.stat: + path: "/etc/nginx/sites-enabled/{{ domain }}.conf" register: reg_enabled - - name: remove if regular file (legacy) instead of symlink - file: - path: "/etc/nginx/sites-enabled/{{domain}}.conf" + - name: Remove if regular file (legacy) instead of symlink + ansible.builtin.file: + path: "/etc/nginx/sites-enabled/{{ domain }}.conf" state: absent when: reg_enabled.stat.exists and reg_enabled.stat.isreg - - name: enable nginx site - file: - src: "../sites-available/{{domain}}.conf" - dest: "/etc/nginx/sites-enabled/{{domain}}.conf" + - name: Enable nginx site + ansible.builtin.file: + src: "../sites-available/{{ domain }}.conf" + dest: "/etc/nginx/sites-enabled/{{ domain }}.conf" state: link - - name: add the config.hjson - template: - src: "inventory/host_vars/{{domain}}/config.hjson" - dest: "{{lemmy_base_dir}}/{{domain}}/lemmy.hjson" - mode: "0600" - owner: "1000" - group: "1000" - - - name: add the customPostgresql.conf - template: - src: "inventory/host_vars/{{domain}}/customPostgresql.conf" - dest: "{{lemmy_base_dir}}/{{domain}}/customPostgresql.conf" + - name: Add the config.hjson + ansible.builtin.template: + src: "inventory/host_vars/{{ domain }}/config.hjson" + dest: "{{ lemmy_base_dir }}/{{ domain }}/lemmy.hjson" mode: "0600" owner: "1000" group: "1000" - vars: - postgres_password: "{{ lookup('password', 'inventory/host_vars/{{domain}}/passwords/postgres chars=ascii_letters,digits') }}" + - name: Add the customPostgresql.conf + ansible.builtin.template: + src: "inventory/host_vars/{{ domain }}/customPostgresql.conf" + dest: "{{ lemmy_base_dir }}/{{ domain }}/customPostgresql.conf" + mode: "0644" + owner: root + group: root - - name: enable and start docker service - systemd: + - name: Enable and start docker service + ansible.builtin.systemd: name: docker - enabled: yes + enabled: true state: started # - name: Change the working directory to /opt @@ -176,18 +257,15 @@ # register: shell_output # - debug: var=shell_output - - name: start docker-compose - docker_compose: - project_src: "{{lemmy_base_dir}}/{{domain}}" + - name: Start docker-compose + community.docker.docker_compose: + project_src: "{{ lemmy_base_dir }}/{{ domain }}" state: present - pull: yes - remove_orphans: yes - - - name: reload nginx with new config - shell: nginx -s reload + pull: true + remove_orphans: true - - name: certbot renewal cronjob - cron: + - name: Certbot renewal cronjob + ansible.builtin.cron: special_time: daily name: certbot-renew-lemmy user: root diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..a0cd255 --- /dev/null +++ b/requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: ansible.posix diff --git a/templates/docker-compose.yml b/templates/docker-compose.yml index b546c97..361a617 100644 --- a/templates/docker-compose.yml +++ b/templates/docker-compose.yml @@ -8,7 +8,7 @@ x-logging: &default-logging services: proxy: - image: nginx:1-alpine + image: docker.io/library/nginx ports: # actual and only port facing any connection from outside # Note, change the left number if port 1236 is already in use on your system @@ -16,6 +16,7 @@ services: - "{{ lemmy_port }}:8536" volumes: - ./nginx_internal.conf:/etc/nginx/nginx.conf:ro,Z + - ./proxy_params:/etc/nginx/proxy_params:ro,Z restart: always logging: *default-logging depends_on: @@ -28,26 +29,29 @@ services: restart: always logging: *default-logging environment: - - RUST_LOG="warn" +{% if lemmy_env_vars is defined and lemmy_env_vars|length > 0 %} +{% for item in lemmy_env_vars %} +{% for key, value in item.items() %} + - {{ key }}={{ value }} +{% endfor %} +{% endfor %} +{% endif %} volumes: - ./lemmy.hjson:/config/config.hjson:Z depends_on: - postgres - pictrs - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8536"] - interval: 1m - timeout: 10s - retries: 3 - labels: - - "autoheal=true" lemmy-ui: image: {{ lemmy_docker_ui_image }} environment: - - LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536 - - LEMMY_UI_LEMMY_EXTERNAL_HOST={{ domain }} - - LEMMY_UI_HTTPS=true +{% if lemmyui_env_vars is defined and lemmyui_env_vars|length > 0 %} +{% for item in lemmyui_env_vars %} +{% for key, value in item.items() %} + - {{ key }}={{ value }} +{% endfor %} +{% endfor %} +{% endif %} volumes: - ./volumes/lemmy-ui/extra_themes:/app/extra_themes depends_on: @@ -56,21 +60,22 @@ services: logging: *default-logging pictrs: - image: asonix/pictrs:0.4.0 + image: docker.io/asonix/pictrs:0.4.7 # this needs to match the pictrs url in lemmy.hjson hostname: pictrs # we can set options to pictrs like this, here we set max. image size and forced format for conversion # entrypoint: /sbin/tini -- /usr/local/bin/pict-rs -p /mnt -m 4 --image-format webp environment: - - PICTRS_OPENTELEMETRY_URL=http://otel:4137 - - PICTRS__API_KEY={{ postgres_password }} - - RUST_LOG=debug - - RUST_BACKTRACE=full - - PICTRS__MEDIA__VIDEO_CODEC=vp9 - - PICTRS__MEDIA__GIF__MAX_WIDTH=256 - - PICTRS__MEDIA__GIF__MAX_HEIGHT=256 - - PICTRS__MEDIA__GIF__MAX_AREA=65536 - - PICTRS__MEDIA__GIF__MAX_FRAME_COUNT=400 +{% if pictrs_env_vars is defined and pictrs_env_vars|length > 0 %} +{% for item in pictrs_env_vars %} +{% for key, value in item.items() %} + - {{ key }}={{ value }} +{% endfor %} +{% endfor %} +{% endif %} +{% if pictrs_safety is defined and pictrs_safety|bool == true %} + - PICTRS__MEDIA__EXTERNAL_VALIDATION=http://{{ domain }}:14051/api/v1/scan/IPADDR +{% endif %} user: 991:991 volumes: - ./volumes/pictrs:/mnt:Z @@ -82,30 +87,56 @@ services: memory: 690m postgres: - image: postgres:15-alpine + image: docker.io/postgres:15-alpine hostname: postgres environment: - - POSTGRES_USER=lemmy - - POSTGRES_PASSWORD={{ postgres_password }} - - POSTGRES_DB=lemmy +{% if postgres_env_vars is defined and postgres_env_vars|length > 0 %} +{% for item in postgres_env_vars %} +{% for key, value in item.items() %} + - {{ key }}={{ value }} +{% endfor %} +{% endfor %} +{% endif %} + ports: + - 5432:5432 volumes: - ./volumes/postgres:/var/lib/postgresql/data:Z - ./customPostgresql.conf:/etc/postgresql.conf restart: always + command: postgres -c config_file=/etc/postgresql.conf + shm_size: 1g logging: *default-logging postfix: - image: mwader/postfix-relay + image: docker.io/mwader/postfix-relay environment: - - POSTFIX_myhostname={{ domain }} +{% if postfix_env_vars is defined and postfix_env_vars|length > 0 %} +{% for item in postfix_env_vars %} +{% for key, value in item.items() %} + - {{ key }}={{ value }} +{% endfor %} +{% endfor %} +{% endif %} restart: "always" logging: *default-logging - autoheal: - restart: always - image: willfarrell/autoheal +{% if pictrs_safety is defined and pictrs_safety|bool == true %} + pictrs-safety: + image: ghcr.io/db0/pictrs-safety:v1.2.2 + hostname: pictrs-safety environment: - - AUTOHEAL_CONTAINER_LABEL=autoheal - - volumes: - - /var/run/docker.sock:/var/run/docker.sock \ No newline at end of file +{% if pictrs_safety_env_vars is defined and pictrs_safety_env_vars|length > 0 %} +{% for item in pictrs_safety_env_vars %} +{% for key, value in item.items() %} + - {{ key }}={{ value }} +{% endfor %} +{% endfor %} +{% endif %} + ports: + - "14051:14051" + user: 991:991 + restart: always + logging: *default-logging + depends_on: + - pictrs +{% endif %} diff --git a/templates/nginx.conf b/templates/nginx.conf index 7ab078b..5e2bc59 100644 --- a/templates/nginx.conf +++ b/templates/nginx.conf @@ -1,9 +1,9 @@ -limit_req_zone $binary_remote_addr zone={{domain}}_ratelimit:10m rate=1r/s; +limit_req_zone $binary_remote_addr zone={{ domain }}_ratelimit:10m rate=1r/s; server { listen 80; listen [::]:80; - server_name {{domain}}; + server_name {{ domain }}; # Hide nginx version server_tokens off; location /.well-known/acme-challenge/ { @@ -17,10 +17,10 @@ server { server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name {{domain}}; + server_name {{ domain }}; - ssl_certificate /etc/letsencrypt/live/{{domain}}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/{{domain}}/privkey.pem; + ssl_certificate /etc/letsencrypt/live/{{ domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ domain }}/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; @@ -63,4 +63,5 @@ server { } } + access_log /var/log/nginx/access.log combined; diff --git a/templates/nginx_internal.conf b/templates/nginx_internal.conf index 34c1427..765ff1a 100644 --- a/templates/nginx_internal.conf +++ b/templates/nginx_internal.conf @@ -5,6 +5,12 @@ events { } http { + # Docker internal DNS IP so we always get the newer containers without having to + # restart/reload the docker container / nginx configuration + resolver 127.0.0.11 valid=5s; + # set the real_ip when from docker internal ranges. Ensuring our internal nginx + # container can always see the correct ips in the logs + set_real_ip_from 172.0.0.0/8; # We construct a string consistent of the "request method" and "http accept header" # and then apply soem ~simply regexp matches to that combination to decide on the # HTTP upstream we should proxy the request to. @@ -21,32 +27,24 @@ http { # Learn more about nginx maps here http://nginx.org/en/docs/http/ngx_http_map_module.html map "$request_method:$http_accept" $proxpass { # If no explicit matches exists below, send traffic to lemmy-ui - default "http://lemmy-ui"; + default "http://lemmy-ui:1234"; # GET/HEAD requests that accepts ActivityPub or Linked Data JSON should go to lemmy. # # These requests are used by Mastodon and other fediverse instances to look up profile information, # discover site information and so on. - "~^(?:GET|HEAD):.*?application\/(?:activity|ld)\+json" "http://lemmy"; + "~^(?:GET|HEAD):.*?application\/(?:activity|ld)\+json" "http://lemmy:8536"; # All non-GET/HEAD requests should go to lemmy # # Rather than calling out POST, PUT, DELETE, PATCH, CONNECT and all the verbs manually # we simply negate the GET|HEAD pattern from above and accept all possibly $http_accept values - "~^(?!(GET|HEAD)).*:" "http://lemmy"; - } - - upstream lemmy { - # this needs to map to the lemmy (server) docker service hostname - server "lemmy:8536"; - } - - upstream lemmy-ui { - # this needs to map to the lemmy-ui docker service hostname - server "lemmy-ui:1234"; + "~^(?!(GET|HEAD)).*:" "http://lemmy:8536"; } server { + set $lemmy_ui "lemmy-ui:1234"; + set $lemmy "lemmy:8536"; # this is the port inside docker, not the public one yet listen 1236; listen 8536; @@ -55,21 +53,11 @@ http { server_name localhost; server_tokens off; - gzip on; - gzip_types text/css application/javascript image/svg+xml; - gzip_vary on; - # Upload limit, relevant for pictrs client_max_body_size 20M; - add_header X-Frame-Options SAMEORIGIN; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - # Send actual client IP upstream - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + include proxy_params; # frontend general requests location / { @@ -79,17 +67,15 @@ http { # security.txt location = /.well-known/security.txt { - proxy_pass "http://lemmy-ui"; + proxy_pass "http://$lemmy_ui"; } # backend - location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) { - proxy_pass "http://lemmy"; + location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known|version|sitemap.xml) { + proxy_pass "http://$lemmy"; - # proxy common stuff - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; + # Send actual client IP upstream + include proxy_params; } } } diff --git a/templates/sysconfig-certbot.j2 b/templates/sysconfig-certbot.j2 new file mode 100644 index 0000000..c2865e0 --- /dev/null +++ b/templates/sysconfig-certbot.j2 @@ -0,0 +1,47 @@ +## NOTE ## +# If a hook is set here then it will be used for all +# certificates and will override any per certificate +# hook configuration in place. + +# Command to be run in a shell before obtaining any +# certificates. Intended primarily for renewal, where it +# can be used to temporarily shut down a webserver that +# might conflict with the standalone plugin. This will +# only be called if a certificate is actually to be +# obtained/renewed. When renewing several certificates +# that have identical pre-hooks, only the first will be +# executed. +# +# An example to stop the MTA before updating certs would be +# PRE_HOOK="--pre-hook 'systemctl stop postfix'" +PRE_HOOK="" + +# Command to be run in a shell after attempting to +# obtain/renew certificates. Can be used to deploy +# renewed certificates, or to restart any servers that +# were stopped by --pre-hook. This is only run if an +# attempt was made to obtain/renew a certificate. If +# multiple renewed certificates have identical post- +# hooks, only one will be run. +# +# An example to restart httpd would be: +# POST_HOOK="--post-hook 'systemctl restart httpd'" +POST_HOOK="'nginx -s reload'" + +# Command to be run in a shell once for each +# successfully renewed certificate. For this command, +# the shell variable $RENEWED_LINEAGE will point to the +# config live subdirectory containing the new certs and +# keys; the shell variable $RENEWED_DOMAINS will contain +# a space-delimited list of renewed cert domains +# +# An example to run a script to alert each cert would be: +# DEPLOY_HOOK="--deploy-hook /usr/local/bin/cert-notifier.sh" +DEPLOY_HOOK="" + +# Any other misc arguments for the renewal +# See certbot -h renew for full list +# +# An example to force renewal for certificates not due yet +# CERTBOT_ARGS="--force-renewal" +CERTBOT_ARGS="" diff --git a/uninstall.yml b/uninstall.yml index 1779c0c..d19f71f 100644 --- a/uninstall.yml +++ b/uninstall.yml @@ -1,38 +1,97 @@ --- -- hosts: all +- name: Uninstall Lemmy + hosts: all vars_prompt: - name: confirm_uninstall prompt: "Do you really want to uninstall Lemmy? This will delete all data and can not be reverted [yes/no]" - private: no + private: false - name: delete_certs prompt: "Delete certificates? Select 'no' if you want to reinstall Lemmy [yes/no]" - private: no + private: false + + - name: stop_disable_nginx + prompt: "Do you want to stop/disable nginx? [yes/no]" + private: false + + - name: stop_disable_docker_podman + prompt: "Do you want to stop/disable Docker/podman? [yes/no]" + private: false tasks: - - name: end play if no confirmation was given - debug: + - name: Inform about cancellation if no confirmation was given + ansible.builtin.debug: msg: "Uninstall cancelled, doing nothing" - when: not confirm_uninstall|bool - - - meta: end_play - when: not confirm_uninstall|bool - - - name: stop docker-compose - docker_compose: - project_src: "{{lemmy_base_dir}}/{{domain}}" - state: absent - - - name: delete data - file: - path: "{{item.path}}" - state: absent - with_items: - - path: "{{lemmy_base_dir}}/{{domain}}" - - path: "/etc/nginx/sites-enabled/{{domain}}.conf" - - - name: remove certbot cronjob - cron: - name: certbot-renew-lemmy - state: absent + when: not confirm_uninstall | bool + + - name: End play if no confirmation was given + ansible.builtin.meta: end_play + when: not confirm_uninstall | bool + + - name: Run Ubuntu specific uninstallation steps + when: ansible_distribution == "Ubuntu" + block: + - name: Stop docker-compose + community.docker.docker_compose: + project_src: "{{ lemmy_base_dir }}/{{ domain }}" + state: absent + + - name: Delete data + ansible.builtin.file: + path: "{{ item.path }}" + state: absent + with_items: + - path: "{{ lemmy_base_dir }}/{{ domain }}" + - path: "/etc/nginx/sites-enabled/{{ domain }}.conf" + + - name: Remove certbot cronjob + ansible.builtin.cron: + name: certbot-renew-lemmy + state: absent + + - name: Stop and disable Docker + ansible.builtin.systemd: + name: docker.service + state: stopped + enabled: false + when: stop_disable_docker_podman | bool + + - name: Run EL specific uninstallation steps + when: + - ansible_distribution in ['AlmaLinux', 'CentOS', 'RedHat', 'Rocky'] + - ansible_distribution_major_version | int >= 9 + block: + - name: Stop and remove containers + ansible.builtin.command: podman-compose down + args: + chdir: "{{ lemmy_base_dir }}/{{ domain }}" + changed_when: true + + - name: Delete Lemmy data + ansible.builtin.file: + path: "{{ item.path }}" + state: absent + loop: + - path: "{{ lemmy_base_dir }}/{{ domain }}" + - path: "/etc/nginx/conf.d/{{ domain }}.conf" + + - name: Stop and disable certbot-renew.timer + ansible.builtin.systemd: + name: certbot-renew.timer + state: stopped + enabled: false + + - name: Stop and disable podman + ansible.builtin.systemd: + name: podman.service + state: stopped + enabled: false + when: stop_disable_docker_podman | bool + + - name: Stop and disable nginx + ansible.builtin.systemd: + name: nginx.service + state: stopped + enabled: false + when: stop_disable_nginx | bool