From 37a91000f42bfa3b8b006ab2f1e672eb961ec1cc Mon Sep 17 00:00:00 2001
From: polyfloyd <floyd@polyfloyd.net>
Date: Mon, 31 Oct 2022 21:19:33 +0100
Subject: [PATCH] Add etherpad

---
 hosts.yaml                                |   3 +
 pad.yaml                                  |   9 ++
 roles/etherpad/defaults/main.yaml         |   4 +
 roles/etherpad/handlers/main.yaml         |   8 ++
 roles/etherpad/tasks/main.yaml            | 124 ++++++++++++++++++++++
 roles/etherpad/templates/etherpad.service |  16 +++
 roles/etherpad/templates/nginx-site.conf  |  33 ++++++
 roles/etherpad/templates/nodesource.list  |   4 +
 roles/etherpad/templates/settings.json    | 113 ++++++++++++++++++++
 9 files changed, 314 insertions(+)
 create mode 100644 pad.yaml
 create mode 100644 roles/etherpad/defaults/main.yaml
 create mode 100644 roles/etherpad/handlers/main.yaml
 create mode 100644 roles/etherpad/tasks/main.yaml
 create mode 100644 roles/etherpad/templates/etherpad.service
 create mode 100644 roles/etherpad/templates/nginx-site.conf
 create mode 100644 roles/etherpad/templates/nodesource.list
 create mode 100644 roles/etherpad/templates/settings.json

diff --git a/hosts.yaml b/hosts.yaml
index 85622b6..a7ce13e 100644
--- a/hosts.yaml
+++ b/hosts.yaml
@@ -11,6 +11,9 @@ all:
         git:
           hosts:
             git.bitlair.nl:
+        pad:
+          hosts:
+            pad.bitlair.nl:
         lights:
           hosts:
             lights.bitlair.nl:
diff --git a/pad.yaml b/pad.yaml
new file mode 100644
index 0000000..63d91b1
--- /dev/null
+++ b/pad.yaml
@@ -0,0 +1,9 @@
+---
+- hosts: pad
+  vars:
+    acme_san_domains:
+      - [ pad.bitlair.nl ]
+  roles:
+    - common
+    - acme
+    - etherpad
diff --git a/roles/etherpad/defaults/main.yaml b/roles/etherpad/defaults/main.yaml
new file mode 100644
index 0000000..ed6395f
--- /dev/null
+++ b/roles/etherpad/defaults/main.yaml
@@ -0,0 +1,4 @@
+nodejs_version: node_18.x
+etherpad_db_user: etherpad
+etherpad_db_password: "{{ lookup('password', '/tmp/etherpad_db_password length=32') }}"
+etherpad_db_name: etherpad
diff --git a/roles/etherpad/handlers/main.yaml b/roles/etherpad/handlers/main.yaml
new file mode 100644
index 0000000..39fb4d8
--- /dev/null
+++ b/roles/etherpad/handlers/main.yaml
@@ -0,0 +1,8 @@
+---
+- import_tasks: ../../common/handlers/main.yaml
+
+- name: restart etherpad
+  systemd:
+    name: etherpad
+    state: restarted
+    daemon_reload: true
diff --git a/roles/etherpad/tasks/main.yaml b/roles/etherpad/tasks/main.yaml
new file mode 100644
index 0000000..b80c15b
--- /dev/null
+++ b/roles/etherpad/tasks/main.yaml
@@ -0,0 +1,124 @@
+---
+- tags: etherpad
+  block:
+    - name: Install dependencies
+      apt:
+        name: [ gpg, nginx, postgresql, python3-psycopg2 ]
+
+    - name: Import nodesource signing key
+      apt_key:
+        url: https://deb.nodesource.com/gpgkey/nodesource.gpg.key
+      notify: apt update
+
+    - name: Install nodesource source list
+      template:
+        src: nodesource.list
+        dest: /etc/apt/sources.list.d/nodesource.list
+        owner: root
+        group: root
+        mode: 0644
+      notify: apt update
+
+    - meta: flush_handlers
+
+    - name: Install nodejs
+      apt:
+        name: nodejs
+
+    - name: Add database user
+      become: true
+      become_method: su
+      become_user: postgres
+      no_log: yes
+      postgresql_user:
+        name: etherpad
+        password: "{{ etherpad_db_password }}"
+
+    - name: Add database
+      become: true
+      become_method: su
+      become_user: postgres
+      postgresql_db:
+        name: "{{ etherpad_db_name }}"
+        owner: "{{ etherpad_db_user }}"
+
+    - name: Add etherpad user
+      user:
+        name: etherpad
+        home: /var/lib/etherpad
+
+    - name: Create log file
+      file:
+        path: /var/log/etherpad.log
+        state: touch
+        owner: etherpad
+        group: etherpad
+        mode: 0644
+
+    - name: Create source directory
+      file:
+        path: /opt/etherpad
+        state: directory
+        owner: etherpad
+        group: etherpad
+        mode: 0755
+
+    - name: Clone etherpad source
+      become: yes
+      become_method: su
+      become_user: etherpad
+      git:
+        repo: https://github.com/ether/etherpad-lite.git
+        version: master
+        dest: /opt/etherpad
+        accept_hostkey: yes
+      notify: restart etherpad
+
+    - name: Install etherpad config
+      template:
+        src: settings.json
+        dest: /opt/etherpad/settings.json
+        owner: root
+        group: root
+        mode: 0644
+      notify: restart etherpad
+
+    - name: Install etherpad service
+      template:
+        src: etherpad.service
+        dest: /etc/systemd/system/etherpad.service
+        owner: root
+        group: root
+        mode: 0644
+      notify: restart etherpad
+
+    - name: Clear default nginx site
+      file:
+        state: absent
+        path: /etc/nginx/sites-enabled/default
+      notify: reload nginx
+
+    - name: Install nginx config
+      template:
+        src: nginx-site.conf
+        dest: /etc/nginx/sites-enabled/etherpad
+        owner: root
+        group: root
+        mode: 0644
+      notify: reload nginx
+
+    - name: Allow HTTP and HTTPS
+      iptables:
+        chain: INPUT
+        protocol: tcp
+        destination_port: "{{ item.port }}"
+        ctstate: NEW
+        jump: ACCEPT
+        ip_version: "{{ item.ip }}"
+        action: insert
+      with_items:
+        - { ip: ipv4, port: 80 }
+        - { ip: ipv4, port: 443 }
+        - { ip: ipv6, port: 80 }
+        - { ip: ipv6, port: 443 }
+      notify: persist iptables
diff --git a/roles/etherpad/templates/etherpad.service b/roles/etherpad/templates/etherpad.service
new file mode 100644
index 0000000..ae128af
--- /dev/null
+++ b/roles/etherpad/templates/etherpad.service
@@ -0,0 +1,16 @@
+# Managed by Ansible
+
+[Unit]
+Description=Etherpad
+After=network.target
+
+[Service]
+Type=simple
+Restart=always
+RestartSec=10s
+ExecStart=/opt/etherpad/src/bin/run.sh /var/log/etherpad.log
+User=etherpad
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/roles/etherpad/templates/nginx-site.conf b/roles/etherpad/templates/nginx-site.conf
new file mode 100644
index 0000000..9910a4d
--- /dev/null
+++ b/roles/etherpad/templates/nginx-site.conf
@@ -0,0 +1,33 @@
+server {
+	listen 443 ssl http2 default_server;
+	listen [::]:443 ssl http2 default_server;
+	server_name {{ etherpad_domain }};
+
+	{% if acme_bootstrap_certs %}
+	include "snippets/snakeoil.conf";
+	{% else %}
+	ssl_certificate     "/var/lib/dehydrated/certs/{{ etherpad_domain }}/fullchain.pem";
+	ssl_certificate_key "/var/lib/dehydrated/certs/{{ etherpad_domain }}/privkey.pem";
+	{% endif %}
+
+	location / {
+		proxy_pass http://127.0.0.1:9001/;
+		include proxy_params;
+		proxy_set_header Upgrade $http_upgrade;
+		proxy_set_header Connection "upgrade";
+	}
+
+	include "snippets/acme.conf";
+}
+
+server {
+	listen 80 default_server;
+	listen [::]:80 default_server;
+	server_name {{ etherpad_domain }};
+
+	location / {
+		rewrite ^/(.*) https://$server_name$request_uri? redirect;
+	}
+
+	include "snippets/acme.conf";
+}
diff --git a/roles/etherpad/templates/nodesource.list b/roles/etherpad/templates/nodesource.list
new file mode 100644
index 0000000..1d17937
--- /dev/null
+++ b/roles/etherpad/templates/nodesource.list
@@ -0,0 +1,4 @@
+# Managed by Ansible
+
+deb https://deb.nodesource.com/{{ nodejs_version }} {{ ansible_facts.distribution_release }} main
+deb-src https://deb.nodesource.com/{{ nodejs_version }} {{ ansible_facts.distribution_release }} main
diff --git a/roles/etherpad/templates/settings.json b/roles/etherpad/templates/settings.json
new file mode 100644
index 0000000..c73cdee
--- /dev/null
+++ b/roles/etherpad/templates/settings.json
@@ -0,0 +1,113 @@
+// Managed by Ansible
+
+{
+  "title": "Bitlair Etherpad",
+  "favicon": null,
+  "skinName": "colibris",
+  "skinVariants": "super-light-toolbar super-light-editor light-background",
+  "ip": "127.0.0.1",
+  "port": "9001",
+  "showSettingsInAdminPage": true,
+
+  "dbType" : "postgres",
+  "dbSettings" : {
+    "host":     "localhost",
+    "user":     "{{ etherpad_db_user }}",
+    "password": "{{ etherpad_db_password }}",
+    "database": "{{ etherpad_db_name }}"
+  },
+
+  "defaultPadText" : "Welkom op Bitlair's Etherpad!\n\nPer 2022-10-30 is deze opnieuw geïnstalleerd. Je oude notities zijn tot 2022-12-01 terug te vinden op pad-oud.bitlair.nl",
+
+  "padOptions": {
+    "noColors":         false,
+    "showControls":     true,
+    "showChat":         true,
+    "showLineNumbers":  true,
+    "useMonospaceFont": false,
+    "userName":         false,
+    "userColor":        false,
+    "rtl":              false,
+    "alwaysShowChat":   false,
+    "chatAndUsers":     false,
+    "lang":             "en-gb"
+  },
+
+  "padShortcutEnabled" : {
+    "altF9":     true, /* focus on the File Menu and/or editbar */
+    "altC":      true, /* focus on the Chat window */
+    "cmdShift2": true, /* shows a gritter popup showing a line author */
+    "delete":    true,
+    "return":    true,
+    "esc":       true, /* in mozilla versions 14-19 avoid reconnecting pad */
+    "cmdS":      true, /* save a revision */
+    "tab":       true, /* indent */
+    "cmdZ":      true, /* undo/redo */
+    "cmdY":      true, /* redo */
+    "cmdI":      true, /* italic */
+    "cmdB":      true, /* bold */
+    "cmdU":      true, /* underline */
+    "cmd5":      true, /* strike through */
+    "cmdShiftL": true, /* unordered list */
+    "cmdShiftN": true, /* ordered list */
+    "cmdShift1": true, /* ordered list */
+    "cmdShiftC": true, /* clear authorship */
+    "cmdH":      true, /* backspace */
+    "ctrlHome":  true, /* scroll to top of pad */
+    "pageUp":    true,
+    "pageDown":  true
+  },
+
+  "suppressErrorsInPadText": false,
+  "requireSession": false,
+  "editOnly": false,
+  "minify": true,
+  "maxAge": 21600, // 60 * 60 * 6 = 6 hours
+  "abiword": null,
+  "soffice": null,
+  "tidyHtml": null,
+  "allowUnknownFileEnds": true,
+  "requireAuthentication": false,
+  "requireAuthorization": false,
+  "trustProxy": false,
+  "cookie": {
+    "sameSite": "Lax"
+  },
+  "disableIPlogging": false,
+  "automaticReconnectionTimeout": 0,
+  "scrollWhenFocusLineIsOutOfViewport": {
+    "percentage": {
+      "editionAboveViewport": 0,
+      "editionBelowViewport": 0
+    },
+    "duration": 0,
+    "scrollWhenCaretIsInTheLastLineOfViewport": false,
+    "percentageToScrollWhenUserPressesArrowUp": 0
+  },
+
+
+  "socketTransportProtocols" : ["xhr-polling", "jsonp-polling", "htmlfile"],
+  "socketIo": {
+    "maxHttpBufferSize": 10000
+  },
+
+  "loadTest": false,
+  "dumpOnUncleanExit": false,
+  "importExportRateLimiting": {
+    // duration of the rate limit window (milliseconds)
+    "windowMs": 90000,
+    // maximum number of requests per IP to allow during the rate limit window
+    "max": 10
+  },
+  "importMaxFileSize": 52428800, // 50 * 1024 * 1024
+  "commitRateLimiting": {
+    // duration of the rate limit window (seconds)
+    "duration": 1,
+    // maximum number of changes per IP to allow during the rate limit window
+    "points": 10
+  },
+  "exposeVersion": false,
+  "loglevel": "INFO",
+  "customLocaleStrings": {},
+  "enableAdminUITests": false
+}