mu
change
commit e5b090c19fbd023eca18d392f6575e88658809bf
author Alpha Chen <alpha@kejadlen.dev>
date
parent 674bf386
diff --git a/.ansible-lint b/.ansible-lint
new file mode 100644
index 0000000..4a24ba6
--- /dev/null
+++ b/.ansible-lint
@@ -0,0 +1,2 @@
+exclude_paths:
+  - .terraform/
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3fa8c86
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.terraform
diff --git a/dev/ansible.cfg b/ansible.cfg
similarity index 100%
rename from dev/ansible.cfg
rename to ansible.cfg
diff --git a/dev/defaults.yml b/dev/defaults.yml
index 178e899..34cb7f3 100644
--- a/dev/defaults.yml
+++ b/dev/defaults.yml
@@ -11,239 +11,247 @@
     with_items:
 
     # NSGlobalDomain defaults
-    - # don't quit idle applications
-      domain: -g
-      key: NSDisableAutomaticTermination
-      type: bool
-      value: true
-    - # disable font smoothing
-      key: AppleFontSmoothing
-      type: int
-      value: 0
-    - # full keyboard access
-      key: AppleKeyboardUIMode
-      type: int
-      value: 3
-    - # show all extensions by default
-      key: AppleShowAllExtensions
-      type: bool
-      value: true
-    - # keyboard repeat rate
-      key: KeyRepeat
-      type: int
-      value: 2
-    - # delay before keyboard repeat
-      key: InitialKeyRepeat
-      type: int
-      value: 25
-    - # set sidebar item size to small
-      key: NSTableViewDefaultSizeMode
-      type: int
-      value: 1
-    - # disable resume
-      key: NSQuitAlwaysKeepsWindows
-      type: bool
-      value: false
-    - # add debug menu in web views
-      key: WebKitDeveloperExtras
-      type: bool
-      value: true
-    - # tap to click
-      key: com.apple.mouse.tapBehavior
-      type: bool
-      value: true
-    - # only show scrollbars when scrolling
-      key: AppleShowScrollBars
-      type: string
-      value: WhenScrolling
-
-    # Safari
-    - # enable Debug menu in Safari
-      domain: com.apple.Safari
-      key: IncludeInternalDebugMenu
-      type: bool
-      value: true
-    - # disable Java
-      domain: com.apple.Safari
-      key: com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaEnabled
-      type: bool
-      value: false
-    - # disable Java
-      domain: com.apple.Safari
-      key: com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaEnabledForLocalFiles
-      type: bool
-      value: false
-
-    - # disable dashboard
-      domain: com.apple.dashboard
-      key: mcx-disabled
-      type: bool
-      value: true
-
-    - # don't write .DS_Store to network volumes
-      domain: com.apple.desktopservices
-      key: DSDontWriteNetworkStores
-      type: bool
-      value: true
-
-    # Dock defaults
-    - # automatically hide and show the dock
-      domain: com.apple.dock
-      key: autohide
-      type: bool
-      value: true
-    - # minimize windows using the scale effect
-      domain: com.apple.dock
-      key: mineffect
-      type: string
-      value: scale
-    - # don't rearrange spaces
-      domain: com.apple.dock
-      key: mru-spaces
-      type: bool
-      value: false
-    - domain: com.apple.dock
-      key: orientation
-      type: string
-      value: left
-    - # set the bottom left hot corner to sleep the display
-      domain: com.apple.dock
-      key: wvous-bl-corner
-      type: int
-      value: 10
-    - # set the icon size to 36 pixels
-      domain: com.apple.dock
-      key: tilesize
-      type: int
-      value: 36
-    - # no dock delay
-      domain: com.apple.dock
-      key: autohide-delay
-      type: float
-      value: 0
-
-    # Trackpad settings
-    - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
-      key: Clicking
-      type: int
-      value: 1
-    - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
-      key: TrackpadFourFingerVertSwipeGesture
-      type: int
-      value: 0
-    - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
-      key: TrackpadThreeFingerDrag
-      type: bool
-      value: true
-    - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
-      key: TrackpadThreeFingerHorizSwipeGesture
-      type: int
-      value: 0
-    - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
-      key: TrackpadThreeFingerVertSwipeGesture
-      type: int
-      value: 0
-
-    # Finder defaults
-    - # don't ask when changing file extension
-      domain: com.apple.finder
-      key: FXEnableExtensionChangeWarning
-      type: bool
-      value: false
-    - # default to list view
-      domain: com.apple.finder
-      key: FXPreferredViewStyle
-      type: string
-      value: Nlsv
-    - # enable text selection in QuickLook
-      domain: com.apple.finder
-      key: QLEnableTextSelection
-      type: bool
-      value: true
-    - # show full path in Finder
-      domain: com.apple.finder
-      key: _FXShowPosixPathInTitle
-      type: bool
-      value: true
-    - # remove the proxy icon hover delay
-      domain: com.apple.Finder
-      key: NSToolbarTitleViewRolloverDelay
-      type: float
-      value: 0
-    - # show the proxy icon and older titlebar
-      # https://twitter.com/chucker/status/1395843084383043584
-      domain: com.apple.Finder
-      key: NSWindowSupportsAutomaticInlineTitle
-      type: bool
-      value: false
-
-    - # set date format in menubar
-      domain: com.apple.menuextra.clock
-      key: DateFormat
-      type: string
-      value: h:mm
-
-    - # no window shadows when capturing windows
-      domain: com.apple.screencapture
-      key: disable-shadow
-      type: bool
-      value: true
-
-    - domain: com.apple.screencapture
-      key: location
-      type: string
-      value: "{{ ansible_env.HOME }}/Downloads"
-
-    - domain: com.apple.screensaver
-      key: askForPassword
-      type: int
-      value: 1
-
-    - domain: com.apple.Terminal
-      key: ShowLineMarks
-      type: bool
-      value: false
-
-    # Other applications
-    - domain: com.google.Chrome
-      key: AppleEnableSwipeNavigateWithScrolls
-      type: bool
-      value: false
-
-    - domain: org.vim.MacVim
-      key: MMLastWindowClosedBehavior
-      type: int
-      value: 2
-
-    - domain: org.vim.MacVim
-      key: MMUntitledWindow
-      type: int
-      value: 1
-
-    - domain: org.vim.MacVim
-      key: SUCheckAtStartup
-      type: int
-      value: 1
-
-    - domain: org.vim.MacVim
-      key: SUEnableAutomaticChecks
-      type: int
-      value: 1
-
-    - domain: com.freron.MailMate
-      key: MmAllowedImageURLRegexp
-      type: string
-      value: https://((i|images|d)\.gr-assets\.com|www\.goodreads\.com|massdrop-s3\.imgix\.net|.*\.cloudfront\.net|s3\.amazonaws\.com|files\.convertkitcdn\.com/assets/pictures)/.*
-
-    - domain: com.freron.MailMate
-      key: MmSendMessageDelayEnabled
-      type: bool
-      value: true
-
-    - domain: com.freron.MailMate
-      key: MmSendMessageDelay
-      type: int
-      value: 60
+      - # don't quit idle applications
+        domain: -g
+        key: NSDisableAutomaticTermination
+        type: bool
+        value: true
+      - # disable font smoothing
+        key: AppleFontSmoothing
+        type: int
+        value: 0
+      - # full keyboard access
+        key: AppleKeyboardUIMode
+        type: int
+        value: 3
+      - # show all extensions by default
+        key: AppleShowAllExtensions
+        type: bool
+        value: true
+      - # keyboard repeat rate
+        key: KeyRepeat
+        type: int
+        value: 2
+      - # delay before keyboard repeat
+        key: InitialKeyRepeat
+        type: int
+        value: 25
+      - # set sidebar item size to small
+        key: NSTableViewDefaultSizeMode
+        type: int
+        value: 1
+      - # disable resume
+        key: NSQuitAlwaysKeepsWindows
+        type: bool
+        value: false
+      - # add debug menu in web views
+        key: WebKitDeveloperExtras
+        type: bool
+        value: true
+      - # tap to click
+        key: com.apple.mouse.tapBehavior
+        type: bool
+        value: true
+      - # only show scrollbars when scrolling
+        key: AppleShowScrollBars
+        type: string
+        value: WhenScrolling
+
+      # Safari
+      - # enable Debug menu in Safari
+        domain: com.apple.Safari
+        key: IncludeInternalDebugMenu
+        type: bool
+        value: true
+      - # disable Java
+        domain: com.apple.Safari
+        key: com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaEnabled
+        type: bool
+        value: false
+      - # disable Java
+        domain: com.apple.Safari
+        key: com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaEnabledForLocalFiles
+        type: bool
+        value: false
+
+      - # disable dashboard
+        domain: com.apple.dashboard
+        key: mcx-disabled
+        type: bool
+        value: true
+
+      - # don't write .DS_Store to network volumes
+        domain: com.apple.desktopservices
+        key: DSDontWriteNetworkStores
+        type: bool
+        value: true
+
+      # Dock defaults
+      - # automatically hide and show the dock
+        domain: com.apple.dock
+        key: autohide
+        type: bool
+        value: true
+      - # minimize windows using the scale effect
+        domain: com.apple.dock
+        key: mineffect
+        type: string
+        value: scale
+      - # don't rearrange spaces
+        domain: com.apple.dock
+        key: mru-spaces
+        type: bool
+        value: false
+      - domain: com.apple.dock
+        key: orientation
+        type: string
+        value: left
+      - # set the bottom left hot corner to sleep the display
+        domain: com.apple.dock
+        key: wvous-bl-corner
+        type: int
+        value: 10
+      - # set the icon size to 36 pixels
+        domain: com.apple.dock
+        key: tilesize
+        type: int
+        value: 36
+      - # no dock delay
+        domain: com.apple.dock
+        key: autohide-delay
+        type: float
+        value: 0
+
+      # Trackpad settings
+      - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
+        key: Clicking
+        type: int
+        value: 1
+      - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
+        key: TrackpadFourFingerVertSwipeGesture
+        type: int
+        value: 0
+      - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
+        key: TrackpadThreeFingerDrag
+        type: bool
+        value: true
+      - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
+        key: TrackpadThreeFingerHorizSwipeGesture
+        type: int
+        value: 0
+      - domain: com.apple.driver.AppleBluetoothMultitouch.trackpad
+        key: TrackpadThreeFingerVertSwipeGesture
+        type: int
+        value: 0
+
+      # Finder defaults
+      - # don't ask when changing file extension
+        domain: com.apple.finder
+        key: FXEnableExtensionChangeWarning
+        type: bool
+        value: false
+      - # default to list view
+        domain: com.apple.finder
+        key: FXPreferredViewStyle
+        type: string
+        value: Nlsv
+      - # enable text selection in QuickLook
+        domain: com.apple.finder
+        key: QLEnableTextSelection
+        type: bool
+        value: true
+      - # show full path in Finder
+        domain: com.apple.finder
+        key: _FXShowPosixPathInTitle
+        type: bool
+        value: true
+      - # remove the proxy icon hover delay
+        domain: com.apple.Finder
+        key: NSToolbarTitleViewRolloverDelay
+        type: float
+        value: 0
+      - # show the proxy icon and older titlebar
+        # https://twitter.com/chucker/status/1395843084383043584
+        domain: com.apple.Finder
+        key: NSWindowSupportsAutomaticInlineTitle
+        type: bool
+        value: false
+
+      - # set date format in menubar
+        domain: com.apple.menuextra.clock
+        key: DateFormat
+        type: string
+        value: h:mm
+
+      - # no window shadows when capturing windows
+        domain: com.apple.screencapture
+        key: disable-shadow
+        type: bool
+        value: true
+
+      - domain: com.apple.screencapture
+        key: location
+        type: string
+        value: "{{ ansible_env.HOME }}/Downloads"
+
+      - domain: com.apple.screensaver
+        key: askForPassword
+        type: int
+        value: 1
+
+      - domain: com.apple.Terminal
+        key: ShowLineMarks
+        type: bool
+        value: false
+
+      # Other applications
+      - domain: com.google.Chrome
+        key: AppleEnableSwipeNavigateWithScrolls
+        type: bool
+        value: false
+
+      - domain: org.vim.MacVim
+        key: MMLastWindowClosedBehavior
+        type: int
+        value: 2
+
+      - domain: org.vim.MacVim
+        key: MMUntitledWindow
+        type: int
+        value: 1
+
+      - domain: org.vim.MacVim
+        key: SUCheckAtStartup
+        type: int
+        value: 1
+
+      - domain: org.vim.MacVim
+        key: SUEnableAutomaticChecks
+        type: int
+        value: 1
+
+      - domain: com.freron.MailMate
+        key: MmAllowedImageURLRegexp
+        type: string
+        value: "{{ regexps | join('|') }}"
+        vars:
+          regexps:
+            - https://((i|images|d)\.gr-assets\.com
+            - www\.goodreads\.com
+            - massdrop-s3\.imgix\.net
+            - .*\.cloudfront\.net
+            - s3\.amazonaws\.com
+            - files\.convertkitcdn\.com/assets/pictures)/.*
+
+      - domain: com.freron.MailMate
+        key: MmSendMessageDelayEnabled
+        type: bool
+        value: true
+
+      - domain: com.freron.MailMate
+        key: MmSendMessageDelay
+        type: int
+        value: 60
 
   handlers:
 
