diff --git a/.gitignore b/.gitignore index 965824b..769c244 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -coturn/secrets.conf -.env -synapse/matrix_access_token.txt -synapse/secrets.yaml +secrets.yml diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d8fd44 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# vps +This repository contains all the files I use to manage services hosted on [viyurz.fr](https://viyurz.fr). + + +## Requirements +Ansible: +``` +sudo apt install -y ansible +``` + +Setup SSL certificates with Certbot beforehand: +``` +sudo apt install -y certbot python3-certbot-dns-ovh +``` + + +## Secrets +Copy the existing `secrets.yml.example` to `secrets.yml`, run `ansible-vault encrypt secrets.yml` to encrypt the file with a password, and finally edit the newly encrypted file with `ansible-vault edit secrets.yml`. + +If you want to change the vault password run `ansible-vault rekey secrets.yml`. diff --git a/ansible-playbook-selector.sh b/ansible-playbook-selector.sh new file mode 100755 index 0000000..89d84a6 --- /dev/null +++ b/ansible-playbook-selector.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +script_relative_path="$(dirname "$0")" +declare -i playbook_number=1 +mapfile -t playbook_list < <(find "$script_relative_path/playbooks" -type f | grep -oP '[^/]+\.yml$') + + +echo "Playbook list:" +for playbook in "${playbook_list[@]}"; do + echo " [$playbook_number] $playbook" + playbook_number+=1 +done + +read -rp "Select playbook number to execute: " selected_playbook_number + + +selected_playbook_name="${playbook_list[((selected_playbook_number - 1))]}" + +if ! echo "$selected_playbook_number" | grep -qP '^[1-9][0-9]*$' || [[ -z "$selected_playbook_name" ]]; then + echo "Invalid playbook number entered." + exit 1 +fi + + +echo "Selected playbook: $selected_playbook_name" + +ansible-playbook "$script_relative_path/playbooks/$selected_playbook_name" diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..34e23ac --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +roles_path = ./roles +ask_vault_pass = True diff --git a/coturn/coturn-docker-entrypoint.sh b/coturn/coturn-docker-entrypoint.sh deleted file mode 100755 index 6a468f6..0000000 --- a/coturn/coturn-docker-entrypoint.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# If command starts with an option, prepend it with a `turnserver` binary. -if [ "${1:0:1}" == '-' ]; then - set -- turnserver "$@" -fi - -# Evaluate each argument separately to avoid mixing them up in a single `eval`. -expanded=() -for i in "$@"; do - expanded+=("$(eval "echo $i")") -done - -cp /etc/coturn/server.conf /tmp/turnserver.conf -cat /etc/coturn/secrets.conf >> /tmp/turnserver.conf - -exec "${expanded[@]}" diff --git a/coturn/docker-compose.yaml b/coturn/docker-compose.yaml deleted file mode 100644 index 0e38058..0000000 --- a/coturn/docker-compose.yaml +++ /dev/null @@ -1,25 +0,0 @@ -services: - coturn: - container_name: coturn - image: coturn/coturn:alpine - restart: always - user: '666:666' - command: - - "--log-file=stdout" - - "-c" - - "/tmp/turnserver.conf" - ports: - - 3478:3478 - - 3478:3478/udp - - 5349:5349 - - 5349:5349/udp - - 49152-49172:49152-49172/udp - tmpfs: - - /var/lib/coturn - volumes: - - ./turnserver.conf:/etc/coturn/server.conf - - ./coturn-docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh - - ./secrets.conf:/etc/coturn/secrets.conf - - /etc/letsencrypt/live/turn.viyurz.fr/fullchain.pem:/etc/coturn/cert.pem - # chown root:666 & chmod 640 on privkey file - - /etc/letsencrypt/live/turn.viyurz.fr/privkey.pem:/etc/coturn/pkey.pem diff --git a/coturn/secrets.conf.example b/coturn/secrets.conf.example deleted file mode 100644 index 018493e..0000000 --- a/coturn/secrets.conf.example +++ /dev/null @@ -1 +0,0 @@ -static-auth-secret=XXX diff --git a/element/config.json b/element/config.json deleted file mode 100644 index ac8ef5b..0000000 --- a/element/config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default_server_name": "viyurz.fr" -} diff --git a/env.yml b/env.yml new file mode 100644 index 0000000..79c9bd6 --- /dev/null +++ b/env.yml @@ -0,0 +1,105 @@ +domain: viyurz.fr +timezone: "Europe/Paris" +host_uid: 1000 +docker_projects_dir: "{{ ansible_env['HOME'] }}/docker-projects" + +# UID shift for mapping between host & containers +uid_shift: 99999 + + +cifs_host: "{{ cifs_credentials['username'] }}.your-storagebox.de" + +cifs_mounts: + backups: + src: "//{{ cifs_host }}/backup/backups" + path: /mnt/storagebox/backups + uid: 0 + gid: "{{ host_uid }}" + file_mode: 640 + dir_mode: 750 + storagebox: + src: "//{{ cifs_host }}/backup" + path: /mnt/storagebox + uid: 0 + gid: 0 + file_mode: 640 + dir_mode: 751 + syncthing: + src: "//{{ cifs_host }}/backup/syncthing" + path: /mnt/storagebox/syncthing + uid: "{{ users['syncthing'] + uid_shift }}" + gid: "{{ users['syncthing'] + uid_shift }}" + file_mode: 640 + dir_mode: 750 + + +projects: + - coturn + - element + - etebase + - hedgedoc + - homepage + - reverse-proxy + - searxng + - synapse + - syncthing + - vaultwarden + + +# Ports exposed to host +ports: + coturn_listening: 3478 + coturn_tls_listening: 5349 + coturn_relay_min: 49152 + coturn_relay_max: 49172 + element: 8084 + etebase: 3735 + hedgedoc: 8086 + homepage: 8082 + searxng: 8083 + synapse: 8008 + syncthing_discosrv: 8443 + syncthing_webui: 8384 + syncthing_tcp: 5432 + syncthing_udp: 22000 + vaultwarden: 8081 + + +# UID in containers +users: + coturn: 666 + etebase: 373 + hedgedoc: 1004 + hedgedoc_mysql: 1005 + homepage: 101 + searxng: 977 + searxng_redis: 999 + synapse: 991 + synapse_postgres: 70 + syncthing: 1001 + syncthing_discosrv: 1002 + vaultwarden: 1000 + + +volumes: + coturn_tls_certificate_file: "/etc/letsencrypt/live/turn.{{ domain }}/fullchain.pem" + coturn_tls_certificate_key_file: "/etc/letsencrypt/live/turn.{{ domain }}/privkey.pem" + etebase_datadir: /mnt/etebasedata + hedgedoc_mysql_datadir: /mnt/hedgedoc/mysql-data + hedgedoc_configdir: /mnt/hedgedoc/config + synapse_datadir: /mnt/synapsedata + synapse_postgres_datadir: /mnt/synapsepgdata + syncthing_datadir: "{{ cifs_mounts['syncthing']['path'] }}" + vaultwarden_datadir: /mnt/vwdata + + +# Service-specific variables +reverse_proxy: + ssl_certificate_file: "/etc/letsencrypt/live/{{ domain }}/fullchain.pem" + ssl_certificate_key_file: "/etc/letsencrypt/live/{{ domain }}/privkey.pem" + ssl_trusted_certificate_file: "/etc/letsencrypt/live/{{ domain }}/chain.pem" + resolver: "185.12.64.12 [a01:4ff:ff00::add:2] [2a01:4ff:ff00::add:1]" + + +synapse: + max_upload_size: 50M diff --git a/etebase/docker-compose.yaml b/etebase/docker-compose.yaml deleted file mode 100644 index 7e37640..0000000 --- a/etebase/docker-compose.yaml +++ /dev/null @@ -1,15 +0,0 @@ -services: - etebase: - image: victorrds/etebase:alpine - container_name: etebase - restart: always - user: '373:373' - environment: - SERVER: http - ALLOWED_HOSTS: etebase.viyurz.fr - SUPER_USER: v444599a8zJUBud60fu9uk9Vo3xXHinp - AUTO_UPDATE: 'true' - ports: - - 3735:3735 - volumes: - - /mnt/etebasedata:/data diff --git a/nc/docker-compose.yaml b/nc/docker-compose.yaml deleted file mode 100644 index d618e35..0000000 --- a/nc/docker-compose.yaml +++ /dev/null @@ -1,19 +0,0 @@ -services: - nextcloud: - image: nextcloud/all-in-one:latest - restart: always - container_name: nextcloud-aio-mastercontainer # This line is not allowed to be changed as otherwise AIO will not work correctly - environment: # Is needed when using any of the options below - - APACHE_PORT=11000 # Is needed when running behind a web server or reverse proxy (like Apache, Nginx, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md - - APACHE_IP_BINDING=127.0.0.1 # Should be set when running behind a web server or reverse proxy (like Apache, Nginx, Cloudflare Tunnel and else) that is running on the same host. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md - - NEXTCLOUD_DATADIR=/mnt/ncdata # Allows to set the host directory for Nextcloud's datadir. ⚠️⚠️⚠️ Warning: do not set or adjust this value after the initial Nextcloud installation is done! See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir - - WATCHTOWER_DOCKER_SOCKET_PATH=$XDG_RUNTIME_DIR/docker.sock - ports: - - 8080:8080 - volumes: - - nextcloud_aio_mastercontainer:/mnt/docker-aio-config # This line is not allowed to be changed as otherwise the built-in backup solution will not work - - $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock:ro # May be changed on macOS, Windows or docker rootless. See the applicable documentation. If adjusting, don't forget to also set 'WATCHTOWER_DOCKER_SOCKET_PATH'! - -volumes: - nextcloud_aio_mastercontainer: - name: nextcloud_aio_mastercontainer # This line is not allowed to be changed as otherwise the built-in backup solution will not work diff --git a/nginx-rp/dhparam.txt b/nginx-rp/dhparam.txt deleted file mode 100644 index 088f967..0000000 --- a/nginx-rp/dhparam.txt +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz -+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a -87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 -YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi -7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD -ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== ------END DH PARAMETERS----- \ No newline at end of file diff --git a/nginx-rp/setup.sh b/nginx-rp/setup.sh deleted file mode 100755 index 2df7389..0000000 --- a/nginx-rp/setup.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - - -if [[ $UID -ne 0 ]]; then - echo "This script must be run as root." - exit 1 -fi - -# Chemin relatif pour les cas où -# le script n'est pas exécuté depuis -# le répertoire où il se trouve. -rel_path="$(dirname "$0")" - -# Fichiers requis pour le script -files=('dhparam.txt' 'nginx.conf' 'reverse-proxy.conf') -for file in "${files[@]}"; do - if ! [[ -f "$rel_path/$file" ]]; then - echo "Required file $file is missing, exiting." - exit 1 - fi -done - - -if [[ ! -x /usr/sbin/nginx ]]; then - apt install -y nginx -fi - - -cp "$rel_path/nginx.conf" /etc/nginx/ -cp "$rel_path/reverse-proxy.conf" /etc/nginx/sites-available/ -cp "$rel_path/dhparam.txt" /etc/nginx/ - - -rm /etc/nginx/sites-enabled/* -ln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/reverse-proxy.conf - - -systemctl start nginx -systemctl reload nginx diff --git a/playbooks/config-fstab.yml b/playbooks/config-fstab.yml new file mode 100644 index 0000000..dd32451 --- /dev/null +++ b/playbooks/config-fstab.yml @@ -0,0 +1,10 @@ +# Playbook to mount CIFS mounts defined in env.yml +- name: Include variables files + hosts: localhost + roles: + - include-vars + +- name: Edit fstab configuration & mount CIFS devices + hosts: localhost + roles: + - fstab diff --git a/playbooks/setup-dockerd.yml b/playbooks/setup-dockerd.yml new file mode 100644 index 0000000..5ef14ab --- /dev/null +++ b/playbooks/setup-dockerd.yml @@ -0,0 +1,5 @@ +- name: Setup Docker rootless + hosts: localhost + roles: + - include-vars + - dockerd diff --git a/playbooks/update-services.yml b/playbooks/update-services.yml new file mode 100644 index 0000000..d97d179 --- /dev/null +++ b/playbooks/update-services.yml @@ -0,0 +1,28 @@ +- name: Include variables files & load nftables.conf + hosts: localhost + roles: + - include-vars + - nftables + +- name: Update project(s) + hosts: localhost + vars_prompt: + - name: selected_projects + prompt: "Choose projects to update (Keep empty to update all. Projects list: {{ hostvars['localhost']['projects'] }})" + private: false + unsafe: true + + - name: docker_pull_images + prompt: "Pull project(s) images?" + default: false + private: false + + tasks: + - name: Update project(s) + include_role: + name: "{{ project }}" + loop: "{{ (selected_projects | split) | default(projects, true) }}" + loop_control: + # Do not use default variable name 'item' to prevent collisions with loops in roles. + loop_var: project + when: project in projects diff --git a/ports.txt b/ports.txt deleted file mode 100644 index 7411685..0000000 --- a/ports.txt +++ /dev/null @@ -1,17 +0,0 @@ -80/443 -> NGINX reverse proxy -995 -> SSH -3478 -> coturn -3735 -> Etebase -5349 -> coturn -5432 -> Syncthing -8008 -> Synapse -8080 -> Nextcloud AIO -8081 -> Vaultwarden -8082 -> nginx-www -8083 -> SearXNG -8084 -> element-web -8384 -> Syncthing Web UI -8443 -> stdisco -11000 -> Nextcloud -22000 -> Syncthing -49152-49652/udp -> coturn diff --git a/roles/coturn/tasks/main.yml b/roles/coturn/tasks/main.yml new file mode 100644 index 0000000..69f2601 --- /dev/null +++ b/roles/coturn/tasks/main.yml @@ -0,0 +1,68 @@ +- name: "Create {{ coturn_project_dir }} project directory" + file: + path: "{{ coturn_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ coturn_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: Template turnserver.conf to project directory + template: + src: turnserver.conf + dest: "{{ coturn_project_dir }}/turnserver.conf" + owner: "{{ ansible_env['USER'] }}" + mode: '640' + # Store result to restart services if the file changed + register: coturn_template_turnserver_result + +# Separate task because template module cannot chown/chgrp to a non-existing user/group +- name: "Change group of turnserver.conf to coturn GID ({{ users['coturn'] + uid_shift }})" + file: + path: "{{ coturn_project_dir }}/turnserver.conf" + group: "{{ users['coturn'] + uid_shift }}" + become: true + +- name: Set limited permissions on certificate directories + file: + path: "/etc/{{ item }}" + state: directory + owner: root + group: root + mode: '751' + become: true + loop: + - letsencrypt + - letsencrypt/live + - letsencrypt/archive + +- name: Set limited permissions on certificate directories + file: + path: "/etc/letsencrypt/{{ item }}/turn.{{ domain }}" + state: directory + owner: "{{ host_uid }}" + group: "{{ users['coturn'] + uid_shift }}" + mode: '550' + become: true + loop: + - live + - archive + +- name: Set limited permissions on certificate key file + file: + path: "/etc/letsencrypt/live/turn.{{ domain }}/privkey.pem" + owner: root + group: "{{ users['coturn'] + uid_shift }}" + mode: '640' + become: true + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ coturn_project_dir }}" + pull: "{{ docker_pull_images | bool }}" + # Restart if config file(s) changed + restarted: "{{ coturn_template_turnserver_result['changed'] | bool }}" diff --git a/roles/coturn/templates/docker-compose.yaml b/roles/coturn/templates/docker-compose.yaml new file mode 100644 index 0000000..eaf00ec --- /dev/null +++ b/roles/coturn/templates/docker-compose.yaml @@ -0,0 +1,18 @@ +services: + coturn: + container_name: coturn + image: coturn/coturn:alpine + restart: always + user: {{ users['coturn'] }}:{{ users['coturn'] }} + ports: + - {{ ports['coturn_listening'] }}:{{ ports['coturn_listening'] }} + - {{ ports['coturn_listening'] }}:{{ ports['coturn_listening'] }}/udp + - {{ ports['coturn_tls_listening'] }}:{{ ports['coturn_tls_listening'] }} + - {{ ports['coturn_tls_listening'] }}:{{ ports['coturn_tls_listening'] }}/udp + - {{ ports['coturn_relay_min'] }}-{{ ports['coturn_relay_max'] }}:{{ ports['coturn_relay_min'] }}-{{ ports['coturn_relay_max'] }}/udp + tmpfs: + - /var/lib/coturn + volumes: + - ./turnserver.conf:/etc/coturn/turnserver.conf + - {{ volumes['coturn_tls_certificate_file'] }}:/etc/coturn/cert.pem + - {{ volumes['coturn_tls_certificate_key_file'] }}:/etc/coturn/pkey.pem diff --git a/coturn/turnserver.conf b/roles/coturn/templates/turnserver.conf similarity index 89% rename from coturn/turnserver.conf rename to roles/coturn/templates/turnserver.conf index 64ce8ec..30c334d 100644 --- a/coturn/turnserver.conf +++ b/roles/coturn/templates/turnserver.conf @@ -1,19 +1,19 @@ -# Required behind NAT -external-ip=167.235.49.84 -#external-ip=2a01:4f8:c0c:a25a::1 +listening-port={{ ports['coturn_listening'] }} +tls-listening-port={{ ports['coturn_tls_listening'] }} # Lower and upper bounds of the UDP relay endpoints: # (default values are 49152 and 65535) -min-port=49152 -max-port=49172 +min-port={{ ports['coturn_relay_min'] }} +max-port={{ ports['coturn_relay_max'] }} #verbose fingerprint # Credentials in secrets.conf (static-auth-secret) use-auth-secret +static-auth-secret={{ coturn_secrets['static_auth_secret'] }} -realm=turn.viyurz.fr +realm=turn.{{ domain }} # TLS certificates, including intermediate certs. # For Let's Encrypt certificates, use `fullchain.pem` here. diff --git a/roles/coturn/vars/main.yml b/roles/coturn/vars/main.yml new file mode 100644 index 0000000..0f1d007 --- /dev/null +++ b/roles/coturn/vars/main.yml @@ -0,0 +1 @@ +coturn_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/roles/dockerd/tasks/main.yml b/roles/dockerd/tasks/main.yml new file mode 100644 index 0000000..05be0fd --- /dev/null +++ b/roles/dockerd/tasks/main.yml @@ -0,0 +1,63 @@ +- name: Make sure required packages are installed + apt: + name: + - docker.io + - docker-compose + - rootlesskit + - slirp4netns + - uidmap + become: true + +- name: Make sure system-wide Docker daemon is stopped & disabled + service: + name: docker + state: stopped + enabled: false + become: true + +- name: Make sure system-wide Docker socket is stopped & disabled + service: + name: docker.socket + state: stopped + enabled: false + become: true + +- name: Run dockerd-rootless-setuptool.sh script + command: + cmd: /usr/share/docker.io/contrib/dockerd-rootless-setuptool.sh install + +- name: Make sure /usr/share/docker.io/contrib is in PATH variable + lineinfile: + path: "{{ ansible_env['HOME'] }}/.profile" + regex: '^export PATH="/usr/share/docker\.io/contrib' + line: 'export PATH="/usr/share/docker.io/contrib:$PATH"' + +- name: Make sure DOCKER_HOST variable is set correctly + lineinfile: + path: "{{ ansible_env['HOME'] }}/.profile" + regex: '^export DOCKER_HOST=' + line: "export DOCKER_HOST=unix:///run/user/{{ host_uid }}/docker.sock" + +- name: "Make sure lingering is enabled for user {{ ansible_env['USER'] }}" + command: + cmd: "loginctl enable-linger {{ ansible_env['USER'] }}" + become: true + +- name: "Create directory {{ ansible_env['HOME'] }}/.config/systemd/user/docker.service.d to override environment variables" + file: + path: "{{ ansible_env['HOME'] }}/.config/systemd/user/docker.service.d" + state: directory + +- name: Add environment variables to Docker user service to use slirp4netns RootlessKit port driver, which enables source IP propagation + copy: + dest: "{{ ansible_env['HOME'] }}/.config/systemd/user/docker.service.d/override.conf" + content: | + [Service] + Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns" + Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns" + +- name: Start/restart & enable Docker user service + service: + name: docker + state: restarted + enabled: true diff --git a/roles/element/tasks/main.yml b/roles/element/tasks/main.yml new file mode 100644 index 0000000..59c36ed --- /dev/null +++ b/roles/element/tasks/main.yml @@ -0,0 +1,28 @@ +- name: "Create {{ element_project_dir }} project directory" + file: + path: "{{ element_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ element_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: Template config.json to project directory + template: + src: config.json + dest: "{{ element_project_dir }}/config.json" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '644' + register: element_template_config_result + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ element_project_dir }}" + pull: "{{ docker_pull_images | bool }}" + # Restart if config file(s) changed + restarted: "{{ element_template_config_result['changed'] | bool }}" diff --git a/roles/element/templates/config.json b/roles/element/templates/config.json new file mode 100644 index 0000000..3c9758f --- /dev/null +++ b/roles/element/templates/config.json @@ -0,0 +1,3 @@ +{ + "default_server_name": "{{ domain }}" +} diff --git a/element/docker-compose.yaml b/roles/element/templates/docker-compose.yaml similarity index 83% rename from element/docker-compose.yaml rename to roles/element/templates/docker-compose.yaml index 4f60b70..65af780 100644 --- a/element/docker-compose.yaml +++ b/roles/element/templates/docker-compose.yaml @@ -4,6 +4,6 @@ services: image: vectorim/element-web:latest restart: always ports: - - 8084:80 + - {{ ports['element'] }}:80 volumes: - ./config.json:/app/config.json diff --git a/roles/element/vars/main.yml b/roles/element/vars/main.yml new file mode 100644 index 0000000..c4d0c56 --- /dev/null +++ b/roles/element/vars/main.yml @@ -0,0 +1 @@ +element_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/roles/etebase/tasks/main.yml b/roles/etebase/tasks/main.yml new file mode 100644 index 0000000..e5bb308 --- /dev/null +++ b/roles/etebase/tasks/main.yml @@ -0,0 +1,26 @@ +- name: "Create {{ etebase_project_dir }} project directory" + file: + path: "{{ etebase_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ etebase_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: "Create directory {{ volumes['etebase_datadir'] }} with correct permissions" + file: + path: "{{ volumes['etebase_datadir'] }}" + state: directory + owner: "{{ users['etebase'] + uid_shift }}" + group: "{{ users['etebase'] + uid_shift }}" + mode: '770' + become: true + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ etebase_project_dir }}" + pull: "{{ docker_pull_images | bool }}" diff --git a/roles/etebase/templates/docker-compose.yaml b/roles/etebase/templates/docker-compose.yaml new file mode 100644 index 0000000..8bddee6 --- /dev/null +++ b/roles/etebase/templates/docker-compose.yaml @@ -0,0 +1,15 @@ +services: + etebase: + image: victorrds/etebase:alpine + container_name: etebase + restart: always + user: {{ users['etebase'] }}:{{ users['etebase'] }} + environment: + SERVER: http + ALLOWED_HOSTS: etebase.{{ domain }} + AUTO_UPDATE: 'true' + TIME_ZONE: {{ timezone }} + ports: + - {{ ports['etebase'] }}:3735 + volumes: + - {{ volumes['etebase_datadir'] }}:/data diff --git a/roles/etebase/vars/main.yml b/roles/etebase/vars/main.yml new file mode 100644 index 0000000..8dd9ef6 --- /dev/null +++ b/roles/etebase/vars/main.yml @@ -0,0 +1 @@ +etebase_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/roles/fstab/tasks/main.yml b/roles/fstab/tasks/main.yml new file mode 100644 index 0000000..8498a57 --- /dev/null +++ b/roles/fstab/tasks/main.yml @@ -0,0 +1,24 @@ +- name: + become: true + block: + - name: Install package cifs-utils + apt: + name: cifs-utils + + - name: "Template {{ fstab_cifs_credentials_filename }} to /etc/{{ fstab_cifs_credentials_filename }}" + template: + src: "{{ fstab_cifs_credentials_filename }}" + dest: "/etc/{{ fstab_cifs_credentials_filename }}" + owner: root + group: root + mode: '600' + register: fstab_template_cifs_credentials_result + + - name: Mount/Remount CIFS devices & edit fstab accordingly + mount: + state: mounted + src: "{{ item.value.src }}" + path: "{{ item.value.path }}" + fstype: cifs + opts: "uid={{ item.value.uid }},gid={{ item.value.gid }},file_mode=0{{ item.value.file_mode }},dir_mode=0{{ item.value.dir_mode }},credentials=/etc/{{ fstab_cifs_credentials_filename }},iocharset=utf8,rw,mfsymlinks,vers=3.0,seal" + loop: "{{ cifs_mounts | dict2items }}" diff --git a/roles/fstab/templates/storagebox-cifs-credentials.txt b/roles/fstab/templates/storagebox-cifs-credentials.txt new file mode 100644 index 0000000..1d26e82 --- /dev/null +++ b/roles/fstab/templates/storagebox-cifs-credentials.txt @@ -0,0 +1,2 @@ +username={{ cifs_credentials['username'] }} +password={{ cifs_credentials['password'] }} diff --git a/roles/fstab/vars/main.yml b/roles/fstab/vars/main.yml new file mode 100644 index 0000000..5560290 --- /dev/null +++ b/roles/fstab/vars/main.yml @@ -0,0 +1 @@ +fstab_cifs_credentials_filename: storagebox-cifs-credentials.txt diff --git a/roles/hedgedoc/tasks/main.yml b/roles/hedgedoc/tasks/main.yml new file mode 100644 index 0000000..d1cc8ab --- /dev/null +++ b/roles/hedgedoc/tasks/main.yml @@ -0,0 +1,35 @@ +- name: "Create {{ hedgedoc_project_dir }} project directory" + file: + path: "{{ hedgedoc_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ hedgedoc_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: "Create directory {{ volumes['hedgedoc_configdir'] }} with correct permissions" + file: + path: "{{ volumes['hedgedoc_configdir'] }}" + state: directory + owner: "{{ users['hedgedoc'] + uid_shift }}" + group: "{{ users['hedgedoc'] + uid_shift }}" + mode: '770' + become: true + +- name: "Create directory {{ volumes['hedgedoc_mysql_datadir'] }} with correct permissions" + file: + path: "{{ volumes['hedgedoc_mysql_datadir'] }}" + state: directory + owner: "{{ users['hedgedoc_mysql'] + uid_shift }}" + group: "{{ users['hedgedoc_mysql'] + uid_shift }}" + mode: '770' + become: true + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ hedgedoc_project_dir }}" + pull: "{{ docker_pull_images | bool }}" diff --git a/roles/hedgedoc/templates/docker-compose.yaml b/roles/hedgedoc/templates/docker-compose.yaml new file mode 100644 index 0000000..859c6f9 --- /dev/null +++ b/roles/hedgedoc/templates/docker-compose.yaml @@ -0,0 +1,32 @@ +services: + hedgedoc: + container_name: hedgedoc + image: lscr.io/linuxserver/hedgedoc:latest + restart: always + environment: + - PUID={{ users['hedgedoc'] }} + - PGID={{ users['hedgedoc'] }} + - TZ={{ timezone }} + - DB_HOST=hedgedoc-mysql + - DB_PORT=3306 + - DB_USER=root + - DB_PASS={{ hedgedoc_secrets['mysql_root_password'] }} + - DB_NAME=hedgedoc + - CMD_DOMAIN=hedgedoc.{{ domain }} + ports: + - {{ ports['hedgedoc'] }}:3000 + volumes: + - {{ volumes['hedgedoc_configdir'] }}:/config + + mysql: + container_name: hedgedoc-mysql + image: mysql:latest + restart: always + user: {{ users['hedgedoc_mysql'] }}:{{ users['hedgedoc_mysql'] }} + environment: + MYSQL_DATABASE: hedgedoc + MYSQL_ROOT_PASSWORD: "{{ hedgedoc_secrets['mysql_root_password'] }}" + volumes: + - {{ volumes['hedgedoc_mysql_datadir'] }}:/var/lib/mysql + + diff --git a/roles/hedgedoc/vars/main.yml b/roles/hedgedoc/vars/main.yml new file mode 100644 index 0000000..1324eb1 --- /dev/null +++ b/roles/hedgedoc/vars/main.yml @@ -0,0 +1 @@ +hedgedoc_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/nginx-www/index/ark.png b/roles/homepage/files/index/ark.png similarity index 100% rename from nginx-www/index/ark.png rename to roles/homepage/files/index/ark.png diff --git a/nginx-www/index/etesync.png b/roles/homepage/files/index/etesync.png similarity index 100% rename from nginx-www/index/etesync.png rename to roles/homepage/files/index/etesync.png diff --git a/nginx-www/index/favicon-16x16.png b/roles/homepage/files/index/favicon-16x16.png similarity index 100% rename from nginx-www/index/favicon-16x16.png rename to roles/homepage/files/index/favicon-16x16.png diff --git a/nginx-www/index/favicon-32x32.png b/roles/homepage/files/index/favicon-32x32.png similarity index 100% rename from nginx-www/index/favicon-32x32.png rename to roles/homepage/files/index/favicon-32x32.png diff --git a/nginx-www/index/favicon.ico b/roles/homepage/files/index/favicon.ico similarity index 100% rename from nginx-www/index/favicon.ico rename to roles/homepage/files/index/favicon.ico diff --git a/nginx-www/index/index.css b/roles/homepage/files/index/index.css similarity index 100% rename from nginx-www/index/index.css rename to roles/homepage/files/index/index.css diff --git a/nginx-www/index/index.html b/roles/homepage/files/index/index.html similarity index 100% rename from nginx-www/index/index.html rename to roles/homepage/files/index/index.html diff --git a/nginx-www/index/logo.jpg b/roles/homepage/files/index/logo.jpg similarity index 100% rename from nginx-www/index/logo.jpg rename to roles/homepage/files/index/logo.jpg diff --git a/nginx-www/index/matrix.png b/roles/homepage/files/index/matrix.png similarity index 100% rename from nginx-www/index/matrix.png rename to roles/homepage/files/index/matrix.png diff --git a/nginx-www/index/nextcloud.png b/roles/homepage/files/index/nextcloud.png similarity index 100% rename from nginx-www/index/nextcloud.png rename to roles/homepage/files/index/nextcloud.png diff --git a/nginx-www/index/searxng.png b/roles/homepage/files/index/searxng.png similarity index 100% rename from nginx-www/index/searxng.png rename to roles/homepage/files/index/searxng.png diff --git a/nginx-www/index/vaultwarden.png b/roles/homepage/files/index/vaultwarden.png similarity index 100% rename from nginx-www/index/vaultwarden.png rename to roles/homepage/files/index/vaultwarden.png diff --git a/nginx-www/index/wallpaper.jpg b/roles/homepage/files/index/wallpaper.jpg similarity index 100% rename from nginx-www/index/wallpaper.jpg rename to roles/homepage/files/index/wallpaper.jpg diff --git a/nginx-www/nginx.conf b/roles/homepage/files/nginx.conf similarity index 98% rename from nginx-www/nginx.conf rename to roles/homepage/files/nginx.conf index 417ff4e..c961c57 100644 --- a/nginx-www/nginx.conf +++ b/roles/homepage/files/nginx.conf @@ -1,4 +1,3 @@ -user nginx; pid /tmp/nginx.pid; worker_processes auto; diff --git a/roles/homepage/tasks/main.yml b/roles/homepage/tasks/main.yml new file mode 100644 index 0000000..67338d4 --- /dev/null +++ b/roles/homepage/tasks/main.yml @@ -0,0 +1,29 @@ +- name: "Create {{ homepage_project_dir }} project directory" + file: + path: "{{ homepage_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ homepage_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: Copy nginx.conf and index/ to project directory + copy: + src: "{{ role_path }}/files/" + dest: "{{ homepage_project_dir }}" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '644' + # Store result to restart services if the file(s) changed + register: homepage_copy_files_result + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ homepage_project_dir }}" + pull: "{{ docker_pull_images | bool }}" + # Restart if config file(s) changed + restarted: "{{ homepage_copy_files_result['changed'] | bool }}" diff --git a/nginx-www/docker-compose.yaml b/roles/homepage/templates/docker-compose.yaml similarity index 52% rename from nginx-www/docker-compose.yaml rename to roles/homepage/templates/docker-compose.yaml index 251e859..47eb39f 100644 --- a/nginx-www/docker-compose.yaml +++ b/roles/homepage/templates/docker-compose.yaml @@ -1,11 +1,11 @@ services: - nginx-www: + homepage: image: nginx:alpine restart: always - container_name: nginx-www - user: '101:101' + container_name: homepage + user: {{ users['homepage'] }}:{{ users['homepage'] }} ports: - - 8082:80 + - {{ ports['homepage'] }}:80 volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./index:/mnt/index diff --git a/roles/homepage/vars/main.yml b/roles/homepage/vars/main.yml new file mode 100644 index 0000000..9f10282 --- /dev/null +++ b/roles/homepage/vars/main.yml @@ -0,0 +1 @@ +homepage_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/roles/include-vars/tasks/main.yml b/roles/include-vars/tasks/main.yml new file mode 100644 index 0000000..e72672b --- /dev/null +++ b/roles/include-vars/tasks/main.yml @@ -0,0 +1,7 @@ +- name: Include vars from env.yml file + include_vars: + file: "{{ playbook_dir }}/../env.yml" + +- name: Include secrets from secrets.yml file + include_vars: + file: "{{ playbook_dir }}/../secrets.yml" diff --git a/roles/nftables/tasks/main.yml b/roles/nftables/tasks/main.yml new file mode 100644 index 0000000..db4735b --- /dev/null +++ b/roles/nftables/tasks/main.yml @@ -0,0 +1,22 @@ +- name: + become: true + block: + - name: Install package nftables + apt: + name: nftables + + - name: Template nftables.conf to /etc/nftables.conf + template: + src: nftables.conf + dest: /etc/nftables.conf + owner: root + group: root + mode: '755' + register: nftables_template_conf_result + + - name: Restart nftables service + service: + name: nftables + state: restarted + enabled: true + when: nftables_template_conf_result['changed'] diff --git a/nftables.conf b/roles/nftables/templates/nftables.conf similarity index 50% rename from nftables.conf rename to roles/nftables/templates/nftables.conf index a211706..faefd77 100755 --- a/nftables.conf +++ b/roles/nftables/templates/nftables.conf @@ -10,21 +10,25 @@ table inet filter { ct state invalid drop ct state { established, related } accept + + # Allow ICMP + meta l4proto icmp limit rate 1/second accept + meta l4proto ipv6-icmp limit rate 1/second accept - # HTTP & Syncthing Relay - tcp dport { http, https, 5432, 22000 } limit rate 5/second accept - udp dport 22000 limit rate 5/second accept + # HTTP/S + tcp dport { http, https } limit rate 5/second accept # SSH tcp dport 995 limit rate 15/minute accept - # TURN - tcp dport { 3478, 5349 } limit rate 5/second accept - udp dport { 3478, 5349, 49152-49172 } limit rate 5/second accept + # Syncthing + tcp dport {{ ports['syncthing_tcp'] }} limit rate 5/second accept + udp dport {{ ports['syncthing_udp'] }} limit rate 5/second accept + + # Coturn + tcp dport { {{ ports['coturn_listening'] }}, {{ ports['coturn_tls_listening'] }} } limit rate 5/second accept + udp dport { {{ ports['coturn_listening'] }}, {{ ports['coturn_tls_listening'] }}, {{ ports['coturn_relay_min'] }}-{{ ports['coturn_relay_max'] }} } limit rate 5/second accept - # Allow ICMP - meta l4proto icmp limit rate 1/second accept - meta l4proto ipv6-icmp limit rate 1/second accept } chain forward { diff --git a/roles/reverse-proxy/tasks/main.yml b/roles/reverse-proxy/tasks/main.yml new file mode 100644 index 0000000..a8dbe62 --- /dev/null +++ b/roles/reverse-proxy/tasks/main.yml @@ -0,0 +1,70 @@ +- name: + become: true + block: + - name: Install package nginx + apt: + name: nginx + + - name: Template nginx.conf to /etc/nginx/nginx.conf + template: + src: nginx.conf + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: '644' + register: nginx_template_nginx_conf_result + + - name: Template reverse-proxy.conf to /etc/nginx/sites-available/reverse-proxy.conf + template: + src: reverse-proxy.conf + dest: /etc/nginx/sites-available/reverse-proxy.conf + owner: root + group: root + mode: '644' + register: nginx_template_reverse_proxy_conf_result + + - name: Remove all enabled NGINX sites + file: + state: "{{ item }}" + path: "/etc/nginx/sites-enabled" + owner: root + group: root + mode: '755' + loop: + - absent + - directory + + - name: Enable reverse-proxy.conf site + file: + state: link + src: /etc/nginx/sites-available/reverse-proxy.conf + dest: /etc/nginx/sites-enabled/reverse-proxy.conf + + - name: Get state of file /etc/nginx/dhparam.txt + stat: + path: /etc/nginx/dhparam.txt + register: nginx_stat_dhparam_result + + - name: Download dhparam file from Mozilla + get_url: + url: https://ssl-config.mozilla.org/ffdhe2048.txt + dest: /etc/nginx/dhparam.txt + when: not nginx_stat_dhparam_result.stat.exists + + - name: Set correct permissions on certificate directories + file: + path: "/etc/letsencrypt/{{ item }}/{{ domain }}" + state: directory + owner: root + group: root + mode: '750' + loop: + - live + - archive + + - name: Start/Reload NGINX service + service: + name: nginx + # Reload if conf changed, if not make sure it is started + state: "{{ (nginx_template_nginx_conf_result['changed'] or nginx_template_reverse_proxy_conf_result['changed']) | ternary('reloaded', 'started') }}" + enabled: yes diff --git a/nginx-rp/nginx.conf b/roles/reverse-proxy/templates/nginx.conf similarity index 88% rename from nginx-rp/nginx.conf rename to roles/reverse-proxy/templates/nginx.conf index dd0c39e..d7478f6 100644 --- a/nginx-rp/nginx.conf +++ b/roles/reverse-proxy/templates/nginx.conf @@ -32,9 +32,9 @@ http { # SSL Settings ## - ssl_certificate /etc/letsencrypt/live/viyurz.fr/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/viyurz.fr/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/viyurz.fr/chain.pem; + ssl_certificate {{ reverse_proxy['ssl_certificate_file'] }}; + ssl_certificate_key {{ reverse_proxy['ssl_certificate_key_file'] }}; + ssl_trusted_certificate {{ reverse_proxy['ssl_trusted_certificate_file'] }}; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; @@ -61,7 +61,7 @@ http { # Headers ## - resolver 185.12.64.12 [a01:4ff:ff00::add:2] [2a01:4ff:ff00::add:1]; + resolver {{ reverse_proxy['resolver'] }}; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # add_header X-Robots-Tag "noindex, nofollow" always; diff --git a/nginx-rp/reverse-proxy.conf b/roles/reverse-proxy/templates/reverse-proxy.conf similarity index 72% rename from nginx-rp/reverse-proxy.conf rename to roles/reverse-proxy/templates/reverse-proxy.conf index dd6935b..c31f664 100644 --- a/nginx-rp/reverse-proxy.conf +++ b/roles/reverse-proxy/templates/reverse-proxy.conf @@ -21,26 +21,26 @@ server { } -# Base domain / Homepage +# Homepage server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name viyurz.fr; + server_name {{ domain }}; location = /.well-known/matrix/server { default_type application/json; - return 200 '{ "m.server": "matrix.viyurz.fr:443" }'; + return 200 '{ "m.server": "matrix.{{ domain }}:443" }'; } location = /.well-known/matrix/client { default_type application/json; add_header Access-Control-Allow-Origin '*'; - return 200 '{ "m.homeserver": { "base_url": "https://matrix.viyurz.fr" } }'; + return 200 '{ "m.homeserver": { "base_url": "https://matrix.{{ domain }}" } }'; } location / { - proxy_pass http://localhost:8082; + proxy_pass http://localhost:{{ ports['homepage'] }}; } } @@ -50,7 +50,7 @@ server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name dl.viyurz.fr; + server_name dl.{{ domain }}; root /var/www/html; autoindex on; @@ -62,10 +62,10 @@ server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name element.viyurz.fr; + server_name element.{{ domain }}; location / { - proxy_pass http://localhost:8084; + proxy_pass http://localhost:{{ ports['element'] }}; add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; @@ -83,23 +83,36 @@ server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name etebase.viyurz.fr; + server_name etebase.{{ domain }}; location ~ ^/(?!admin) { - proxy_pass http://localhost:3735; + proxy_pass http://localhost:{{ ports['etebase'] }}; } } -# SearxNG +# Hedgedoc server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name searx.viyurz.fr; + server_name hedgedoc.{{ domain }}; + + location / { + proxy_pass http://localhost:{{ ports['hedgedoc'] }}; + } +} + + +# SearXNG +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name searx.{{ domain }}; location / { - proxy_pass http://localhost:8083; + proxy_pass http://localhost:{{ ports['searxng'] }}; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; add_header Set-Cookie "Path=/; HttpOnly; Secure"; @@ -113,37 +126,37 @@ server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name matrix.viyurz.fr; + server_name matrix.{{ domain }}; location ~ ^(/_matrix|/_synapse/client) { - proxy_pass http://localhost:8008; + proxy_pass http://localhost:{{ ports['synapse'] }}; # Nginx by default only allows file uploads up to 1M in size # Increase client_max_body_size to match max_upload_size defined in homeserver.yaml - client_max_body_size 50M; + client_max_body_size {{ synapse['max_upload_size'] }}; } location / { - return 308 https://element.viyurz.fr/; + return 308 https://element.{{ domain }}/; } } # Syncthing Discovery -upstream stdisco.viyurz.fr { +upstream stdisco.{{ domain }} { # Local IP address:port for discovery server - server localhost:8443; + server localhost:{{ ports['syncthing_discosrv'] }}; } server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name stdisco.viyurz.fr; + server_name stdisco.{{ domain }}; ssl_verify_client optional_no_ca; location / { - proxy_pass http://stdisco.viyurz.fr; + proxy_pass http://stdisco.{{ domain }}; proxy_set_header X-Client-Port $remote_port; proxy_set_header X-SSL-Cert $ssl_client_cert; @@ -156,14 +169,14 @@ server { # Vaultwarden upstream vaultwarden-default { zone vaultwarden-default 64k; - server localhost:8081; + server localhost:{{ ports['vaultwarden'] }}; keepalive 2; } server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name vw.viyurz.fr; + server_name vw.{{ domain }}; location / { proxy_pass http://vaultwarden-default; diff --git a/searxng/limiter.toml b/roles/searxng/files/limiter.toml similarity index 100% rename from searxng/limiter.toml rename to roles/searxng/files/limiter.toml diff --git a/searxng/settings.yml b/roles/searxng/files/settings.yml similarity index 100% rename from searxng/settings.yml rename to roles/searxng/files/settings.yml diff --git a/roles/searxng/tasks/main.yml b/roles/searxng/tasks/main.yml new file mode 100644 index 0000000..01bb50c --- /dev/null +++ b/roles/searxng/tasks/main.yml @@ -0,0 +1,29 @@ +- name: "Create {{ searxng_project_dir }} project directory" + file: + path: "{{ searxng_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ searxng_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: Copy settings.yml and limiter.toml to project directory + copy: + src: "{{ role_path }}/files/" + dest: "{{ searxng_project_dir }}" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '644' + # Store result to restart services if the file(s) changed + register: searxng_copy_files_result + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ searxng_project_dir }}" + pull: "{{ docker_pull_images | bool }}" + # Restart if config file(s) changed + restarted: "{{ searxng_copy_files_result['changed'] | bool }}" diff --git a/searxng/docker-compose.yaml b/roles/searxng/templates/docker-compose.yaml similarity index 72% rename from searxng/docker-compose.yaml rename to roles/searxng/templates/docker-compose.yaml index d5e2d30..41a291c 100644 --- a/searxng/docker-compose.yaml +++ b/roles/searxng/templates/docker-compose.yaml @@ -3,10 +3,8 @@ services: container_name: searxng-redis image: docker.io/library/redis:alpine restart: always + user: {{ users['searxng_redis'] }}:{{ users['searxng_redis'] }} command: redis-server --save 30 1 --loglevel warning - user: '999:999' - networks: - - searxng volumes: - redis:/data @@ -21,12 +19,10 @@ services: - SETGID - SETUID environment: - - SEARXNG_BASE_URL=https://searx.viyurz.fr/ - - SEARXNG_SECRET=${SEARXNG_SECRET} - networks: - - searxng + - SEARXNG_BASE_URL=https://searx.{{ domain }} + - SEARXNG_SECRET={{ searxng_secrets['searxng_secret'] }} ports: - - 8083:8080 + - {{ ports['searxng'] }}:8080 volumes: - ./settings.yml:/etc/searxng/settings.yml - ./limiter.toml:/etc/searxng/limiter.toml @@ -36,10 +32,5 @@ services: max-size: "1m" max-file: "1" -networks: - searxng: - ipam: - driver: default - volumes: redis: diff --git a/roles/searxng/vars/main.yml b/roles/searxng/vars/main.yml new file mode 100644 index 0000000..30462f4 --- /dev/null +++ b/roles/searxng/vars/main.yml @@ -0,0 +1 @@ +searxng_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/roles/synapse/tasks/main.yml b/roles/synapse/tasks/main.yml new file mode 100644 index 0000000..f97dbb5 --- /dev/null +++ b/roles/synapse/tasks/main.yml @@ -0,0 +1,53 @@ +- name: "Create {{ synapse_project_dir }} project directory" + file: + path: "{{ synapse_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ synapse_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: Template homeserver.yaml to project directory + template: + src: homeserver.yaml + dest: "{{ synapse_project_dir }}/homeserver.yaml" + owner: "{{ ansible_env['USER'] }}" + mode: '640' + # Store result to restart services if the file changed + register: synapse_template_homeserver_result + +# Separate task because template module cannot chown/chgrp to a non-existing user/group +- name: "Change group of homeserver.yaml to synapse GID ({{ users['synapse'] + uid_shift }})" + file: + path: "{{ synapse_project_dir }}/homeserver.yaml" + group: "{{ users['synapse'] + uid_shift }}" + become: true + +- name: "Create directory {{ volumes['synapse_datadir'] }} with correct permissions" + file: + path: "{{ volumes['synapse_datadir'] }}" + state: directory + owner: "{{ users['synapse'] + uid_shift }}" + group: "{{ users['synapse'] + uid_shift }}" + mode: '770' + become: true + +- name: "Create directory {{ volumes['synapse_postgres_datadir'] }} with correct permissions" + file: + path: "{{ volumes['synapse_postgres_datadir'] }}" + state: directory + owner: "{{ users['synapse_postgres'] + uid_shift }}" + group: "{{ users['synapse_postgres'] + uid_shift }}" + mode: '770' + become: true + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ synapse_project_dir }}" + pull: "{{ docker_pull_images | bool }}" + # Restart if config file(s) changed + restarted: "{{ synapse_template_homeserver_result['changed'] | bool }}" diff --git a/roles/synapse/templates/docker-compose.yaml b/roles/synapse/templates/docker-compose.yaml new file mode 100644 index 0000000..f072de9 --- /dev/null +++ b/roles/synapse/templates/docker-compose.yaml @@ -0,0 +1,27 @@ +services: + postgres: + container_name: synapse-postgres + image: postgres:alpine + restart: always + user: {{ users['synapse_postgres'] }}:{{ users['synapse_postgres'] }} + environment: + LANG: C + POSTGRES_INITDB_ARGS: "--locale=C --encoding=UTF8" + POSTGRES_USER: {{ synapse_secrets['postgres_user'] }} + POSTGRES_PASSWORD: {{ synapse_secrets['postgres_password'] }} + volumes: + - {{ volumes['synapse_postgres_datadir'] }}:/var/lib/postgresql/data + + synapse: + container_name: synapse + image: matrixdotorg/synapse:latest + restart: always + environment: + UID: {{ users['synapse'] }} + GID: {{ users['synapse'] }} + TZ: {{ timezone }} + ports: + - {{ ports['synapse'] }}:8008 + volumes: + - {{ volumes['synapse_datadir'] }}:/data + - ./homeserver.yaml:/data/homeserver.yaml diff --git a/synapse/homeserver.yaml b/roles/synapse/templates/homeserver.yaml similarity index 72% rename from synapse/homeserver.yaml rename to roles/synapse/templates/homeserver.yaml index e54a233..22f109c 100644 --- a/synapse/homeserver.yaml +++ b/roles/synapse/templates/homeserver.yaml @@ -4,7 +4,7 @@ # Server -server_name: "viyurz.fr" +server_name: "{{ domain }}" pid_file: /data/homeserver.pid listeners: - port: 8008 @@ -24,8 +24,8 @@ max_avatar_size: 2M database: name: psycopg2 args: - user: synapse - password: synapse + user: {{ synapse_secrets['postgres_user'] }} + password: {{ synapse_secrets['postgres_password'] }} dbname: synapse host: synapse-postgres cp_min: 5 @@ -33,13 +33,13 @@ database: # Logging -log_config: "/data/viyurz.fr.log.config" +log_config: "/data/{{ domain }}.log.config" # Media Store media_store_path: /data/media_store # Changer aussi le max_body_size dans le reverse proxy -max_upload_size: 50M +max_upload_size: {{ synapse['max_upload_size'] }} media_retention: remote_media_lifetime: 14d url_preview_enabled: true @@ -70,7 +70,8 @@ url_preview_accept_language: # TURN -turn_uris: ["turns:turn.viyurz.fr?transport=udp", "turns:turn.viyurz.fr?transport=tcp"] +turn_uris: ["turns:turn.{{ domain }}?transport=udp", "turns:turn.{{ domain }}?transport=tcp"] +turn_shared_secret: "{{ synapse_secrets['turn_shared_secret'] }}" turn_user_lifetime: 86400000 turn_allow_guests: true @@ -84,8 +85,13 @@ registration_requires_token: true report_stats: true +# API Configuration +macaroon_secret_key: "{{ synapse_secrets['macaroon_secret_key'] }}" +form_secret: "{{ synapse_secrets['form_secret'] }}" + + # Signing Keys -signing_key_path: "/data/viyurz.fr.signing.key" +signing_key_path: "/data/{{ domain }}.signing.key" trusted_key_servers: - server_name: "matrix.org" suppress_key_server_warning: true diff --git a/roles/synapse/vars/main.yml b/roles/synapse/vars/main.yml new file mode 100644 index 0000000..e4adca5 --- /dev/null +++ b/roles/synapse/vars/main.yml @@ -0,0 +1 @@ +synapse_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/roles/syncthing/tasks/main.yml b/roles/syncthing/tasks/main.yml new file mode 100644 index 0000000..2511e6f --- /dev/null +++ b/roles/syncthing/tasks/main.yml @@ -0,0 +1,17 @@ +- name: "Create {{ syncthing_project_dir }} project directory" + file: + path: "{{ syncthing_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ syncthing_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ syncthing_project_dir }}" + pull: "{{ docker_pull_images | bool }}" diff --git a/roles/syncthing/templates/docker-compose.yaml b/roles/syncthing/templates/docker-compose.yaml new file mode 100644 index 0000000..0955205 --- /dev/null +++ b/roles/syncthing/templates/docker-compose.yaml @@ -0,0 +1,35 @@ +services: + syncthing: + image: syncthing/syncthing:latest + container_name: syncthing + restart: always + user: {{ users['syncthing'] }}:{{ users['syncthing'] }} + environment: + - PUID={{ users['syncthing'] }} + - PGID={{ users['syncthing'] }} + ports: + - {{ ports['syncthing_webui'] }}:8384 # Web UI + - {{ ports['syncthing_tcp'] }}:22000/tcp # TCP file transfers + - {{ ports['syncthing_udp'] }}:22000/udp # QUIC file transfers + volumes: + - {{ volumes['syncthing_datadir'] }}:/var/syncthing + + stdiscosrv: + image: syncthing/discosrv:latest + container_name: syncthing-discosrv + restart: always + entrypoint: + - "/bin/entrypoint.sh" + - "/bin/stdiscosrv" + - "-http" + - "-debug" + environment: + - PUID={{ users['syncthing_discosrv'] }} + - PGID={{ users['syncthing_discosrv'] }} + networks: + - discosrv + ports: + - {{ ports['syncthing_discosrv'] }}:8443 + +networks: + discosrv: diff --git a/roles/syncthing/vars/main.yml b/roles/syncthing/vars/main.yml new file mode 100644 index 0000000..45bb45b --- /dev/null +++ b/roles/syncthing/vars/main.yml @@ -0,0 +1 @@ +syncthing_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/roles/vaultwarden/tasks/main.yml b/roles/vaultwarden/tasks/main.yml new file mode 100644 index 0000000..c154857 --- /dev/null +++ b/roles/vaultwarden/tasks/main.yml @@ -0,0 +1,26 @@ +- name: "Create {{ vaultwarden_project_dir }} project directory" + file: + path: "{{ vaultwarden_project_dir }}" + state: directory + +- name: Template docker-compose.yaml to project directory + template: + src: docker-compose.yaml + dest: "{{ vaultwarden_project_dir }}/docker-compose.yaml" + owner: "{{ ansible_env['USER'] }}" + group: "{{ ansible_env['USER'] }}" + mode: '640' + +- name: "Create directory {{ volumes['vaultwarden_datadir'] }} with correct permissions" + file: + path: "{{ volumes['vaultwarden_datadir'] }}" + state: directory + owner: "{{ users['vaultwarden'] + uid_shift }}" + group: "{{ users['vaultwarden'] + uid_shift }}" + mode: '770' + become: true + +- name: Pull/Create/Restart project services + community.docker.docker_compose: + project_src: "{{ vaultwarden_project_dir }}" + pull: "{{ docker_pull_images | bool }}" diff --git a/vw/docker-compose.yaml b/roles/vaultwarden/templates/docker-compose.yaml similarity index 53% rename from vw/docker-compose.yaml rename to roles/vaultwarden/templates/docker-compose.yaml index e1d5c3c..17aed67 100644 --- a/vw/docker-compose.yaml +++ b/roles/vaultwarden/templates/docker-compose.yaml @@ -3,12 +3,12 @@ services: image: vaultwarden/server:alpine container_name: vaultwarden restart: always - user: '1000:1000' + user: {{ users['vaultwarden'] }}:{{ users['vaultwarden'] }} environment: - - DOMAIN=https://vw.viyurz.fr # Your domain; vaultwarden needs to know it's https to work properly with attachments + - DOMAIN=https://vw.{{ domain }} - SIGNUPS_ALLOWED=false - INVITATIONS_ALLOWED=false ports: - - 8081:80 + - {{ ports['vaultwarden'] }}:80 volumes: - - /mnt/vwdata:/data + - {{ volumes['vaultwarden_datadir' ] }}:/data diff --git a/roles/vaultwarden/vars/main.yml b/roles/vaultwarden/vars/main.yml new file mode 100644 index 0000000..50892d2 --- /dev/null +++ b/roles/vaultwarden/vars/main.yml @@ -0,0 +1 @@ +vaultwarden_project_dir: "{{ docker_projects_dir }}/{{ role_name }}" diff --git a/searxng/.env.example b/searxng/.env.example deleted file mode 100644 index 112b909..0000000 --- a/searxng/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -# Generate secret with: -# $ cat /dev/urandom | tr -dc 'a-z-A-Z-0-9' | head -c 50 - -SEARXNG_SECRET=XXX diff --git a/secrets.yml.example b/secrets.yml.example new file mode 100644 index 0000000..60161e5 --- /dev/null +++ b/secrets.yml.example @@ -0,0 +1,22 @@ +ansible_become_password: + +cifs_credentials: + username: + password: + +# To generate random secret: openssl rand -base64 50 +coturn_secrets: + static_auth_secret: + +hedgedoc_secrets: + mysql_root_password: + +searxng_secrets: + searxng_secret: + +synapse_secrets: + postgres_user: + postgres_password: + turn_shared_secret: "{{ coturn_secrets['static_auth_secret'] }}" + macaroon_secret_key: + form_secret: diff --git a/setup-rootless.sh b/setup-rootless.sh deleted file mode 100755 index bfe1315..0000000 --- a/setup-rootless.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -sudo apt install -y uidmap slirp4netns rootlesskit - -if ! grep -q '/usr/share/docker.io/contrib' "$HOME/.profile" > /dev/null; then - echo 'export PATH="/usr/share/docker.io/contrib:$PATH"' >> "$HOME/.profile" -fi - -if ! grep -q 'DOCKER_HOST' "$HOME/.profile" > /dev/null; then - echo "export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock" >> "$HOME/.profile" -fi - -sudo loginctl enable-linger "$USER" - -PATH="/usr/share/docker.io/contrib:$PATH" dockerd-rootless-setuptool.sh install - -mkdir -p "$HOME/.config/systemd/user/docker.service.d" - -cat << EOF > "$HOME/.config/systemd/user/docker.service.d/override.conf" -[Service] -Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns" -Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns" -EOF - -systemctl --user enable docker -systemctl --user restart docker diff --git a/synapse/docker-compose.yaml b/synapse/docker-compose.yaml deleted file mode 100644 index d0419b1..0000000 --- a/synapse/docker-compose.yaml +++ /dev/null @@ -1,44 +0,0 @@ -services: - postgres: - container_name: synapse-postgres - image: postgres:alpine - restart: always - user: '70:70' - environment: - LANG: C - POSTGRES_INITDB_ARGS: "--locale=C --encoding=UTF8" - POSTGRES_USER: synapse - POSTGRES_PASSWORD: synapse - networks: - - synapse - volumes: - - /mnt/synapsepgdata:/var/lib/postgresql/data - - synapse: - container_name: synapse - image: matrixdotorg/synapse:latest - # command: generate - restart: always - user: '991:991' - command: > - run - --config-path=/data/homeserver.yaml - --config-path=/data/secrets.yaml - environment: - SYNAPSE_SERVER_NAME: viyurz.fr - SYNAPSE_REPORT_STATS: "yes" - SYNAPSE_HTTP_PORT: 8008 - TZ: "Europe/Paris" - networks: - - synapse - ports: - - 8008:8008 - volumes: - - /mnt/synapsedata:/data - - ./homeserver.yaml:/data/homeserver.yaml - - ./secrets.yaml:/data/secrets.yaml - -networks: - synapse: - ipam: - driver: default diff --git a/synapse/generate_registration_token.sh b/synapse/generate_registration_token.sh deleted file mode 100755 index 66a3f4f..0000000 --- a/synapse/generate_registration_token.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -rel_path="$(dirname "$0")" -access_token="$(cat $rel_path/./matrix_access_token.txt)" - -curl --header "Authorization: Bearer $access_token" \ - -H "Content-Type: application/json" -w "\n" \ - -X POST http://localhost:8008/_synapse/admin/v1/registration_tokens/new \ - -d '{ "uses_allowed": 1, "expiry_time": '"$(date +%s000 -d tomorrow)"' }' diff --git a/synapse/matrix_access_token.txt.example b/synapse/matrix_access_token.txt.example deleted file mode 100644 index cd3b7a9..0000000 --- a/synapse/matrix_access_token.txt.example +++ /dev/null @@ -1 +0,0 @@ -syt_XXX diff --git a/synapse/secrets.yaml.example b/synapse/secrets.yaml.example deleted file mode 100644 index 84063dd..0000000 --- a/synapse/secrets.yaml.example +++ /dev/null @@ -1,6 +0,0 @@ -# Generate random secret: -# $ cat /dev/urandom | tr -dc '[:graph:]' | tr -d '"\\' | head -c 50 - -turn_shared_secret: "XXX" -macaroon_secret_key: "XXX" -form_secret: "XXX" diff --git a/syncthing/docker-compose.yaml b/syncthing/docker-compose.yaml deleted file mode 100644 index 5017562..0000000 --- a/syncthing/docker-compose.yaml +++ /dev/null @@ -1,36 +0,0 @@ -services: - syncthing: - image: syncthing/syncthing:latest - container_name: syncthing - restart: always - user: '1001:1001' - environment: - - PUID=1001 - - PGID=1001 - ports: - - 8384:8384 # Web UI - - 22000:22000/tcp # TCP file transfers - - 22000:22000/udp # QUIC file transfers - - 5432:22000/tcp - volumes: - - /mnt/syncthing:/var/syncthing - - stdiscosrv: - image: syncthing/discosrv:latest - container_name: stdiscosrv - restart: always - entrypoint: - - "/bin/entrypoint.sh" - - "/bin/stdiscosrv" - - "-http" - - "-debug" - environment: - - PUID=1002 - - PGID=1002 - networks: - - disco - ports: - - 8443:8443 - -networks: - disco: diff --git a/update.sh b/update.sh deleted file mode 100755 index eaa7464..0000000 --- a/update.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash - - -services=(coturn element etebase nginx-www searxng synapse syncthing vw) -needs_backup=(etebase synapse vw) - - -rel_path="$(dirname "$0")" - - -function pull { - docker-compose -f "$rel_path/$1/docker-compose.yaml" pull -} - - -# Runs compose up & eventually make a backup before -# $1 = project name -function up { - if echo "${needs_backup[*]}" | grep -qP "\b$1\b" && has_update "$1"; then - sudo "$rel_path/backup.sh" "$1" --norestart - fi - - docker-compose -f "$rel_path/$1/docker-compose.yaml" up -d -} - - -# To use after pulling latest images of project -# Checks if at least one container can be updated -# $1 = project name -function has_update { - readarray -t cont_list < <(docker-compose -f "$rel_path/$1/docker-compose.yaml" ps -a | tail -n+3 | cut -d ' ' -f 1) - for cont in "${cont_list[@]}"; do - # Return true if container doesn't exist - if ! docker ps -a --format='{{.Names}}' | grep -q "$cont"; then - return 0 - fi - cont_image_id="$(docker inspect "$cont" --format='{{.Image}}')" - repo_url="$(docker inspect "$cont" --format='{{.Config.Image}}')" - repo_image_id="$(docker image inspect "$repo_url" --format='{{.Id}}')" - if [[ "$cont_image_id" != "$repo_image_id" ]]; then - return 0 - fi - done - return 1 -} - - -service="$(echo "$2" | sed -E 's/[/ ]//g')" - - -case "$1" in - pull) - if [[ -z "$service" ]]; then - for serv in "${services[@]}"; do - pull "$serv" - done - elif echo "${services[*]}" | grep -qP "\b$service\b"; then - pull "$service" - else - echo "invalid project name. it should be one of: ${services[*]}." - fi - ;; - - up) - if [[ -z "$service" ]]; then - for serv in "${services[@]}"; do - pull "$serv" - up "$serv" - done - elif echo "${services[*]}" | grep -qP "\b$service\b"; then - pull "$service" - up "$service" - else - echo "Invalid project name. It should be one of: ${services[*]}." - fi - ;; - - *) - echo "Invalid action. It should be one of: pull, up." - ;; -esac