The Great Ansible Update.

This commit is contained in:
Viyurz 2024-02-17 19:01:04 +01:00
parent f264c34304
commit 474ca92782
82 changed files with 945 additions and 427 deletions

5
.gitignore vendored
View file

@ -1,4 +1 @@
coturn/secrets.conf
.env
synapse/matrix_access_token.txt
synapse/secrets.yaml
secrets.yml

20
README.md Normal file
View file

@ -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`.

27
ansible-playbook-selector.sh Executable file
View file

@ -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"

3
ansible.cfg Normal file
View file

@ -0,0 +1,3 @@
[defaults]
roles_path = ./roles
ask_vault_pass = True

View file

@ -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[@]}"

View file

@ -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

View file

@ -1 +0,0 @@
static-auth-secret=XXX

View file

@ -1,3 +0,0 @@
{
"default_server_name": "viyurz.fr"
}

105
env.yml Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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-----

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
- name: Setup Docker rootless
hosts: localhost
roles:
- include-vars
- dockerd

View file

@ -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

View file

@ -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

View file

@ -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 }}"

View file

@ -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

View file

@ -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.

View file

@ -0,0 +1 @@
coturn_project_dir: "{{ docker_projects_dir }}/{{ role_name }}"

View file

@ -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

View file

@ -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 }}"

View file

@ -0,0 +1,3 @@
{
"default_server_name": "{{ domain }}"
}

View file

@ -4,6 +4,6 @@ services:
image: vectorim/element-web:latest
restart: always
ports:
- 8084:80
- {{ ports['element'] }}:80
volumes:
- ./config.json:/app/config.json

View file

@ -0,0 +1 @@
element_project_dir: "{{ docker_projects_dir }}/{{ role_name }}"

View file

@ -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 }}"

View file

@ -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

View file

@ -0,0 +1 @@
etebase_project_dir: "{{ docker_projects_dir }}/{{ role_name }}"

View file

@ -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 }}"

View file

@ -0,0 +1,2 @@
username={{ cifs_credentials['username'] }}
password={{ cifs_credentials['password'] }}

View file

@ -0,0 +1 @@
fstab_cifs_credentials_filename: storagebox-cifs-credentials.txt

View file

@ -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 }}"

View file

@ -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

View file

@ -0,0 +1 @@
hedgedoc_project_dir: "{{ docker_projects_dir }}/{{ role_name }}"

View file

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 251 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 978 B

After

Width:  |  Height:  |  Size: 978 B

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View file

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

View file

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 5 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 576 KiB

After

Width:  |  Height:  |  Size: 576 KiB

View file

@ -1,4 +1,3 @@
user nginx;
pid /tmp/nginx.pid;
worker_processes auto;

View file

@ -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 }}"

View file

@ -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

View file

@ -0,0 +1 @@
homepage_project_dir: "{{ docker_projects_dir }}/{{ role_name }}"

View file

@ -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"

View file

@ -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']

View file

@ -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 {

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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 }}"

View file

@ -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:

View file

@ -0,0 +1 @@
searxng_project_dir: "{{ docker_projects_dir }}/{{ role_name }}"

View file

@ -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