diff --git a/dev/homebrew.yml b/dev/homebrew.yml
index a3a41eb..9aa79f4 100644
--- a/dev/homebrew.yml
+++ b/dev/homebrew.yml
@@ -1,49 +1,62 @@
-- hosts: all
+- name: Homebrew
+  hosts: all
   tasks:
 
-  - community.general.homebrew:
+  - name: Install Homebrew formulae
+    community.general.homebrew:
       name: "{{ item }}"
     loop:
-    - chruby
-    - difftastic
-    - direnv
-    - efm-langserver
-    - entr
-    - exa
-    - fasd
-    - fd
-    - fzf
-    - git
-    - git-lfs
-    - jq
-    - luarocks
-    - neovim
-    - ripgrep
-    - ruby-install
-    - shellcheck
-    - svn # required for source code pro
-    - tmux
-    - tree
-    - zsh
+      - chruby
+      - colima
+      - difftastic
+      - direnv
+      - docker
+      - docker-compose
+      - efm-langserver
+      - entr
+      - exa
+      - fasd
+      - fd
+      - fzf
+      - git
+      - git-lfs
+      - jq
+      - luarocks
+      - neovim
+      - ripgrep
+      - ruby-install
+      - shellcheck
+      # - svn # required for source code pro?
+      - tmux
+      - tree
+      - zsh
 
