commit dc401edc2e05c54004ec19216f7017654855591f Author: olli <> Date: Thu Aug 24 14:43:25 2023 +0200 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/turn.yml b/turn.yml new file mode 100644 index 0000000..07bdb96 --- /dev/null +++ b/turn.yml @@ -0,0 +1,260 @@ +--- +- name: turn + hosts: all + tasks: + + - name: Create /home/docker/turn.{{inventory_hostname}} dir + ansible.builtin.file: + path: /home/docker/turn.{{inventory_hostname}} + owner: root + group: docker + state: directory + mode: '0550' + + - name: Create /home/docker/turn.{{inventory_hostname}}/coturn dir + ansible.builtin.file: + path: /home/docker/turn.{{inventory_hostname}}/coturn + owner: nobody + group: docker + state: directory + mode: '0550' + + - name: /home/docker/turn.{{inventory_hostname}}/coturn/turnserver.conf + blockinfile: + path: /home/docker/turn.{{inventory_hostname}}/coturn/turnserver.conf + mode: "0400" + owner: nobody + group: root + create: yes + marker: "# {mark} ANSIBLE MANAGED BLOCK" + block: | + use-auth-secret + realm=turn.{{inventory_hostname}} + listening-port=3479 + tls-listening-port=5349 + min-port=49160 + max-port=49200 + verbose + allow-loopback-peers + log-file=stdout + new-log-timestamp + tls-listening-port=5349 + cert=/etc/coturn/cert.pem + pkey=/etc/coturn/key.pem + backup: yes + + - name: /home/docker/turn.{{inventory_hostname}}/genpw.sh (generate Random PW for Turn) + blockinfile: + path: /home/docker/turn.{{inventory_hostname}}/genpw.sh + create: yes + mode: 0550 + owner: root + group: docker + marker: "# {mark} ANSIBLE MANAGED BLOCK" + block: | + cd /home/docker/turn.{{inventory_hostname}} + turn_secret=$(pwgen -s 32 1) + turn_cli_secret=$(pwgen -s 32 1) + + [ -f env ] || echo "TURN_SECRET=!TURN_SECRET! + TURN_CLI_SECRET=!TURN_CLI_SECRET! + " >env + + chmod 440 env + chown root:docker env + sed -i "s/\!TURN_SECRET\!/$turn_secret/g" env + sed -i "s/\!TURN_CLI_SECRET\!/$turn_cli_secret/g" env + + . ./env + grep -q 'static-auth-secret=' coturn/turnserver.conf || echo "static-auth-secret=$TURN_SECRET" >>coturn/turnserver.conf + grep -q 'cli-password=' coturn/turnserver.conf || echo "cli-password=$TURN_CLI_SECRET" >>coturn/turnserver.conf + backup: yes + validate: /bin/bash -n %s + notify: run genpw.sh + + - name: /home/docker/turn.{{inventory_hostname}}/genpw.sh shebang + lineinfile: + path: /home/docker/turn.{{inventory_hostname}}/genpw.sh + insertbefore: BOF + line: "#!/bin/bash -e" + + - name: Gen initial passwords if not exists + ansible.builtin.shell: ./genpw.sh + args: + chdir: /home/docker/turn.{{inventory_hostname}} + creates: /home/docker/turn.{{inventory_hostname}}/env + + - name: /home/docker/turn.{{inventory_hostname}}/newip.sh (define external and local IP in turnserver.conf) + blockinfile: + path: /home/docker/turn.{{inventory_hostname}}/newip.sh + create: yes + mode: 0550 + owner: root + group: docker + marker: "# {mark} ANSIBLE MANAGED BLOCK" + block: | + . /etc/bash/gaboshlib.include + cd /home/docker/turn.{{inventory_hostname}}/coturn + + local_ip=$(ip route get 1 | grep " src " | head -n1 | cut -d" " -f7) + g_valid_ipv4 "$local_ip" || g_echo_error_exit "Invalid local_ip $local_ip" + external_ip=$(curl -s https://checkipv4.dedyn.io) + g_valid_ipv4 "$local_ip" || g_echo_error_exit "Invalid external_ip $external_ip" + if ! grep -q "external-ip=$local_ip/$external_ip" turnserver.conf + then + sed -i '/^external-ip=.*/d' turnserver.conf + echo "external-ip=$local_ip/$external_ip" >>turnserver.conf + fi + [ -f /home/docker/turn.{{inventory_hostname}}/docker-compose.yml ] && \ + docker compose -f /home/docker/turn.{{inventory_hostname}}/docker-compose.yml restart + exit 0 + backup: yes + validate: /bin/bash -n %s + notify: run newip.sh + + - name: /home/docker/turn.{{inventory_hostname}}/newip.sh shebang + lineinfile: + path: /home/docker/turn.{{inventory_hostname}}/newip.sh + insertbefore: BOF + line: "#!/bin/bash -e" + + - name: Update external and local IP in turnserver.conf + ansible.builtin.shell: ./newip.sh + args: + chdir: /home/docker/turn.{{inventory_hostname}} + changed_when: false + + - name: /home/docker/turn.{{inventory_hostname}}/docker-compose.yml Container Configuration + blockinfile: + path: /home/docker/turn.{{inventory_hostname}}/docker-compose.yml + create: yes + mode: 0440 + owner: root + group: docker + marker: "# {mark} ANSIBLE MANAGED BLOCK" + block: | + version: '3.6' + services: + + turn.{{inventory_hostname}}: + image: coturn/coturn:latest + restart: unless-stopped + volumes: + - /etc/localtime:/etc/localtime:ro + - ./coturn:/etc/coturn + ports: + - 49160-49200:49160-49200/udp + - 5349:5349 + - 5349:5349/udp + + # Workaround for getting a letsencrypt-cert by traefik + turn.{{inventory_hostname}}--ssl: + image: nginx:latest + restart: unless-stopped + volumes: + - ./htdocs:/usr/share/nginx/html:ro + - /etc/localtime:/etc/localtime:ro + networks: + - traefik + labels: + - traefik.enable=true + # HTTPS + - traefik.http.routers.turn-{{ ansible_facts['hostname'] }}.rule=Host(`turn.{{inventory_hostname}}`) + - traefik.http.routers.turn-{{ ansible_facts['hostname'] }}.entrypoints=https + - traefik.http.routers.turn-{{ ansible_facts['hostname'] }}.tls=true + # Proxy to service-port + - traefik.http.services.turn-{{ ansible_facts['hostname'] }}.loadbalancer.server.port=80 + - traefik.http.routers.turn-{{ ansible_facts['hostname'] }}.service=turn-{{ ansible_facts['hostname'] }} + # cert via letsencrypt + - traefik.http.routers.turn-{{ ansible_facts['hostname'] }}.tls.certresolver=letsencrypt + # activate secHeaders@file + - traefik.http.routers.turn-{{ ansible_facts['hostname'] }}.middlewares=secHeaders@file + # Traefik network + - traefik.docker.network=traefik + + networks: + traefik: + external: true + + notify: Restart turn + + - name: /usr/local/sbin/autoupdate.d/turn.update (workaround for valid ssl-certs) + blockinfile: + path: /usr/local/sbin/autoupdate.d/turn.update + mode: "0400" + owner: root + group: root + create: yes + marker: "# {mark} ANSIBLE MANAGED BLOCK" + block: | + # take letsencrypt-certs from traefik + cd /home/docker/turn.{{inventory_hostname}}/coturn + # cleanup + rm -f key.pem cert.pem + touch key.pem cert.pem + chown nobody key.pem cert.pem + chmod 400 key.pem cert.pem + # run ssl-container + docker compose -f /home/docker/turn.{{inventory_hostname}}/docker-compose.yml up turn.defiant.dedyn.io--ssl -d + # get cert + function getcert { + cat /home/docker/traefik/letsencrypt/acme.json | jq -r ".letsencrypt.Certificates[] | select(.domain.main==\"turn.{{inventory_hostname}}\") | .certificate" | base64 -d >cert.pem + } + + function getkey { + cat /home/docker/traefik/letsencrypt/acme.json | jq -r ".letsencrypt.Certificates[] | select(.domain.main==\"turn.{{inventory_hostname}}\") | .key" | base64 -d >key.pem + } + getkey + getcert + until [ -s cert.pem ] + do + getcert + sleep 31 + done + until [ -s key.pem ] + do + getkey + sleep 32 + done + docker compose -f /home/docker/turn.{{inventory_hostname}}/docker-compose.yml down + docker compose -f /home/docker/turn.{{inventory_hostname}}/docker-compose.yml up -d + backup: yes + validate: /bin/bash -n %s + notify: run turn.update + + - name: Allow turn for audio/video tcp + community.general.ufw: + rule: allow + port: '5349' + proto: tcp + + - name: Allow turn for audio/video udp + community.general.ufw: + rule: allow + port: '5349' + proto: udp + + handlers: + - name: run genpw.sh + ansible.builtin.shell: ./genpw.sh + args: + chdir: /home/docker/turn.{{inventory_hostname}} + notify: Restart turn + + - name: run newip.sh + ansible.builtin.shell: ./newip.sh + args: + chdir: /home/docker/turn.{{inventory_hostname}} + notify: Restart turn + + - name: run turn.update + ansible.builtin.shell: bash /usr/local/sbin/autoupdate.d/turn.update + notify: Restart turn + + + - name: Restart turn + ansible.builtin.shell: docker-compose up -d + args: + chdir: /home/docker/turn.{{inventory_hostname}} + +