diff --git a/README.md b/README.md index 05a8542..1edb00b 100755 --- a/README.md +++ b/README.md @@ -1,21 +1,39 @@ +# Ansible scripte + +## Setup + +```bash +# Ensure `ansible-core` is installed using pipx +sudo apt remove ansible-core +# Install pipx and ansible-core +sudo apt-get install pipx +pipx install ansible-core +# Ensure your path is correct for pipx apps +pipx ensurepath +# Ensure any shell caching of paths is reset +hash -r +``` + +## Scripts + ```bash # install roles and collections ansible-galaxy install -r requirements.yml # Install the frontend -ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass frontend.yaml +ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass frontend.yaml -K # Github runner -ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass github-runner.yaml +ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass github-runner.yaml -K # gitea server -ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass gitea.yaml +ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass gitea.yaml -K # graphana + prometheus -ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass monitor.yaml +ansible-playbook -i inventory.yaml -e @secrets.enc --ask-vault-pass monitor.yaml -K # apt-cacheer-ng -ansible-playbook -i inventory.yaml --ask-become-pass apt-cacher-ng.yaml +ansible-playbook -i inventory.yaml --ask-become-pass apt-cacher-ng.yaml -K ``` To make use of the apt cache, ensure you have a file like this with CACHE_HOST changes to your actual host diff --git a/apptabulous/reverseproxy/conf.d/reverse_proxy.conf b/apptabulous/reverseproxy/conf.d/reverse_proxy.conf index b3960d1..70652e1 100755 --- a/apptabulous/reverseproxy/conf.d/reverse_proxy.conf +++ b/apptabulous/reverseproxy/conf.d/reverse_proxy.conf @@ -22,7 +22,7 @@ server { } location / { - proxy_pass http://rpi4-2:3000; + proxy_pass http://website:3000; } } @@ -42,7 +42,7 @@ server { # } location / { - proxy_pass http://rpi5-2:3000; + proxy_pass http://gitea:3000; } } @@ -62,44 +62,44 @@ server { } location / { - proxy_pass http://rpi4-2:3001; + proxy_pass http://apptabulous_website:3000; } } # Container registry -server { - listen 80; - listen [::]:80; - listen 443 ssl; - listen [::]:443 ssl; - server_name hub.apptabulous.co.uk; +# server { +# listen 80; +# listen [::]:80; +# listen 443 ssl; +# listen [::]:443 ssl; +# server_name hub.apptabulous.co.uk; - ssl_certificate /etc/letsencrypt/live/apptabulous.co.uk/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/apptabulous.co.uk/privkey.pem; +# ssl_certificate /etc/letsencrypt/live/apptabulous.co.uk/fullchain.pem; +# ssl_certificate_key /etc/letsencrypt/live/apptabulous.co.uk/privkey.pem; - # disable any limits to avoid HTTP 413 for large image uploads - client_max_body_size 0; +# # disable any limits to avoid HTTP 413 for large image uploads +# client_max_body_size 0; - # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) - chunked_transfer_encoding on; +# # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) +# chunked_transfer_encoding on; - location / { - proxy_pass http://rpi4-2:5000; - } -} +# location / { +# proxy_pass http://rpi4-2:5000; +# } +# } -# Watchtower -server { - listen 80; - listen [::]:80; - listen 443 ssl; - listen [::]:443 ssl; - server_name watchtower.apptabulous.co.uk; +# # Watchtower +# server { +# listen 80; +# listen [::]:80; +# listen 443 ssl; +# listen [::]:443 ssl; +# server_name watchtower.apptabulous.co.uk; - ssl_certificate /etc/letsencrypt/live/apptabulous.co.uk/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/apptabulous.co.uk/privkey.pem; +# ssl_certificate /etc/letsencrypt/live/apptabulous.co.uk/fullchain.pem; +# ssl_certificate_key /etc/letsencrypt/live/apptabulous.co.uk/privkey.pem; - location / { - proxy_pass http://rpi4-2:8080; - } -} +# location / { +# proxy_pass http://rpi4-2:8080; +# } +# } diff --git a/apptabulous/reverseproxy/stream.d/ssh.conf b/apptabulous/reverseproxy/stream.d/ssh.conf index e35ebb1..85ca46a 100644 --- a/apptabulous/reverseproxy/stream.d/ssh.conf +++ b/apptabulous/reverseproxy/stream.d/ssh.conf @@ -1,7 +1,9 @@ # Stream the ssh connections for gitea -server { - listen 2222; - proxy_pass rpi5-2:2222; # the machine where sshd runs (often same as gitea) - proxy_timeout 1h; - proxy_connect_timeout 10s; -} +# The gitea container is running on the same machine as the reverse proxy for now, +# so we don't need to stream the ssh connection to another machine. +# server { +# listen 2222; +# proxy_pass rpi5-2:2222; # the machine where sshd runs (often same as gitea) +# proxy_timeout 1h; +# proxy_connect_timeout 10s; +# } diff --git a/frontend-cockpit.yaml b/frontend-cockpit.yaml new file mode 100755 index 0000000..7712655 --- /dev/null +++ b/frontend-cockpit.yaml @@ -0,0 +1,206 @@ +--- +- name: Frontend setup + hosts: frontend-cockpit + + vars: + username: matt + + certbot_install_method: package + certbot_create_method: standalone + # certbot_install_method: source + # certbot_repo: https://github.com/certbot/certbot.git + # certbot_version: master + certbot_keep_updated: true + # certbot_dir: /opt/certbot + certbot_create_extra_args: "--http-01-port 8080" + certbot_auto_renew_user: "root" + certbot_auto_renew_hour: "3" + certbot_auto_renew_minute: "30" + certbot_create_if_missing: true + certbot_admin_email: matthew@thespencers.me.uk + certbot_certs: + - domains: + - "apptabulous.co.uk" + - "www.apptabulous.co.uk" + - "hub.apptabulous.co.uk" + - "watchtower.apptabulous.co.uk" + webroot: "/var/www/html" + - domains: + - "m5p3nc3r.co.uk" + - "www.m5p3nc3r.co.uk" + - "gitea.m5p3nc3r.co.uk" + webroot: "/var/www/html" + + + cockpit_plugins: + - cockpit-podman + cockpit_core_packages: + - cockpit + - cockpit-bridge + - cockpit-ws + - cockpit-ws-selinux + - cockpit-system + + roles: + - role: geerlingguy.git + become: true + - role: geerlingguy.certbot + become: true + + pre_tasks: + - name: Install python3-libdnf5 for DNF5 support on Fedora 41+ + become: true + ansible.builtin.raw: dnf install -y python3-libdnf5 + when: ansible_facts['os_family'] == 'RedHat' + changed_when: false + + tasks: + - name: Reload systemd daemon + become: true + ansible.builtin.systemd: + daemon_reload: true + + - name: Install Cockpit + include_role: + name: linux-system-roles.cockpit + apply: + become: true + vars: + # Prometheus is currently running on port 9090 + cockpit_port: 9091 + cockpit_packages: default + + - name: Gather package facts + ansible.builtin.package_facts: + manager: auto + + - name: Remove unwanted Cockpit plugins + become: true + ansible.builtin.package: + name: "{{ ansible_facts.packages | dict2items + | selectattr('key', 'match', '^cockpit-') + | map(attribute='key') + | reject('in', cockpit_plugins + cockpit_core_packages) + | list }}" + state: absent + when: > + ansible_facts.packages | dict2items + | selectattr('key', 'match', '^cockpit-') + | map(attribute='key') + | reject('in', cockpit_plugins + cockpit_core_packages) + | list | length > 0 + + - name: Install Podman + become: true + ansible.builtin.package: + name: podman + state: present + + - name: Install Cockpit plugins + become: true + ansible.builtin.package: + name: "{{ cockpit_plugins }}" + state: present + + + - name: Grant {{ username }} read access to letsencrypt certificates + become: true + ansible.posix.acl: + path: /etc/letsencrypt + entity: "{{ username }}" + etype: user + permissions: rX + recursive: true + state: present + + - name: Override default certbot start/stop jobs + become: true + ansible.builtin.copy: + src: letsencrypt + dest: /etc + + - name: Copy reverse proxy configuration to host + become: true + ansible.builtin.copy: + src: apptabulous/reverseproxy + dest: /etc + + - name: Create shared container network + containers.podman.podman_network: + name: webservices + state: present + + - name: Start reverse proxy container + containers.podman.podman_container: + name: reverse_proxy + image: docker.io/library/nginx:alpine + restart_policy: always + network: webservices + volumes: + - /etc/reverseproxy/nginx.conf:/etc/nginx/nginx.conf + - /etc/reverseproxy/conf.d:/etc/nginx/conf.d + - /etc/reverseproxy/stream.d:/etc/nginx/stream.d + - /etc/letsencrypt:/etc/letsencrypt + ports: + - "8080:80" + - "8443:443" + state: started + + # - name: Start docker registry + # community.docker.docker_container: + # name: registry + # image: registry:2 + # restart_policy: always + # ports: + # - "5000:5000" + # state: started + + - name: Log into ghcr.io registry + # become: true + containers.podman.podman_login: + registry: ghcr.io + username: "{{ secrets.GITHUB_ACTOR }}" + password: "{{ secrets.GITHUB_TOKEN }}" + + - name: Open firewall ports for web services + become: true + ansible.posix.firewalld: + port: "{{ item }}/tcp" + permanent: true + state: enabled + immediate: true + loop: + - 8080 + - 8443 + - 2222 + + - name: Start m5p3nc3r website + containers.podman.podman_container: + name: website + image: ghcr.io/m5p3nc3r/website:main + restart_policy: always + network: webservices + label: + io.containers.autoupdate: registry + volumes: + - /home/matt/public/apps:/app/public/apps:Z + env: + NEXT_SERVER_ACTIONS_ENCRYPTION_KEY: "{{ secrets.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY }}" + state: started + + - name: Start Apptabulous website + containers.podman.podman_container: + name: apptabulous_website + image: ghcr.io/m5p3nc3r/apptabulous_website:main + restart_policy: always + network: webservices + label: + io.containers.autoupdate: registry + state: started + + - name: Enable podman auto-update timer + become: true + ansible.builtin.systemd: + name: podman-auto-update.timer + enabled: true + state: started diff --git a/frontend.yaml b/frontend.yaml index 83c783b..d7fafbd 100755 --- a/frontend.yaml +++ b/frontend.yaml @@ -62,7 +62,6 @@ community.docker.docker_container: name: reverse_proxy image: nginx:alpine - #image: ghcr.io/m5p3nc3r/nginx-keyval:main restart_policy: always volumes: - /etc/reverseproxy/nginx.conf:/etc/nginx/nginx.conf diff --git a/gitea.yaml b/gitea.yaml index 31580ac..577cb28 100644 --- a/gitea.yaml +++ b/gitea.yaml @@ -1,5 +1,5 @@ --- -- name: Frontend setup +- name: Gitea setup hosts: gitea vars: @@ -17,59 +17,37 @@ local: "/mnt/gitea_backups" remote: "/var/nfs/shared/gitea_backups" - - - docker_add_repo: true - docker_users: - - "{{ username }}" - - roles: - - role: geerlingguy.git - become: true - - role: geerlingguy.docker - become: true - tasks: - - name: Create myapp directory in home - ansible.builtin.file: - path: "{{ ansible_env.HOME }}/gitea" - state: directory - mode: "0755" + - name: Install Podman + become: true + ansible.builtin.package: + name: podman + state: present - - name: Copy the gitea compose file to the host - ansible.builtin.copy: - src: gitea/compose.yaml - dest: "{{ ansible_env.HOME }}/gitea/compose.yaml" - - # - name: Install NFS client - # ansible.builtin.apt: - # name: nfs-common - # state: present - # update_cache: true - # become: true - - - name: Stop gitea services if running - community.docker.docker_compose_v2: - project_src: "{{ ansible_env.HOME }}/gitea/" - state: absent - ignore_errors: true + - name: Allow containers to access NFS mounts + become: true + ansible.posix.seboolean: + name: virt_use_nfs + state: true + persistent: true - name: Unmount NFS volumes before creating mountpoint directories + become: true ansible.posix.mount: path: "{{ item.value.local }}" state: unmounted loop: "{{ mounts | dict2items }}" - become: true - name: Create mountpoint directories for gitea + become: true ansible.builtin.file: path: "{{ item.value.local }}" state: directory mode: "0755" - loop: "{{mounts | dict2items }}" - become: true + loop: "{{ mounts | dict2items }}" - - name: Mount an NFS volume for repositories + - name: Mount NFS volumes for gitea + become: true ansible.posix.mount: src: "192.168.1.160:{{ item.value.remote }}" path: "{{ item.value.local }}" @@ -77,29 +55,46 @@ state: mounted fstype: nfs loop: "{{ mounts | dict2items }}" + + - name: Open firewall ports for gitea become: true + ansible.posix.firewalld: + port: "{{ item }}/tcp" + permanent: true + state: enabled + immediate: true + loop: + - 3002 + - 2222 - - - name: Create and start services - community.docker.docker_compose_v2: - project_src: "{{ ansible_env.HOME }}/gitea/" + - name: Create shared container network + containers.podman.podman_network: + name: webservices state: present - - name: Start watchtower - community.docker.docker_container: - name: watchtower - image: nickfedor/watchtower + - name: Start gitea + containers.podman.podman_container: + name: gitea + image: docker.io/gitea/gitea:latest restart_policy: always + network: webservices + label: + io.containers.autoupdate: registry + env: + USER_UID: "977" + USER_GID: "988" + TZ: Europe/London volumes: - - /var/run/docker.sock:/var/run/docker.sock - - /home/matt/.docker/config.json:/config.json - command: - - --cleanup - - --http-api-update - - --http-api-token={{ secrets.WATCHTOWER_HTTP_API_TOKEN }} - - --http-api-periodic-polls + - /mnt/gitea_data:/data:z + - /mnt/gitea_repos:/data/git/repositories:z ports: - - "8080:8080" + - "3002:3000" + - "2222:22" state: started - + - name: Enable podman auto-update timer + become: true + ansible.builtin.systemd: + name: podman-auto-update.timer + enabled: true + state: started diff --git a/gitea/compose.yaml b/gitea/compose.yaml index f1b3bcc..94e064b 100644 --- a/gitea/compose.yaml +++ b/gitea/compose.yaml @@ -11,23 +11,14 @@ services: - TZ=Europe/London volumes: - # Local: app.ini, database (sqlite by default), queues (LevelDB), sessions, etc. - # - gitea-data:/data-old - - /mnt/gitea_data:/data - - # NAS: only repositories (best practice) - - /mnt/gitea_repos:/data/git/repositories + # NAS: configuration and repositories + - /mnt/gitea_data:/data:z + - /mnt/gitea_repos:/data/git/repositories:z # Optional: put LFS on NAS too - # - /mnt/gitea-lfs:/data/git/lfs + # - /mnt/gitea-lfs:/data/git/lfs:z - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro ports: - - "3000:3000" # Web + - "3002:3000" # Web - "2222:22" # SSH (container 22 -> host 2222) - -# volumes: -# gitea-data: -# driver: local diff --git a/github-runner.yaml b/github-runner.yaml index 234a0cd..19f7ed8 100755 --- a/github-runner.yaml +++ b/github-runner.yaml @@ -4,7 +4,6 @@ vars: username: matt - docker_add_repo: true docker_users: - "{{ username }}" @@ -13,22 +12,14 @@ - role: geerlingguy.docker become: true - - role: compscidr.github_runner.github_runner + tasks: + - name: Register GitHub runners + ansible.builtin.include_role: + name: compscidr.github_runner.github_runner vars: github_runner_install_docker: false github_runner_personal_access_token: "{{ secrets.GITHUB_ACTIONS_TOKEN }}" - github_runner_name: "aarch64-rpi5-runner" - github_runner_repo: "m5p3nc3r/website" - github_runner_lables: "aarch64, rpi5" - - tasks: - - name: Start watchtower - community.docker.docker_container: - name: watchtower - image: containrrr/watchtower - restart_policy: always - command: - - --cleanup - volumes: - - /var/run/docker.sock:/var/run/docker.sock - state: started + github_runner_name: "{{ item.name }}" + github_runner_repo: "{{ item.repo }}" + github_runner_labels: "{{ item.labels }}" + loop: "{{ runner_configs }}" diff --git a/host_vars/rpi5-2.yaml b/host_vars/rpi5-2.yaml new file mode 100644 index 0000000..68e179d --- /dev/null +++ b/host_vars/rpi5-2.yaml @@ -0,0 +1,5 @@ +--- +runner_configs: + - name: aarch64-rpi5-runner + repo: m5p3nc3r/website + labels: "aarch64,rpi5" diff --git a/host_vars/ryzen7.yaml b/host_vars/ryzen7.yaml new file mode 100644 index 0000000..44cecd7 --- /dev/null +++ b/host_vars/ryzen7.yaml @@ -0,0 +1,8 @@ +--- +runner_configs: + - name: amd64-ryzen7-runner + repo: m5p3nc3r/website + labels: "amd64,x86_64,ryzen7" + - name: arm64-ryzen7-runner + repo: m5p3nc3r/website + labels: "arm64,aarch64,ryzen7" diff --git a/inventory.yaml b/inventory.yaml index 5a90108..cc6faf4 100755 --- a/inventory.yaml +++ b/inventory.yaml @@ -1,13 +1,15 @@ all: hosts: - rpi4-1: - ansible_host: rpi4-1.local + # rpi4-1: + # ansible_host: rpi4-1.local rpi4-2: ansible_host: rpi4-2.local rpi5-1: ansible_host: rpi5-1.local rpi5-2: ansible_host: rpi5-2.local + ryzen7: + ansible_host: ryzen7 children: monitored: hosts: @@ -19,13 +21,18 @@ all: rpi4-2: {} frontend: hosts: - rpi4-1: {} + rpi4-2: {} + frontend-cockpit: + hosts: + ryzen7: {} github-runners: hosts: - rpi5-1: {} + # rpi5-2: {} + ryzen7: {} gitea: hosts: - rpi5-2: {} + # rpi5-2: {} + ryzen7: {} apt-cacher-ng: hosts: rpi4-2: {} \ No newline at end of file diff --git a/requirements.yml b/requirements.yml index bdd7896..56d1a44 100755 --- a/requirements.yml +++ b/requirements.yml @@ -1,10 +1,16 @@ --- collections: - community.docker + - community.general + - ansible.posix + - containers.podman - compscidr.github_runner roles: - - geerlingguy.certbot + - name: geerlingguy.certbot + src: https://github.com/geerlingguy/ansible-role-certbot + version: master - geerlingguy.git - geerlingguy.nginx - geerlingguy.docker + - linux-system-roles.cockpit