-    - fabianishere/personal/pam_reattach
+      - fabianishere/personal/pam_reattach
 
-  - community.general.homebrew_cask:
+  - name: Install Homebrew casks
+    community.general.homebrew_cask:
       name: "{{ item }}"
     loop:
-    - alfred
-    - bartender
-    - dash
-    - fantastical
-    - firefox
-    - google-chrome
-    - hammerspoon
-    - mailmate
-    - obsidian
-    - slack
-    - topnotch
-    - zoom
+      - alfred
+      - bartender
+      - dash
+      - fantastical
+      - firefox-developer-edition
+      - google-chrome
+      - hammerspoon
+      - mailmate
+      - obsidian
+      - slack
+      - topnotch
+      - zoom
 
-    # - homebrew/cask-fonts/font-source-code-pro
-    - homebrew/cask-fonts/font-sauce-code-pro-nerd-font
-    - homebrew/cask-versions/firefox-developer-edition
+      # - homebrew/cask-fonts/font-source-code-pro
+      - homebrew/cask-fonts/font-sauce-code-pro-nerd-font
+      - homebrew/cask-versions/firefox-developer-edition
+
+  - name: Heed docker-compose caveats
+    block:
+      - name: Create Docker CLI plugins config dir
+        ansible.buitin.file:
+          dest: ~/.docker/cli-plugins
+          state: directory
diff --git a/dev/macos.yml b/dev/macos.yml
index 3bb27c4..1980ca9 100644
--- a/dev/macos.yml
+++ b/dev/macos.yml
@@ -20,12 +20,11 @@
       dest: ~/Library/Dictionaries/websters-1913.dictionary
 
   - name: Enable Touch ID for sudo
-    block:
-    - lineinfile:
-        path: /etc/pam.d/sudo
-        insertafter: '^auth\s+sufficient'
-        regexp: '^auth\s+sufficient\s+pam_tid.so$'
-        line: "auth\tsufficient\tpam_tid.so"
+    lineinfile:
+      path: /etc/pam.d/sudo
+      insertafter: '^auth\s+sufficient'
+      regexp: '^auth\s+sufficient\s+pam_tid.so$'
+      line: "auth\tsufficient\tpam_tid.so"
 
     # tmux
     - shell: brew --prefix
@@ -35,4 +34,4 @@
         insertbefore: '^auth\tsufficient\tpam_tid.so'
         regexp: '^auth\s+optional\s+.*pam_reattach.so$'
         line: "auth\toptional\t{{ brew_prefix.stdout | trim }}/lib/pam/pam_reattach.so"
-    become: yes
+    become: true
diff --git a/dev/main.yml b/dev/main.yml
index e048e3d..fda7e99 100644
--- a/dev/main.yml
+++ b/dev/main.yml
@@ -33,5 +33,4 @@
 - hosts: all
   tasks:
 
-  - ansible.builtin.command: "luarocks install fennel"
-
+    - ansible.builtin.command: "luarocks install fennel"
diff --git a/dev/hosts.yml b/hosts.yml
similarity index 57%
rename from dev/hosts.yml
rename to hosts.yml
index fe1528d..b59cb75 100644
--- a/dev/hosts.yml
+++ b/hosts.yml
@@ -3,3 +3,6 @@ all:
     localhost:
       ansible_connection: local
       ansible_python_interpreter: "{{ansible_playbook_python}}"
+    ramble-hard:
+      ansible_user: root
+      ansible_python_interpreter: /usr/bin/python3
diff --git a/ramble-hard/main.yml b/ramble-hard/main.yml
new file mode 100644
index 0000000..11496a7
--- /dev/null
+++ b/ramble-hard/main.yml
@@ -0,0 +1,3 @@
+- hosts: ramble-hard
+  tasks:
+
diff --git a/ramble-hard/nginx/main.yml b/ramble-hard/nginx/main.yml
new file mode 100644
index 0000000..dc1cbcf
--- /dev/null
+++ b/ramble-hard/nginx/main.yml
@@ -0,0 +1,65 @@
+---
+
+- name: Set up Lets Encrypt
+  hosts: ramble-hard
+  vars_files:
+    - ../vars.private
+  tasks:
+
+  - apt:
+      update_cache: yes
+
+  - package:
+      name:
+      - certbot
+      - nginx
+
+  - service:
+      name: nginx
+      state: stopped
+
+  - command: >
+      certbot certonly --standalone --preferred-challenges http
+      -n --agree-tos -m {{ lets_encrypt.email }}
+      -d {{ tld }}
+    vars:
+      tld: "{{ item.value['subdomain'] | default(item.key) }}.{{ domain }}"
+    loop: "{{ apps | dict2items }}"
+
+  - service:
+      name: nginx
+      state: started
+
+  - template:
+      src: renew-certs
+      dest: /etc/cron.daily/renew-certs
+      mode: +x
+
+# - name: Set up nginx proxies
+#   hosts: ramble-hard
+#   vars_files:
+#     - ../vars.private
+#   tasks:
+
+#   - template:
+#       src: nginx.conf
+#       dest: /etc/nginx/sites-available/{{ item.key }}.conf
+#     vars:
+#       server_name: "{{ item.value['subdomain'] | default(item.key) }}.{{ domain }}"
+#       port: "{{ item.value['port'] }}"
+#     loop: "{{ apps | dict2items }}"
+#     notify: Restart nginx
+
+#   - file:
+#       src: /etc/nginx/sites-available/{{ item.key }}.conf
+#       dest: /etc/nginx/sites-enabled/{{ item.key }}.conf
+#       state: link
+#     loop: "{{ apps | dict2items }}"
+#     notify: Restart nginx
+
+  # handlers:
+
+  #   - name: Restart nginx
+  #     service:
+  #       name: nginx
+  #       state: restarted
diff --git a/ramble-hard/nginx/nginx.conf b/ramble-hard/nginx/nginx.conf
new file mode 100644
index 0000000..8ef2227
--- /dev/null
+++ b/ramble-hard/nginx/nginx.conf
@@ -0,0 +1,37 @@
+server {
+    server_name {{ server_name }};
+
+    listen 80;
+    listen [::]:80;
+
+    location / {
+      return https://$server_name$request_uri;
+    }
+}
+
+
+server {
+    server_name {{ server_name }};
+
+    listen 443 ssl http2;
+    listen [::]:443 ssl http2;
+
+    ssl_trusted_certificate   /etc/letsencrypt/live/{{ server_name }}/chain.pem;
+    ssl_certificate           /etc/letsencrypt/live/{{ server_name }}/fullchain.pem;
+    ssl_certificate_key       /etc/letsencrypt/live/{{ server_name }}/privkey.pem;
+
+    ssl_stapling on;
+    ssl_stapling_verify on;
+
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+    proxy_set_header Host $http_host;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+    client_max_body_size 10m;
+
+    location / {
+        proxy_pass http://127.0.0.1:{{ port }};
+    }
+}
diff --git a/ramble-hard/nginx/renew-certs b/ramble-hard/nginx/renew-certs
new file mode 100644
index 0000000..88192fc
--- /dev/null
+++ b/ramble-hard/nginx/renew-certs
@@ -0,0 +1,2 @@
+#!/bin/sh
+certbot renew -w /var/lib/letsencrypt/ --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"
diff --git a/ramble-hard/pleroma/01.yml b/ramble-hard/pleroma/01.yml
new file mode 100644
index 0000000..fc720db
--- /dev/null
+++ b/ramble-hard/pleroma/01.yml
@@ -0,0 +1,118 @@
+# https://docs.pleroma.social/backend/installation/otp_en/
+---
+- hosts: ramble-hard
+  become: true
+  tasks:
+
+    # arch="$(uname -m)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;fi;echo "$arch$libc_postfix" # noqa yaml[line-length]
+    - shell: |
+        arch="$(uname -m)"
+        if [ "$arch" = "x86_64" ]; then
+          arch="amd64";
+        elif [ "$arch" = "armv7l" ]; then
+          arch="arm";
+        elif [ "$arch" = "aarch64" ]; then
+          arch="arm64";
+        else
+          echo "Unsupported arch: $arch">&2;
+        fi;
+        if getconf GNU_LIBC_VERSION>/dev/null; then
+          libc_postfix="";
+        elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ]; then
+          libc_postfix="-musl";
+        elif [ "$(find /lib/libc.musl*|wc -l)" ]; then
+          libc_postfix="-musl";
+        else
+          echo "Unsupported libc">&2;
+        fi;
+        echo "$arch$libc_postfix"
+      register: arch_result
+    - set_fact:
+        pleroma_flavour: "{{ arch_result.stdout | trim }}"
+
+    - apt:
+        update_cache: true
+
+    # apt install curl unzip libncurses5 postgresql postgresql-contrib nginx certbot libmagic-dev
+    # apt install imagemagick ffmpeg libimage-exiftool-perl
+    # apt install postgresql-11-rum
+    - package:
+        name:
+          - curl
+          - unzip
+          - libncurses5
+          - postgresql
+          - postgresql-contrib
+          - nginx
+          - certbot
+          - libmagic-dev
+          - imagemagick
+          - ffmpeg
+          - libimage-exiftool-perl
+          # - postgresql-13-rum
+      notify:
+        - Restart postgres
+
+    # Create a Pleroma user
+    # adduser --system --shell  /bin/false --home /opt/pleroma pleroma
+    - user:
+        name: pleroma
+        home: /opt/pleroma
+        shell: /bin/false
+        system: true
+
+    # Clone the release build into a temporary directory and unpack it
+    # su pleroma -s $SHELL -lc "
+    # curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=$FLAVOUR' -o /tmp/pleroma.zip
+    # unzip /tmp/pleroma.zip -d /tmp/
+    # "
+    - get_url:
+        url: https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job={{ pleroma_flavour }}
+        dest: /tmp/pleroma.zip
+    - command: unzip /tmp/pleroma.zip -d /tmp/
+
+    # Move the release to the home directory and delete temporary files
+    # su pleroma -s $SHELL -lc "
+    # mv /tmp/release/* /opt/pleroma
+    # rmdir /tmp/release
+    # rm /tmp/pleroma.zip
+    # "
+    - copy:
+        src: /tmp/release/
+        dest: /opt/pleroma/
+        remote_src: true
+        owner: pleroma
+    - file:
+        path: "{{ item }}"
+        state: absent
+      loop:
+        - /tmp/release
+        - /tmp/pleroma.zip
+
+    # Create uploads directory and set proper permissions (skip if planning to use a remote uploader)
+    # Note: It does not have to be `/var/lib/pleroma/uploads`, the config generator will ask about the upload directory later
+    # mkdir -p /var/lib/pleroma/uploads
+    # chown -R pleroma /var/lib/pleroma
+
+    # Create custom public files directory (custom emojis, frontend bundle overrides, robots.txt, etc.)
+    # Note: It does not have to be `/var/lib/pleroma/static`, the config generator will ask about the custom public files directory later
+    # mkdir -p /var/lib/pleroma/static
+    # chown -R pleroma /var/lib/pleroma
+
+    # Create a config directory
+    # mkdir -p /etc/pleroma
+    # chown -R pleroma /etc/pleroma
+    - file:
+        path: "{{ item }}"
+        state: directory
+        owner: pleroma
+      loop:
+        - /var/lib/pleroma/uploads
+        - /var/lib/pleroma/static
+        - /etc/pleroma
+
+  handlers:
+    - name: Restart postgres
+      service:
+        name: postgresql
+        state: restarted
diff --git a/ramble-hard/pleroma/02.yml b/ramble-hard/pleroma/02.yml
new file mode 100644
index 0000000..c028715
--- /dev/null
+++ b/ramble-hard/pleroma/02.yml
@@ -0,0 +1,30 @@
+# https://docs.pleroma.social/backend/installation/otp_en/
+---
+- hosts: ramble-hard
+  become: true
+  tasks:
+
+    # Create the postgres database
+    # su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
+    - command: psql -f /tmp/setup_db.psql
+      become_user: postgres
+
+    # Create the database schema
+    # su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
+    - command: ./bin/pleroma_ctl migrate
+      args:
+        chdir: /opt/pleroma
+      become_user: pleroma
+
+    # If you have installed RUM indexes uncomment and run
+    # su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
+    # - command: ./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/
+    #   args:
+    #     chdir: /opt/pleroma
+    #   become_user: pleroma
+
+  handlers:
+    - name: Restart postgres
+      service:
+        name: postgresql
+        state: restarted
diff --git a/ramble-hard/pleroma/03.yml b/ramble-hard/pleroma/03.yml
new file mode 100644
index 0000000..b0b75e8
--- /dev/null
+++ b/ramble-hard/pleroma/03.yml
@@ -0,0 +1,89 @@
+# https://docs.pleroma.social/backend/installation/otp_en/
+---
+- hosts: ramble-hard
+  become: true
+  vars_files:
+    - ../vars.private
+  tasks:
+
+    - package:
+        name:
+        - certbot
+        - nginx
+
+    - service:
+        name: nginx
+        state: stopped
+
+    # certbot certonly --standalone --preferred-challenges http -d yourinstance.tld
+    - command: >
+        certbot certonly --standalone --preferred-challenges http
+        -n --agree-tos -m {{ lets_encrypt.email }}
+        -d {{ pleroma.tld }}
+
+    - service:
+        name: nginx
+        state: started
+
+    # cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.conf
+    # ln -s /etc/nginx/sites-available/pleroma.conf /etc/nginx/sites-enabled/pleroma.conf
+    - copy:
+        src: /opt/pleroma/installation/pleroma.nginx
+        dest: /etc/nginx/sites-available/pleroma.conf
+        remote_src: true
+      notify: Restart nginx
+    - file:
+        src: /etc/nginx/sites-available/pleroma.conf
+        dest: /etc/nginx/sites-enabled/pleroma.conf
+        state: link
+      notify: Restart nginx
+
+    - replace:
+        path: /etc/nginx/sites-available/pleroma.conf
+        regexp: 'example\.tld'
+        replace: "{{ pleroma.tld }}"
+      notify: Restart nginx
+
+    # Copy the service into a proper directory
+    # cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service
+    - copy:
+        src: /opt/pleroma/installation/pleroma.service
+        dest: /etc/systemd/system/pleroma.service
+        remote_src: true
+      # Start pleroma and enable it on boot
+      # systemctl start pleroma
+      # systemctl enable pleroma
+      notify: Restart pleroma
+
+    # Create the directory for webroot challenges
+    # mkdir -p /var/lib/letsencrypt
+    - file:
+        path: /var/lib/letsencrypt
+        state: directory
+
+    # Add it to the daily cron
+    # echo '#!/bin/sh
+    # certbot renew --cert-name yourinstance.tld --webroot -w /var/lib/letsencrypt/ --post-hook "systemctl reload nginx"
+    # ' > /etc/cron.daily/renew-pleroma-cert
+    # chmod +x /etc/cron.daily/renew-pleroma-cert
+    - ansible.builtin.copy:
+        content: |
+          \#!/bin/sh
+          certbot renew --cert-name {{ pleroma.tld }} --webroot -w /var/lib/letsencrypt/ --post-hook "systemctl reload nginx"
+        dest: /etc/cron.daily/renew-pleroma-cert
+        mode: +x
+    # - template:
+    #     src: renew-pleroma-cert
+    #     dest: /etc/cron.daily/renew-pleroma-cert
+    #     mode: +x
+
+  handlers:
+    - name: Restart nginx
+      service:
+        name: nginx
+        state: restarted
+    - name: Restart pleroma
+      service:
+        name: pleroma
+        enabled: true
+        state: restarted
diff --git a/ramble-hard/pleroma/README.md b/ramble-hard/pleroma/README.md
new file mode 100644
index 0000000..c598010
--- /dev/null
+++ b/ramble-hard/pleroma/README.md
@@ -0,0 +1,23 @@
+```sh
+ansible-playbook playbooks/pleroma/01.yml
+
+su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql"
+
+ansible-playbook playbooks/pleroma/02.yml
+
+# Start the instance to verify that everything is working as expected
+su pleroma -s $SHELL -lc "./bin/pleroma daemon"
+
+# Wait for about 20 seconds and query the instance endpoint, if it shows your
+# uri, name and email correctly, you are configured correctly
+sleep 20 && curl http://localhost:4000/api/v1/instance
+
+# Stop the instance
+su pleroma -s $SHELL -lc "./bin/pleroma stop"
+
+ansible-playbook -l pleroma playbooks/pleroma/03.yml
+
+cd /opt/pleroma
+su pleroma -s $SHELL -lc "./bin/pleroma_ctl user new joeuser joeuser@sld.tld --admin"
+su pleroma -s $SHELL -lc "./bin/pleroma_ctl config migrate_to_db"
+```