From 4e50fdce0923171c4edd13a803c720065a4d2383 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 14 Jul 2024 23:36:42 +0100 Subject: [PATCH 01/30] add pricing page --- main/templates/main/guides_pricing.html | 71 +++++++++++++++++++++++++ main/urls.py | 1 + main/views/general.py | 7 +++ 3 files changed, 79 insertions(+) create mode 100644 main/templates/main/guides_pricing.html diff --git a/main/templates/main/guides_pricing.html b/main/templates/main/guides_pricing.html new file mode 100644 index 0000000..328c795 --- /dev/null +++ b/main/templates/main/guides_pricing.html @@ -0,0 +1,71 @@ +{% extends 'main/layout.html' %} + +{% load static %} + +{% block title %}Pricing — Mataroa{% endblock %} + +{% block content %} +
+

Pricing

+

+ In the interest of business transparency, in this page we explain the rationale + for our pricing. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Apple PlanWatermelon PlanKiwi Plan
Price$1 one-off$19/year$49/year
Core functionality
Email subcribers1001,00010,000
Image hosting100MB250MB1000MB
Custom domain
Auto-exports
+
+ +
+ +{% include 'partials/footer.html' %} + +{% endblock %} diff --git a/main/urls.py b/main/urls.py index f572ad4..28645e5 100644 --- a/main/urls.py +++ b/main/urls.py @@ -14,6 +14,7 @@ path("modus/operandi/", general.operandi, name="operandi"), path("modus/transparency/", general.transparency, name="transparency"), path("modus/privacy/", general.privacy_redir, name="privacy_redir"), + path("guides/pricing/", general.guides_pricing, name="guides_pricing"), path("guides/markdown/", general.guides_markdown, name="guides_markdown"), path("guides/images/", general.guides_images, name="guides_images"), path( diff --git a/main/views/general.py b/main/views/general.py index 1dcabc5..1813229 100644 --- a/main/views/general.py +++ b/main/views/general.py @@ -1277,3 +1277,10 @@ def guides_customdomain(request): request, "main/guides_customdomain.html", ) + + +def guides_pricing(request): + return render( + request, + "main/guides_pricing.html", + ) From 1d08e67e51fb150884235bb0e9ef13d83d8fb423 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:21:48 +0000 Subject: [PATCH 02/30] replace uwsgi with gunicorn --- requirements.in | 2 +- requirements.txt | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/requirements.in b/requirements.in index ce511db..9a92a0d 100644 --- a/requirements.in +++ b/requirements.in @@ -1,6 +1,6 @@ django psycopg2-binary -uwsgi +gunicorn markdown pygments bleach[css] diff --git a/requirements.txt b/requirements.txt index 741d3eb..5c0e6a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.12 # by the following command: # -# pip-compile requirements.in +# pip-compile # asgiref==3.7.2 # via django @@ -14,10 +14,14 @@ charset-normalizer==3.3.2 # via requests django==5.0.2 # via -r requirements.in +gunicorn==21.2.0 + # via -r requirements.in idna==3.6 # via requests markdown==3.5.2 # via -r requirements.in +packaging==24.0 + # via gunicorn psycopg2-binary==2.9.9 # via -r requirements.in pygments==2.17.2 @@ -36,8 +40,6 @@ typing-extensions==4.9.0 # via stripe urllib3==2.2.0 # via requests -uwsgi==2.0.24 - # via -r requirements.in webencodings==0.5.1 # via # bleach From ea2ba85002e978ad6ff07085731de54b9514690f Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:22:12 +0000 Subject: [PATCH 03/30] rename requirements dev --- requirements_dev.txt => requirements.dev.txt | 1 + 1 file changed, 1 insertion(+) rename requirements_dev.txt => requirements.dev.txt (83%) diff --git a/requirements_dev.txt b/requirements.dev.txt similarity index 83% rename from requirements_dev.txt rename to requirements.dev.txt index a49a037..9a99824 100644 --- a/requirements_dev.txt +++ b/requirements.dev.txt @@ -3,3 +3,4 @@ isort==5.10.1 flake8==6.1.0 black==23.11.0 coverage==7.3.2 +ansible==9.4.0 From 713b04c4c619248048721265527dcca053569520 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:22:51 +0000 Subject: [PATCH 04/30] remove uwsgi from gitignore --- .gitignore | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.gitignore b/.gitignore index a53424d..b700bf2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,11 +13,6 @@ postgres-data/ .coverage htmlcov/ -# uwsgi -uwsgi.ini -uwsgi-log.txt -mataroa.pid - # docker docker-postgres-data/ docker-compose.override.yml From 9f019a04ea02f18beccdb5b70d7a2e5a159032c4 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:24:03 +0000 Subject: [PATCH 05/30] add ansible configurations --- ansible/.envrc.example | 26 +++++++++ ansible/ansible.cfg | 3 ++ ansible/inventory.yaml | 5 ++ ansible/mataroa.service.j2 | 20 +++++++ ansible/playbook.yaml | 108 +++++++++++++++++++++++++++++++++++++ ansible/vars.yaml | 5 ++ 6 files changed, 167 insertions(+) create mode 100644 ansible/.envrc.example create mode 100644 ansible/ansible.cfg create mode 100644 ansible/inventory.yaml create mode 100644 ansible/mataroa.service.j2 create mode 100644 ansible/playbook.yaml create mode 100644 ansible/vars.yaml diff --git a/ansible/.envrc.example b/ansible/.envrc.example new file mode 100644 index 0000000..c306d83 --- /dev/null +++ b/ansible/.envrc.example @@ -0,0 +1,26 @@ +# inventory.yaml + +# Server IP and user with ssh access +export ANSIBLE_HOST= +export ANSIBLE_USER=root + + +# vars.yaml + +# Show exceptions and tracebacks on errors +export DEBUG=1 + +# Database connection +export DATABASE_URL=postgres://mataroa:@localhost:5432/mataroa + +# Session cookies secret +export SECRET_KEY=some-secret-key + +# SMTP credentials +export EMAIL_HOST_USER= +export EMAIL_HOST_PASSWORD= + +# Stripe payments details +export STRIPE_API_KEY= +export STRIPE_PUBLIC_KEY= +export STRIPE_PRICE_ID= diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000..f9e6eec --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +inventory = inventory.yaml +pipelining = True diff --git a/ansible/inventory.yaml b/ansible/inventory.yaml new file mode 100644 index 0000000..5c10106 --- /dev/null +++ b/ansible/inventory.yaml @@ -0,0 +1,5 @@ +virtualmachines: + hosts: + huron: + ansible_host: "{{ lookup('env', 'ANSIBLE_HOST') }}" + ansible_user: "{{ lookup('env', 'ANSIBLE_USER') }}" diff --git a/ansible/mataroa.service.j2 b/ansible/mataroa.service.j2 new file mode 100644 index 0000000..c85d50a --- /dev/null +++ b/ansible/mataroa.service.j2 @@ -0,0 +1,20 @@ +[Unit] +Description=mataroa +After=network.target + +[Service] +Type=simple +User=deploy +Group=www-data +WorkingDirectory=/var/www/mataroa +ExecStart=/var/www/mataroa/.venv/bin/gunicorn -b 127.0.0.1:5001 -w 4 mataroa.wsgi +ExecReload=/bin/kill -HUP $MAINPID +Environment="DEBUG={{ debug }}" +Environment="SECRET_KEY={{ secret_key }}" +Environment="EMAIL_HOST_USER={{ email_host_user }}" +Environment="EMAIL_HOST_PASSWORD={{ email_host_password }}" +TimeoutSec=15 +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/ansible/playbook.yaml b/ansible/playbook.yaml new file mode 100644 index 0000000..380b1ba --- /dev/null +++ b/ansible/playbook.yaml @@ -0,0 +1,108 @@ +--- +- hosts: virtualmachines + vars_files: + - vars.yaml + become: yes + tasks: + # smoke test and essential dependencies + - name: ping + ansible.builtin.ping: + - name: essentials + ansible.builtin.apt: + update_cache: yes + name: + - vim + - git + - python3.11 + - python3.11-venv + - python3.11-dev + state: present + + # deploy user and directory + - name: www directory + ansible.builtin.file: + path: /var/www + state: directory + mode: '0755' + - name: create user + ansible.builtin.user: + name: deploy + password: "" + shell: /bin/bash + groups: + - sudo + - www-data + append: yes + createhome: yes + skeleton: '/etc/skel' + generate_ssh_key: yes + ssh_key_type: 'ed25519' + - name: www ownership + ansible.builtin.file: + path: /var/www + owner: deploy + group: www-data + recurse: yes + + # repository + - name: clone + ansible.builtin.git: + repo: https://github.com/mataroa-blog/mataroa + dest: /var/www/mataroa + version: ansible + accept_hostkey: true + become_user: deploy + - name: dependencies + ansible.builtin.pip: + virtualenv_command: python3 -m venv .venv + virtualenv: /var/www/mataroa/.venv + requirements: /var/www/mataroa/requirements.txt + become_user: deploy + + # systemd + - name: systemd template + ansible.builtin.template: + src: mataroa.service.j2 + dest: /etc/systemd/system/mataroa.service + owner: root + group: root + mode: '0644' + - name: systemd reload + ansible.builtin.systemd: + daemon_reload: true + - name: systemd enable + ansible.builtin.systemd: + name: mataroa + enabled: yes + - name: systemd start + ansible.builtin.systemd: + name: mataroa + state: restarted + + # deployment specific + - name: collectstatic + ansible.builtin.shell: + cmd: | + source .venv/bin/activate + python3 manage.py collectstatic --no-input + chdir: /var/www/mataroa + args: + executable: /bin/bash + become_user: deploy + - name: migrations + ansible.builtin.shell: + cmd: | + source .venv/bin/activate + python3 manage.py migrate --no-input + chdir: /var/www/mataroa + args: + executable: /bin/bash + become_user: deploy + - name: gunicorn restart + ansible.builtin.systemd: + name: mataroa + state: restarted + - name: caddy restart + ansible.builtin.systemd: + name: caddy + state: restarted diff --git a/ansible/vars.yaml b/ansible/vars.yaml new file mode 100644 index 0000000..e2a611a --- /dev/null +++ b/ansible/vars.yaml @@ -0,0 +1,5 @@ +--- +debug: "{{ lookup('env', 'DEBUG') }}" +secret_key: "{{ lookup('env', 'SECRET_KEY') }}" +email_host_user: "{{ lookup('env', 'EMAIL_HOST_USER') }}" +email_host_password: "{{ lookup('env', 'EMAIL_HOST_PASSWORD') }}" From 86c4c4119faf894b6cae51587ff58d98d2f18094 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:26:39 +0000 Subject: [PATCH 06/30] change host key name on ansible inventory --- ansible/inventory.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/inventory.yaml b/ansible/inventory.yaml index 5c10106..17a3ccc 100644 --- a/ansible/inventory.yaml +++ b/ansible/inventory.yaml @@ -1,5 +1,5 @@ virtualmachines: hosts: - huron: + main: ansible_host: "{{ lookup('env', 'ANSIBLE_HOST') }}" ansible_user: "{{ lookup('env', 'ANSIBLE_USER') }}" From 727fc1d81cadc9c749b7085258f98d6c5ea73d49 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:32:22 +0000 Subject: [PATCH 07/30] add postgres setup on ansible --- ansible/playbook.yaml | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/ansible/playbook.yaml b/ansible/playbook.yaml index 380b1ba..6b34c21 100644 --- a/ansible/playbook.yaml +++ b/ansible/playbook.yaml @@ -11,11 +11,15 @@ ansible.builtin.apt: update_cache: yes name: - - vim + - gcc - git + - libpq-dev + - postgresql + - python3-psycopg2 - python3.11 - - python3.11-venv - python3.11-dev + - python3.11-venv + - vim state: present # deploy user and directory @@ -44,6 +48,29 @@ group: www-data recurse: yes + # postgresql setup + - name: pg user + community.general.postgresql_user: + name: "{{ postgres_username }}" + password: "{{ postgres_password }}" + expires: infinity + state: present + become_user: postgres + - name: pg database + community.general.postgresql_db: + name: "{{ postgres_database }}" + owner: "{{ postgres_username }}" + state: present + become_user: postgres + - name: pg permissions + community.postgresql.postgresql_privs: + db: "{{ postgres_database }}" + privs: ALL + objs: ALL_IN_SCHEMA + role: "{{ postgres_username }}" + grant_option: true + become_user: postgres + # repository - name: clone ansible.builtin.git: From a4d3b24a36c321668111f1f5c7c283e4f2bf6a8f Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:38:27 +0000 Subject: [PATCH 08/30] fix database env vars for ansible --- ansible/playbook.yaml | 4 ++-- ansible/vars.yaml | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ansible/playbook.yaml b/ansible/playbook.yaml index 6b34c21..18a9e19 100644 --- a/ansible/playbook.yaml +++ b/ansible/playbook.yaml @@ -58,13 +58,13 @@ become_user: postgres - name: pg database community.general.postgresql_db: - name: "{{ postgres_database }}" + name: mataroa owner: "{{ postgres_username }}" state: present become_user: postgres - name: pg permissions community.postgresql.postgresql_privs: - db: "{{ postgres_database }}" + db: mataroa privs: ALL objs: ALL_IN_SCHEMA role: "{{ postgres_username }}" diff --git a/ansible/vars.yaml b/ansible/vars.yaml index e2a611a..80e175a 100644 --- a/ansible/vars.yaml +++ b/ansible/vars.yaml @@ -1,5 +1,15 @@ --- debug: "{{ lookup('env', 'DEBUG') }}" + secret_key: "{{ lookup('env', 'SECRET_KEY') }}" + +database_url: "{{ lookup('env', 'SECRET_KEY') }}" +postgres_username: "{{ lookup('env', 'POSTGRES_USERNAME') }}" +postgres_password: "{{ lookup('env', 'POSTGRES_PASSWORD') }}" + email_host_user: "{{ lookup('env', 'EMAIL_HOST_USER') }}" email_host_password: "{{ lookup('env', 'EMAIL_HOST_PASSWORD') }}" + +stripe_api_key: "{{ lookup('env', 'STRIPE_API_KEY') }}" +stripe_public_key: "{{ lookup('env', 'STRIPE_PUBLIC_KEY') }}" +stripe_price_id: "{{ lookup('env', 'STRIPE_PRICE_ID') }}" From 873f926dabf8bda693ae43e7c85cda91fbf36748 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:42:05 +0000 Subject: [PATCH 09/30] fix database url on migrations ansible task --- ansible/playbook.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ansible/playbook.yaml b/ansible/playbook.yaml index 18a9e19..1990a01 100644 --- a/ansible/playbook.yaml +++ b/ansible/playbook.yaml @@ -121,6 +121,8 @@ cmd: | source .venv/bin/activate python3 manage.py migrate --no-input + environment: + DATABASE_URL: "{{ database_url }}" chdir: /var/www/mataroa args: executable: /bin/bash From cc9205d724934e01456fff128ef92d21ef681968 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:44:24 +0000 Subject: [PATCH 10/30] change ansible environment configuration --- ansible/playbook.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ansible/playbook.yaml b/ansible/playbook.yaml index 1990a01..1584673 100644 --- a/ansible/playbook.yaml +++ b/ansible/playbook.yaml @@ -120,9 +120,7 @@ ansible.builtin.shell: cmd: | source .venv/bin/activate - python3 manage.py migrate --no-input - environment: - DATABASE_URL: "{{ database_url }}" + DATABASE_URL='{{ database_url }}' python3 manage.py migrate --no-input chdir: /var/www/mataroa args: executable: /bin/bash From 6c38c141e70099dc9aa130627f6642dec11257e1 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:57:43 +0000 Subject: [PATCH 11/30] add caddy on playbook ansible --- ansible/playbook.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/ansible/playbook.yaml b/ansible/playbook.yaml index 1584673..a604dea 100644 --- a/ansible/playbook.yaml +++ b/ansible/playbook.yaml @@ -22,6 +22,31 @@ - vim state: present + # caddy + - name: add caddy key + ansible.builtin.apt_key: + id: 65760C51EDEA2017CEA2CA15155B6D79CA56EA34 + url: https://dl.cloudsmith.io/public/caddy/stable/gpg.key + keyring: /etc/apt/trusted.gpg.d/caddy-stable.gpg + state: present + - name: add caddy deb repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/etc/apt/trusted.gpg.d/caddy-stable.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main + - name: add caddy deb-src repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/etc/apt/trusted.gpg.d/caddy-stable.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main + - name: install caddy + ansible.builtin.apt: + update_cache: yes + name: caddy + - name: caddyfile + ansible.builtin.template: + src: Caddyfile.j2 + dest: /etc/caddy/Caddyfile + owner: root + group: root + mode: '0644' + # deploy user and directory - name: www directory ansible.builtin.file: From 194533370f84a30fc4b1c0953f15e79453abba2a Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:57:54 +0000 Subject: [PATCH 12/30] update vars on playbook ansible --- ansible/mataroa.service.j2 | 6 +++++- ansible/vars.yaml | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ansible/mataroa.service.j2 b/ansible/mataroa.service.j2 index c85d50a..073eaef 100644 --- a/ansible/mataroa.service.j2 +++ b/ansible/mataroa.service.j2 @@ -7,12 +7,16 @@ Type=simple User=deploy Group=www-data WorkingDirectory=/var/www/mataroa -ExecStart=/var/www/mataroa/.venv/bin/gunicorn -b 127.0.0.1:5001 -w 4 mataroa.wsgi +ExecStart=/var/www/mataroa/.venv/bin/gunicorn -b 127.0.0.1:5000 -w 4 mataroa.wsgi ExecReload=/bin/kill -HUP $MAINPID Environment="DEBUG={{ debug }}" Environment="SECRET_KEY={{ secret_key }}" +Environment="DATABASE_URL={{ database_url }}" Environment="EMAIL_HOST_USER={{ email_host_user }}" Environment="EMAIL_HOST_PASSWORD={{ email_host_password }}" +Environment="STRIPE_API_KEY={{ stripe_api_key }}" +Environment="STRIPE_PUBLIC_KEY={{ stripe_public_key }}" +Environment="STRIPE_PRICE_ID={{ stripe_price_id }}" TimeoutSec=15 Restart=always diff --git a/ansible/vars.yaml b/ansible/vars.yaml index 80e175a..52ee280 100644 --- a/ansible/vars.yaml +++ b/ansible/vars.yaml @@ -1,9 +1,12 @@ --- +domain: "{{ lookup('env', 'DOMAIN') }}" +email: "{{ lookup('env', 'EMAIL') }}" + debug: "{{ lookup('env', 'DEBUG') }}" secret_key: "{{ lookup('env', 'SECRET_KEY') }}" -database_url: "{{ lookup('env', 'SECRET_KEY') }}" +database_url: "{{ lookup('env', 'DATABASE_URL') }}" postgres_username: "{{ lookup('env', 'POSTGRES_USERNAME') }}" postgres_password: "{{ lookup('env', 'POSTGRES_PASSWORD') }}" From 0669958a94efe4cb78bbedbfc46d28ca623fe048 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 11:58:11 +0000 Subject: [PATCH 13/30] add caddyfile config ansible template --- ansible/Caddyfile.j2 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 ansible/Caddyfile.j2 diff --git a/ansible/Caddyfile.j2 b/ansible/Caddyfile.j2 new file mode 100644 index 0000000..1eb5a10 --- /dev/null +++ b/ansible/Caddyfile.j2 @@ -0,0 +1,14 @@ +{{ domain }} { + route { + file_server /static/* { + root /var/www/mataroa + } + reverse_proxy 127.0.0.1:5000 + } + + tls {{ email }} { + on_demand + } + + encode zstd gzip +} From 0b58e3e7694499bd04e2e1a29f8123df31a6eca6 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 17:55:24 +0100 Subject: [PATCH 14/30] enable environment configured domain settings --- mataroa/settings.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mataroa/settings.py b/mataroa/settings.py index 8a95000..d270788 100644 --- a/mataroa/settings.py +++ b/mataroa/settings.py @@ -30,14 +30,14 @@ ALLOWED_HOSTS = [ "127.0.0.1", "localhost", - ".mataroa.blog", + f".{os.environ.get('DOMAIN', 'mataroa.blog')}", ".mataroalocal.blog", "*", ] ADMINS = [("Theodore Keloglou", "zf@sirodoht.com")] -CANONICAL_HOST = "mataroa.blog" +CANONICAL_HOST = os.environ.get("DOMAIN", "mataroa.blog") if DEBUG: CANONICAL_HOST = "mataroalocal.blog:8000" @@ -183,10 +183,10 @@ EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD") EMAIL_PORT = 587 -DEFAULT_FROM_EMAIL = "Mataroa " -NOTIFICATIONS_FROM_EMAIL = "Mataroa Notifications " -EMAIL_FROM_HOST = "mataroa.blog" -SERVER_EMAIL = "DC Parlov " +EMAIL_FROM_HOST = CANONICAL_HOST +DEFAULT_FROM_EMAIL = f"Mataroa " +NOTIFICATIONS_FROM_EMAIL = f"Mataroa Notifications " +SERVER_EMAIL = f"DC Parlov " EMAIL_SUBJECT_PREFIX = "[Mataroa Notification] " EMAIL_TEST_RECEIVE_LIST = os.environ.get("EMAIL_TEST_RECEIVE_LIST") From 28fcd742dc4b6d57dd71662a41c06788f1807772 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 14 Jul 2024 23:37:55 +0100 Subject: [PATCH 15/30] remove uwsgi related docs --- docs/src/dependencies.md | 6 +- docs/src/deployment.md | 40 ------- docs/src/file-structure-walkthrough.md | 3 +- docs/src/server-playbook.md | 158 ------------------------- mataroa.uwsgi.service | 17 --- uwsgi.example.ini | 19 --- 6 files changed, 4 insertions(+), 239 deletions(-) delete mode 100644 docs/src/server-playbook.md delete mode 100644 mataroa.uwsgi.service delete mode 100644 uwsgi.example.ini diff --git a/docs/src/dependencies.md b/docs/src/dependencies.md index 1e76d16..966f605 100644 --- a/docs/src/dependencies.md +++ b/docs/src/dependencies.md @@ -17,7 +17,7 @@ Current list of top-level PyPI dependencies (source at [requirements.in](/requir * [Django](https://pypi.org/project/Django/) * [psycopg2-binary](https://pypi.org/project/psycopg2-binary/) -* [uWSGI](https://pypi.org/project/uWSGI/) +* [gunicorn](https://pypi.org/project/gunicorn/) * [Markdown](https://pypi.org/project/Markdown/) * [Pygments](https://pypi.org/project/Pygments/) * [bleach](https://pypi.org/project/bleach/) @@ -27,7 +27,7 @@ Current list of top-level PyPI dependencies (source at [requirements.in](/requir After approving a dependency, the process to add it is: -1. Assuming a venv is activated and `requirements_dev.txt` are installed. +1. Assuming a venv is activated and `requirements.dev.txt` are installed. 1. Add new dependency in [`requirements.in`](/requirements.in). 1. Run `pip-compile` to generate [`requirements.txt`](/requirements.txt) 1. Run `pip install -r requirements.txt` @@ -38,7 +38,7 @@ When a new Django version is out it’s a good idea to upgrade everything. Steps: -1. Assuming a venv is activated and `requirements_dev.txt` are installed. +1. Assuming a venv is activated and `requirements.dev.txt` are installed. 1. Run `pip-compile -U` to generate an upgraded `requirements.txt`. 1. Run `git diff requirements.txt` and spot non-patch level vesion bumps. 1. Examine release notes of each one. diff --git a/docs/src/deployment.md b/docs/src/deployment.md index a5f3286..d36c65e 100644 --- a/docs/src/deployment.md +++ b/docs/src/deployment.md @@ -1,41 +1 @@ # Deployment - -How to deploy a new mataroa instance? - -1. Get a linux server -1. Follow the [server playbook](./server-playbook.md) -1. Update [mataroa/settings](../mataroa/settings.py) - * `ADMINS` - * `CANONICAL_HOST` - * `EMAIL_HOST` and `EMAIL_HOST_BROADCAST` -1. Adjust the [deploy.sh](../deploy.sh) script - * Change IP -1. Enable `deploy` user to reload the uwsgi systemd service. To do this... - -...add `deploy` user to sudo/wheel group: - -```sh -adduser deploy sudo -``` - -Then, edit sudoers with: - -```sh -visudo -``` - -and add the following: - -``` -# Allow deploy user to restart apps -%deploy ALL=NOPASSWD: /usr/bin/systemctl reload mataroa.uwsgi -``` - -Rumours are the only way to see the results is to reboot :/ - -But once you do (!) — then: - -```sh -sudo -i -u deploy -sudo systemctl reload mataroa.uwsgi -``` diff --git a/docs/src/file-structure-walkthrough.md b/docs/src/file-structure-walkthrough.md index 92e8817..154cacc 100644 --- a/docs/src/file-structure-walkthrough.md +++ b/docs/src/file-structure-walkthrough.md @@ -77,8 +77,7 @@ Condensed and commented sources file tree: │   └── wsgi.py ├── requirements.in # user-editable requirements file ├── requirements.txt # pip-compile generated version-locked dependencies -├── requirements_dev.txt # user-editable development requirements -└── uwsgi.example.ini # example configuration for uWSGI +└── requirements.dev.txt # user-editable development requirements ``` ## [`main/urls.py`](/main/urls.py) diff --git a/docs/src/server-playbook.md b/docs/src/server-playbook.md deleted file mode 100644 index 43cfcd2..0000000 --- a/docs/src/server-playbook.md +++ /dev/null @@ -1,158 +0,0 @@ -# Server Playbook - -This is a basic playbook on how to setup a new mataroa instance. - -Based and tested on Ubuntu 22.04. - -## Set editor - -Optional. - -```sh -select-editor -update-alternatives --config editor -echo 'export EDITOR=vim;' >> ~/.bashrc -source ~/.bashrc -``` - -## Set timezone - -```sh -timedatectl set-timezone UTC -``` - -## Update system - -```sh -apt update -unattended-upgrade -``` - -## Install Python and Git - -```sh -apt install -y python3 python3-dev python3-venv build-essential git -``` - -## Install Caddy - -From: https://caddyserver.com/docs/install#debian-ubuntu-raspbian - -```sh -apt install -y debian-keyring debian-archive-keyring apt-transport-https -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list -apt update -apt install caddy -``` - -## Setup deploy user - -```sh -adduser deploy # leave password empty three times -adduser deploy caddy -adduser deploy www-data -cd /var/ -mkdir www -chown -R deploy:www-data www -``` - -## Install and setup PostgreSQL - -```sh -apt install postgresql -sudo -i -u postgres -createdb mataroa -createuser mataroa -psql -ALTER USER mataroa WITH PASSWORD 'xxx'; -exit -exit -``` - -Note: Change 'xxx' with whatever password you choose. - -## Install acme.sh and get certificates - -We use Automatic DNS API integration with DNSimple in this case, because -wildcard domain auto-renew is much harder otherwise. - -https://github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dnsimple - -```sh -curl https://get.acme.sh | sh -s email=person@example.com -# installation also inserts a cronjob for auto-renewal - -# setup DNSimple API -echo 'export DNSimple_OAUTH_TOKEN="token-here"' >> /root/.acme.sh/acme.sh.env - -# issue cert -acme.sh --issue --dns dns_dnsimple -d mataroa.blog -d *.mataroa.blog - -# we "install" (copy) the cert because we should not use the cert from acme.sh's internal store -acme.sh --install-cert -d mataroa.blog -d *.mataroa.blog --key-file /etc/caddy/mataroa-blog-key.pem --fullchain-file /etc/caddy/mataroa-blog-cert.pem --reloadcmd "chown caddy:www-data /etc/caddy/mataroa-blog-{cert,key}.pem && systemctl restart caddy" -``` - -Note: acme.sh's default SSL provider is ZeroSSL which does not accept email with -plus-subaddressing. It will not error gracefully, just fail with a cryptic -message (tested with acmesh v3.0.7). - -## Clone repository and configure - -```sh -sudo -i -u deploy -cd /var/www/ -git clone https://git.sr.ht/~sirodoht/mataroa - -cd mataroa/ -python3 -m venv .venv -source .venv/bin/activate -pip install -r requirements.txt -python manage.py collectstatic - -# setup uwsgi -cp uwsgi.example.ini uwsgi.ini -vim uwsgi.ini # edit env variables -exit - -# setup caddy -cp Caddyfile /etc/caddy/ -sudo vim /etc/caddy/Caddyfile # edit caddyfile as required -``` - -Note: We could install uWSGI from Ubuntu's repositories (it's written in C -after all) but uWSGI has multiple extensions and compile options which change -depending on the distribution. For this reason, we install from PyPI, which is -consistent. - -## Add systemd entry - -```sh -cp /var/www/mataroa/mataroa.uwsgi.service /lib/systemd/system/mataroa.uwsgi.service - -# edit and add env variables as required -vim /lib/systemd/system/mataroa.uwsgi.service - -ln -s /lib/systemd/system/mataroa.uwsgi.service /etc/systemd/system/multi-user.target.wants/ -systemctl daemon-reload -systemctl enable mataroa.uwsgi -systemctl start mataroa.uwsgi -systemctl status mataroa.uwsgi -``` - -At this point DNS should also be set and just rebooting should result in the -instance showing the landing. - -## Setup Cronjobs - -One at 10am for email notifications (newsletters): - -``` -0 10 * * * * bash -c 'cd /var/www/mataroa && source .venv/bin/activate && source .envrc && python manage.py processnotifications' -``` - -One monthly for mail exports - -``` -0 0 * * * bash -c 'cd /var/www/mataroa && source .venv/bin/activate && source .envrc && python manage.py mail_exports' -``` diff --git a/mataroa.uwsgi.service b/mataroa.uwsgi.service deleted file mode 100644 index cb9c483..0000000 --- a/mataroa.uwsgi.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=uWSGI instance to serve mataroa -Documentation=https://github.com/mataroa-blog/mataroa -After=network.target - -[Service] -Type=simple -User=deploy -Group=www-data -ExecStart=/var/www/mataroa/.venv/bin/uwsgi --ini /var/www/mataroa/uwsgi.ini -ExecReload=/bin/kill -HUP $MAINPID -WorkingDirectory=/var/www/mataroa -Environment="PATH=/var/www/mataroa/.venv/bin" -ProtectSystem=full - -[Install] -WantedBy=multi-user.target diff --git a/uwsgi.example.ini b/uwsgi.example.ini deleted file mode 100644 index 18f8060..0000000 --- a/uwsgi.example.ini +++ /dev/null @@ -1,19 +0,0 @@ -[uwsgi] -master = true -module = mataroa.wsgi:application -virtualenv = .venv -strict = true -http-socket = :5000 -need-app = true -vacuum = true -max-requests = 5000 -processes = 3 -harakiri = 120 -enable-threads = true -die-on-term = true - -env = DEBUG=1 -env = SECRET_KEY=some-secret-key -env = DATABASE_URL=postgres://mataroa:db-password@db:5432/mataroa -env = EMAIL_HOST_USER=smtp-user -env = EMAIL_HOST_PASSWORD=smtp-password From 2af33b8cdfb99eb1bd107282a512ae60d9ff7119 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 12:13:48 +0000 Subject: [PATCH 16/30] remove deploy script --- deploy.sh | 55 ------------------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100755 deploy.sh diff --git a/deploy.sh b/deploy.sh deleted file mode 100755 index 9487d79..0000000 --- a/deploy.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -set -o nounset -set -o pipefail -if [[ "${TRACE-0}" == "1" ]]; then - set -o xtrace -fi - -if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then - echo 'Usage: ./deploy.sh - -This script deploys the service in the production server.' - exit -fi - -cd "$(dirname "$0")" - -main() { - # check venv is enabled - if [[ -z "${VIRTUAL_ENV}" ]]; then - exit - fi - - # make sure linting checks pass - make lint - - # static - python manage.py collectstatic --noinput - - # make sure latest requirements are installed - pip install -U pip - pip install -r requirements.txt - - # make sure tests pass - make test - - # push origin srht - git push -v srht main - - # push on github - git push -v github main - - # pull on server and reload - ssh deploy@95.217.30.133 'cd /var/www/mataroa ' \ - '&& git pull ' \ - '&& source .venv/bin/activate ' \ - '&& pip install -U pip ' \ - '&& pip install -r requirements.txt ' \ - '&& python manage.py collectstatic --noinput ' \ - '&& source .envrc && python manage.py migrate ' \ - '&& sudo systemctl reload mataroa.uwsgi' -} - -main "$@" From a4693d0cba88f629c4d7ab599d9c6a93c24cebf2 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 12:14:09 +0000 Subject: [PATCH 17/30] add new variables on ansible envrc example --- ansible/.envrc.example | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ansible/.envrc.example b/ansible/.envrc.example index c306d83..4ffd897 100644 --- a/ansible/.envrc.example +++ b/ansible/.envrc.example @@ -7,15 +7,21 @@ export ANSIBLE_USER=root # vars.yaml +# Domain name and email for Caddy +export DOMAIN=mataroa.blog +export EMAIL=admin@mataroa.blog + # Show exceptions and tracebacks on errors export DEBUG=1 -# Database connection -export DATABASE_URL=postgres://mataroa:@localhost:5432/mataroa - # Session cookies secret export SECRET_KEY=some-secret-key +# Database connection +export DATABASE_URL=postgres://mataroa:xxx@localhost:5432/mataroa +export POSTGRES_USERNAME=mataroa +export POSTGRES_PASSWORD=xxx + # SMTP credentials export EMAIL_HOST_USER= export EMAIL_HOST_PASSWORD= From ff313122aa8325e82494d043b246f1ad1f992d84 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 17:56:35 +0100 Subject: [PATCH 18/30] change readme with updated deploy docs --- README.md | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 0356c9a..343ea52 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ volume, located in the root of the project. ``` python3 -m venv .venv source .venv/bin/activate -pip install -r requirements_dev.txt +pip install -r requirements.dev.txt pip install -r requirements.txt ``` @@ -221,20 +221,12 @@ make lint See the [Deployment](./docs/deployment.md) document for an overview on steps required to deploy a mataroa instance. -See the [Server Playbook](./docs/server-playbook.md) document for a detailed -run through of setting up a mataroa instance on an Ubuntu 22.04 LTS system -using [uWSGI](https://uwsgi.readthedocs.io/en/latest/) and -[Caddy](https://caddyserver.com/). - -See the [Server Migration](./docs/server-migration.md) document for a guide on -how to migrate servers. - ### Useful Commands -To reload the uWSGI process: +To reload the gunicorn process: ```sh -sudo systemctl reload mataroa.uwsgi +sudo systemctl reload mataroa ``` To reload Caddy: @@ -243,10 +235,10 @@ To reload Caddy: systemctl restart caddy # root only ``` -uWSGI logs: +gunicorn logs: ```sh -journalctl -fb -u mataroa.uwsgi +journalctl -fb -u mataroa ``` Caddy logs: @@ -259,7 +251,7 @@ Get an overview with systemd status: ```sh systemctl status caddy -systemctl status mataroa.uwsgi +systemctl status mataroa ``` ## Backup From ad5d7c25128dfd1a20035ad4a9caaa709596f6d8 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 12:14:52 +0000 Subject: [PATCH 19/30] fix dockerfile dev requirements --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7287efa..d14e3a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,8 +12,8 @@ RUN apt-get update && \ && rm -rf /var/lib/apt/lists/* COPY requirements.txt /code/ -COPY requirements_dev.txt /code/ -RUN pip install -U pip && pip install -Ur /code/requirements.txt && pip install -Ur /code/requirements_dev.txt +COPY requirements.dev.txt /code/ +RUN pip install -U pip && pip install -Ur /code/requirements.txt && pip install -Ur /code/requirements.dev.txt WORKDIR /code COPY . /code/ From f975b0db32d4e26489c149e2c04c2a3d013bb1b9 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 12:17:42 +0000 Subject: [PATCH 20/30] fix and update github ci --- .github/workflows/django-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/django-build.yml b/.github/workflows/django-build.yml index c4adec3..1a59899 100644 --- a/.github/workflows/django-build.yml +++ b/.github/workflows/django-build.yml @@ -25,10 +25,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python 3.10 + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' - name: Install Dependencies run: | python -m pip install --upgrade pip @@ -43,6 +43,6 @@ jobs: - name: Lint run: | touch .envrc - pip install -r requirements_dev.txt + pip install -r requirements.dev.txt pip install -r requirements.txt make lint From d9061f6e774dc30b358d170149ea594067b20c73 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sat, 30 Mar 2024 12:49:07 +0000 Subject: [PATCH 21/30] add localdev mode env variable --- .envrc.example | 25 ++++++++++++++++++++++--- ansible/.envrc.example | 7 +++++++ ansible/mataroa.service.j2 | 3 +++ ansible/vars.yaml | 1 + mataroa/settings.py | 8 +++++--- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/.envrc.example b/.envrc.example index e1ebd40..73fa8df 100644 --- a/.envrc.example +++ b/.envrc.example @@ -1,5 +1,24 @@ +# Exceptions and tracebacks on errors +# 1: show +# 0: don't show export DEBUG=1 + +# Stop real emails and turn https off +# 1: stop and off +# 0: do not stop and on +export LOCALDEV_MODE=1 + +# Session cookies secret export SECRET_KEY=some-secret-key -export DATABASE_URL=postgres://mataroa:db-password@db:5432/mataroa -export EMAIL_HOST_USER=smtp-user -export EMAIL_HOST_PASSWORD=smtp-password + +# Database connection +export DATABASE_URL=postgres://mataroa:xxx@localhost:5432/mataroa + +# SMTP credentials +export EMAIL_HOST_USER= +export EMAIL_HOST_PASSWORD= + +# Stripe payments details +export STRIPE_API_KEY= +export STRIPE_PUBLIC_KEY= +export STRIPE_PRICE_ID= diff --git a/ansible/.envrc.example b/ansible/.envrc.example index 4ffd897..f69f78b 100644 --- a/ansible/.envrc.example +++ b/ansible/.envrc.example @@ -12,8 +12,15 @@ export DOMAIN=mataroa.blog export EMAIL=admin@mataroa.blog # Show exceptions and tracebacks on errors +# 1: show +# 0: don't show export DEBUG=1 +# Stop real emails and turn https off +# 1: stop and off +# 0: do not stop and on +export LOCALDEV_MODE=1 + # Session cookies secret export SECRET_KEY=some-secret-key diff --git a/ansible/mataroa.service.j2 b/ansible/mataroa.service.j2 index 073eaef..2fd2e83 100644 --- a/ansible/mataroa.service.j2 +++ b/ansible/mataroa.service.j2 @@ -9,7 +9,10 @@ Group=www-data WorkingDirectory=/var/www/mataroa ExecStart=/var/www/mataroa/.venv/bin/gunicorn -b 127.0.0.1:5000 -w 4 mataroa.wsgi ExecReload=/bin/kill -HUP $MAINPID +Environment="DOMAIN={{ domain }}" +Environment="EMAIL={{ email }}" Environment="DEBUG={{ debug }}" +Environment="LOCALDEV_MODE={{ localdev_mode }}" Environment="SECRET_KEY={{ secret_key }}" Environment="DATABASE_URL={{ database_url }}" Environment="EMAIL_HOST_USER={{ email_host_user }}" diff --git a/ansible/vars.yaml b/ansible/vars.yaml index 52ee280..1ad1126 100644 --- a/ansible/vars.yaml +++ b/ansible/vars.yaml @@ -3,6 +3,7 @@ domain: "{{ lookup('env', 'DOMAIN') }}" email: "{{ lookup('env', 'EMAIL') }}" debug: "{{ lookup('env', 'DEBUG') }}" +localdev_mode: "{{ lookup('env', 'LOCALDEV_MODE') }}" secret_key: "{{ lookup('env', 'SECRET_KEY') }}" diff --git a/mataroa/settings.py b/mataroa/settings.py index d270788..7b591d4 100644 --- a/mataroa/settings.py +++ b/mataroa/settings.py @@ -27,6 +27,8 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True if os.environ.get("DEBUG") == "1" else False +LOCALDEV_MODE = True if os.environ.get("LOCALDEV_MODE") == "1" else False + ALLOWED_HOSTS = [ "127.0.0.1", "localhost", @@ -38,7 +40,7 @@ ADMINS = [("Theodore Keloglou", "zf@sirodoht.com")] CANONICAL_HOST = os.environ.get("DOMAIN", "mataroa.blog") -if DEBUG: +if LOCALDEV_MODE: CANONICAL_HOST = "mataroalocal.blog:8000" @@ -174,7 +176,7 @@ # Email EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" -if DEBUG: +if LOCALDEV_MODE: EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" EMAIL_USE_TLS = True EMAIL_HOST = "smtp.postmarkapp.com" @@ -194,7 +196,7 @@ # Security middleware -if not DEBUG: +if not LOCALDEV_MODE: SECURE_CONTENT_TYPE_NOSNIFF = True X_FRAME_OPTIONS = "DENY" SESSION_COOKIE_SECURE = True From b870673c3db0bf597a74ee0c60a8872a40671d8a Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 17:57:13 +0100 Subject: [PATCH 22/30] switch to getenv on settings --- mataroa/settings.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/mataroa/settings.py b/mataroa/settings.py index 7b591d4..5125508 100644 --- a/mataroa/settings.py +++ b/mataroa/settings.py @@ -22,24 +22,24 @@ # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.environ.get("SECRET_KEY", "nonrandom_secret") +SECRET_KEY = os.getenv("SECRET_KEY", "nonrandom_secret") # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True if os.environ.get("DEBUG") == "1" else False +DEBUG = True if os.getenv("DEBUG") == "1" else False -LOCALDEV_MODE = True if os.environ.get("LOCALDEV_MODE") == "1" else False +LOCALDEV_MODE = True if os.getenv("LOCALDEV_MODE") == "1" else False ALLOWED_HOSTS = [ "127.0.0.1", "localhost", - f".{os.environ.get('DOMAIN', 'mataroa.blog')}", + f".{os.getenv('DOMAIN', 'mataroa.blog')}", ".mataroalocal.blog", "*", ] ADMINS = [("Theodore Keloglou", "zf@sirodoht.com")] -CANONICAL_HOST = os.environ.get("DOMAIN", "mataroa.blog") +CANONICAL_HOST = os.getenv("DOMAIN", "mataroa.blog") if LOCALDEV_MODE: CANONICAL_HOST = "mataroalocal.blog:8000" @@ -104,7 +104,7 @@ # Database # https://docs.djangoproject.com/en/3.0/ref/settings/#databases -database_url = os.environ.get("DATABASE_URL", "") +database_url = os.getenv("DATABASE_URL", "") database_url = parse.urlparse(database_url) # e.g. postgres://mataroa:password@127.0.0.1:5432/mataroa database_name = database_url.path[1:] # url.path is '/mataroa' @@ -181,8 +181,8 @@ EMAIL_USE_TLS = True EMAIL_HOST = "smtp.postmarkapp.com" EMAIL_HOST_BROADCASTS = "smtp-broadcasts.postmarkapp.com" -EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER") -EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD") +EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER") +EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") EMAIL_PORT = 587 EMAIL_FROM_HOST = CANONICAL_HOST @@ -206,17 +206,17 @@ # Stripe # https://stripe.com/docs/api -STRIPE_API_KEY = os.environ.get("STRIPE_API_KEY", "") -STRIPE_PUBLIC_KEY = os.environ.get("STRIPE_PUBLIC_KEY", "") -STRIPE_PRICE_ID = os.environ.get("STRIPE_PRICE_ID", "") +STRIPE_API_KEY = os.getenv("STRIPE_API_KEY", "") +STRIPE_PUBLIC_KEY = os.getenv("STRIPE_PUBLIC_KEY", "") +STRIPE_PRICE_ID = os.getenv("STRIPE_PRICE_ID", "") # Translate -TRANSLATE_API_URL = os.environ.get( +TRANSLATE_API_URL = os.getenv( "TRANSLATE_API_URL", "https://translate.mataroa.blog/api/generate" ) -TRANSLATE_API_TOKEN = os.environ.get("TRANSLATE_API_TOKEN", "") +TRANSLATE_API_TOKEN = os.getenv("TRANSLATE_API_TOKEN", "") # Logging From 15f3b202ceba25e090a80f8479dc8930e5c5ca0b Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 18:04:45 +0100 Subject: [PATCH 23/30] switch to ruff --- Makefile | 34 ---------------------------------- README.md | 30 +++++++++++++++++++++--------- requirements.dev.txt | 10 ++++------ ruff.toml | 16 ++++++++++++++++ 4 files changed, 41 insertions(+), 49 deletions(-) delete mode 100644 Makefile create mode 100644 ruff.toml diff --git a/Makefile b/Makefile deleted file mode 100644 index b67d449..0000000 --- a/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -.PHONY: all -all: format lint cov - -.PHONY: format -format: - $(info Formating Python code) - black --exclude '/\.venv/' . - isort --profile black . - -.PHONY: lint -lint: - $(info Running Python linters) - flake8 --exclude=.venv/ --ignore=E203,E501,W503 - isort --check-only --profile black . - black --check --exclude '/\.venv/' . - shellcheck -x *.sh - -.PHONY: test -test: - $(info Running test suite) - python -Wall manage.py test - -.PHONY: cov -cov: - $(info Generating coverage report) - coverage run --source='.' --omit '.venv/*' manage.py test - coverage report -m - -.PHONY: upgrade -upgrade: - $(info Running pip-compile -U) - pip-compile -U requirements.in - pip install --upgrade pip - pip install -r requirements.txt diff --git a/README.md b/README.md index 343ea52..ae9008d 100644 --- a/README.md +++ b/README.md @@ -197,23 +197,35 @@ python manage.py test For coverage, run: ```sh -make cov +coverage run --source='.' --omit '.venv/*' manage.py test +coverage report -m ``` ## Code linting & formatting -The following tools are used for code linting and formatting: +We use [ruff](https://github.com/astral-sh/ruff) for Python code formatting and linting. -* [black](https://github.com/psf/black) for code formatting -* [isort](https://github.com/pycqa/isort) for imports order consistency -* [flake8](https://gitlab.com/pycqa/flake8) for code linting -* [shellcheck](https://github.com/koalaman/shellcheck) for shell scripts +To format: -To use: +```sh +ruff format +``` + +To lint: ```sh -make format -make lint +ruff check +ruff check --fix +``` + +## Python dependencies + +We use [pip-tools](https://github.com/jazzband/pip-tools) to manage our Python dependencies: + +```sh +pip-compile -U requirements.in +pip install --upgrade pip +pip install -r requirements.txt ``` ## Deployment diff --git a/requirements.dev.txt b/requirements.dev.txt index 9a99824..a97e033 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -1,6 +1,4 @@ -pip-tools==7.3.0 -isort==5.10.1 -flake8==6.1.0 -black==23.11.0 -coverage==7.3.2 -ansible==9.4.0 +pip-tools==7.4.1 +ruff==0.5.0 +coverage==7.5.4 +ansible==10.1.0 diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..f514d76 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,16 @@ +[lint] +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # flake8-simplify + "SIM", + # isort + "I", +] +ignore = ["E501"] # line too long From 13de15eb0236290db24d2bf0496c281101f802dd Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 18:05:50 +0100 Subject: [PATCH 24/30] ruff check fix --- main/tests/test_billing.py | 24 ++++++------------------ main/tests/test_blog.py | 6 +++--- main/views/export.py | 34 +++++++++++++++++----------------- manage.py | 1 + mataroa/urls.py | 1 + 5 files changed, 28 insertions(+), 38 deletions(-) diff --git a/main/tests/test_billing.py b/main/tests/test_billing.py index 1639119..4fec4cf 100644 --- a/main/tests/test_billing.py +++ b/main/tests/test_billing.py @@ -66,9 +66,7 @@ def test_index(self): ), patch.object( billing, "_get_payment_methods", - ), patch.object( - billing, "_get_invoices" - ): + ), patch.object(billing, "_get_invoices"): response = self.client.get(reverse("billing_index")) self.assertEqual(response.status_code, 200) self.assertContains(response, b"Free Plan") @@ -95,9 +93,7 @@ def test_index(self): billing, "_get_stripe_subscription", return_value=subscription, - ), patch.object( - billing, "_get_payment_methods" - ), patch.object( + ), patch.object(billing, "_get_payment_methods"), patch.object( billing, "_get_invoices" ): response = self.client.get(reverse("billing_index")) @@ -135,9 +131,7 @@ def test_card_add_post(self): billing, "_get_stripe_subscription", return_value=subscription, - ), patch.object( - billing, "_get_payment_methods" - ), patch.object( + ), patch.object(billing, "_get_payment_methods"), patch.object( billing, "_get_invoices" ): response = self.client.post( @@ -205,9 +199,7 @@ def test_cancel_subscription_get(self): ), patch.object( billing, "_get_payment_methods", - ), patch.object( - billing, "_get_invoices" - ): + ), patch.object(billing, "_get_invoices"): response = self.client.get(reverse("billing_subscription_cancel")) # need to check inside with context because billing_index needs @@ -224,9 +216,7 @@ def test_cancel_subscription_post(self): ), patch.object( billing, "_get_payment_methods", - ), patch.object( - billing, "_get_invoices" - ): + ), patch.object(billing, "_get_invoices"): response = self.client.post(reverse("billing_subscription_cancel")) self.assertRedirects(response, reverse("billing_index")) @@ -269,9 +259,7 @@ def test_reenable_subscription_post(self): ), patch.object( billing, "_get_payment_methods", - ), patch.object( - billing, "_get_invoices" - ): + ), patch.object(billing, "_get_invoices"): response = self.client.post(reverse("billing_subscription")) self.assertRedirects(response, reverse("billing_index")) diff --git a/main/tests/test_blog.py b/main/tests/test_blog.py index 2f3b6b9..78a694e 100644 --- a/main/tests/test_blog.py +++ b/main/tests/test_blog.py @@ -251,9 +251,9 @@ def test_blog_export(self): response = self.client.post(reverse("export_epub")) self.assertEqual(response.status_code, 200) self.assertEqual(response["Content-Type"], "application/epub") - self.assertContains(response, "OEBPS/titlepage.xhtml".encode("utf-8")) - self.assertContains(response, "OEBPS/toc.xhtml".encode("utf-8")) - self.assertContains(response, "OEBPS/author.xhtml".encode("utf-8")) + self.assertContains(response, b"OEBPS/titlepage.xhtml") + self.assertContains(response, b"OEBPS/toc.xhtml") + self.assertContains(response, b"OEBPS/author.xhtml") class BlogNotificationListTestCase(TestCase): diff --git a/main/views/export.py b/main/views/export.py index 4b61934..9cad874 100644 --- a/main/views/export.py +++ b/main/views/export.py @@ -73,7 +73,7 @@ def export_markdown(request): def export_zola(request): if request.method == "POST": # load zola templates - with open("./export_base_zola/config.toml", "r") as zola_config_file: + with open("./export_base_zola/config.toml") as zola_config_file: zola_config = ( zola_config_file.read() .replace("example.com", f"{request.user.username}.mataroa.blog") @@ -82,13 +82,13 @@ def export_zola(request): "Example blog description", f"{request.user.blog_byline or ''}" ) ) - with open("./export_base_zola/style.css", "r") as zola_styles_file: + with open("./export_base_zola/style.css") as zola_styles_file: zola_styles = zola_styles_file.read() - with open("./export_base_zola/index.html", "r") as zola_index_file: + with open("./export_base_zola/index.html") as zola_index_file: zola_index = zola_index_file.read() - with open("./export_base_zola/post.html", "r") as zola_post_file: + with open("./export_base_zola/post.html") as zola_post_file: zola_post = zola_post_file.read() - with open("./export_base_zola/_index.md", "r") as zola_content_index_file: + with open("./export_base_zola/_index.md") as zola_content_index_file: zola_content_index = zola_content_index_file.read() # get all user posts and add them into export_posts encoded @@ -129,7 +129,7 @@ def export_zola(request): def export_hugo(request): if request.method == "POST": # load hugo templates - with open("./export_base_hugo/config.toml", "r") as hugo_config_file: + with open("./export_base_hugo/config.toml") as hugo_config_file: blog_title = request.user.blog_title or f"{request.user.username} blog" blog_byline = request.user.blog_byline or "" hugo_config = ( @@ -138,17 +138,17 @@ def export_hugo(request): .replace("Example blog title", blog_title) .replace("Example blog description", blog_byline) ) - with open("./export_base_hugo/theme.toml", "r") as hugo_theme_file: + with open("./export_base_hugo/theme.toml") as hugo_theme_file: hugo_theme = hugo_theme_file.read() - with open("./export_base_hugo/style.css", "r") as hugo_styles_file: + with open("./export_base_hugo/style.css") as hugo_styles_file: hugo_styles = hugo_styles_file.read() - with open("./export_base_hugo/single.html", "r") as hugo_single_file: + with open("./export_base_hugo/single.html") as hugo_single_file: hugo_single = hugo_single_file.read() - with open("./export_base_hugo/list.html", "r") as hugo_list_file: + with open("./export_base_hugo/list.html") as hugo_list_file: hugo_list = hugo_list_file.read() - with open("./export_base_hugo/index.html", "r") as hugo_index_file: + with open("./export_base_hugo/index.html") as hugo_index_file: hugo_index = hugo_index_file.read() - with open("./export_base_hugo/baseof.html", "r") as hugo_baseof_file: + with open("./export_base_hugo/baseof.html") as hugo_baseof_file: hugo_baseof = hugo_baseof_file.read() # get all user posts and add them into export_posts encoded @@ -302,9 +302,9 @@ def export_epub(request): epub_uuid = str(uuid.uuid4()) # load mimetype and container.xml - with open("./export_base_epub/mimetype", "r") as mimetype_file: + with open("./export_base_epub/mimetype") as mimetype_file: mimetype_content = mimetype_file.read() - with open("./export_base_epub/container.xml", "r") as container_xml_file: + with open("./export_base_epub/container.xml") as container_xml_file: container_xml_content = container_xml_file.read() # process posts @@ -329,7 +329,7 @@ def export_epub(request): + "\n" ) content_opf_spine += f' ' + "\n" - with open("./export_base_epub/content.opf", "r") as opf_content_file: + with open("./export_base_epub/content.opf") as opf_content_file: content_opf_content = opf_content_file.read() content_opf_content = content_opf_content.replace( @@ -370,7 +370,7 @@ def export_epub(request): f'
  • {chapter["title"]}
  • ' + "\n" ) - with open("./export_base_epub/toc.xhtml", "r") as toc_xhtml_file: + with open("./export_base_epub/toc.xhtml") as toc_xhtml_file: toc_xhtml_content = toc_xhtml_file.read() toc_xhtml_content = toc_xhtml_content.replace( "", toc_xhtml_body @@ -399,7 +399,7 @@ def export_epub(request): chapter_title="About the Author", chapter_link="author.xhtml", ) - with open("./export_base_epub/toc.ncx", "r") as toc_ncx_file: + with open("./export_base_epub/toc.ncx") as toc_ncx_file: toc_ncx_content = toc_ncx_file.read() toc_ncx_content = toc_ncx_content.replace( diff --git a/manage.py b/manage.py index db6e463..8c140e7 100755 --- a/manage.py +++ b/manage.py @@ -1,5 +1,6 @@ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" + import os import sys diff --git a/mataroa/urls.py b/mataroa/urls.py index 576c91d..a7c1ffc 100644 --- a/mataroa/urls.py +++ b/mataroa/urls.py @@ -13,6 +13,7 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.contrib import admin from django.urls import include, path From da0dcc934b20f1c15316d0a3a0cc3b8961ec7138 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 18:06:27 +0100 Subject: [PATCH 25/30] ruff check fix unsafe --- main/models.py | 4 +--- main/util.py | 2 +- main/views/billing.py | 4 ++-- mataroa/settings.py | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/main/models.py b/main/models.py index b8607be..b2b2184 100644 --- a/main/models.py +++ b/main/models.py @@ -224,9 +224,7 @@ def body_as_text(self): @property def is_draft(self): - if self.published_at: - return False - return True + return not self.published_at @property def is_published(self): diff --git a/main/util.py b/main/util.py index 44f986f..462973a 100644 --- a/main/util.py +++ b/main/util.py @@ -161,7 +161,7 @@ def remove_control_chars(text): See http://www.unicode.org/reports/tr44/#General_Category_Values """ control_char_string = "".join(denylist.DISALLOWED_CHARACTERS) - control_char_re = re.compile("[%s]" % re.escape(control_char_string)) + control_char_re = re.compile(f"[{re.escape(control_char_string)}]") return control_char_re.sub(" ", text) diff --git a/main/views/billing.py b/main/views/billing.py index a7b347d..d6e89b9 100644 --- a/main/views/billing.py +++ b/main/views/billing.py @@ -338,7 +338,7 @@ def dispatch(self, request, *args, **kwargs): # check if card id is valid for user card_id = self.kwargs.get(self.slug_url_kwarg) - if card_id not in self.stripe_payment_methods.keys(): + if card_id not in self.stripe_payment_methods: mail_admins( "User tried to delete card with invalid Stripe card ID", f"user.id={request.user.id}\nuser.username={request.user.username}", @@ -360,7 +360,7 @@ def billing_card_default(request, stripe_payment_method_id): stripe_payment_methods = _get_payment_methods(request.user.stripe_customer_id) - if stripe_payment_method_id not in stripe_payment_methods.keys(): + if stripe_payment_method_id not in stripe_payment_methods: return HttpResponseBadRequest("Invalid Card ID.") stripe.api_key = settings.STRIPE_API_KEY diff --git a/mataroa/settings.py b/mataroa/settings.py index 5125508..b2132ec 100644 --- a/mataroa/settings.py +++ b/mataroa/settings.py @@ -25,9 +25,9 @@ SECRET_KEY = os.getenv("SECRET_KEY", "nonrandom_secret") # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True if os.getenv("DEBUG") == "1" else False +DEBUG = os.getenv("DEBUG") == "1" -LOCALDEV_MODE = True if os.getenv("LOCALDEV_MODE") == "1" else False +LOCALDEV_MODE = os.getenv("LOCALDEV_MODE") == "1" ALLOWED_HOSTS = [ "127.0.0.1", From 549b24022e56bc7c8539b146f2e17ff2056c274f Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 18:10:49 +0100 Subject: [PATCH 26/30] fix raise from exception ruff check errors --- main/models.py | 6 +++--- main/views/billing.py | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/main/models.py b/main/models.py index b2b2184..ffe379f 100644 --- a/main/models.py +++ b/main/models.py @@ -228,11 +228,11 @@ def is_draft(self): @property def is_published(self): + # draft case if not self.published_at: - # draft case return False - if self.published_at > timezone.now().date(): - # future publishing date case + # future publishing date case + if self.published_at > timezone.now().date(): # noqa: SIM103 return False return True diff --git a/main/views/billing.py b/main/views/billing.py index d6e89b9..9104f07 100644 --- a/main/views/billing.py +++ b/main/views/billing.py @@ -35,7 +35,7 @@ def _create_setup_intent(customer_id): ) except stripe.error.StripeError as ex: logger.error(str(ex)) - raise Exception("Failed to create setup intent on Stripe.") + raise Exception("Failed to create setup intent on Stripe.") from ex return { "stripe_client_secret": stripe_setup_intent["client_secret"], @@ -61,7 +61,7 @@ def _create_stripe_subscription(customer_id): ) except stripe.error.StripeError as ex: logger.error(str(ex)) - raise Exception("Failed to create subscription on Stripe.") + raise Exception("Failed to create subscription on Stripe.") from ex return { "stripe_subscription_id": stripe_subscription["id"], @@ -78,7 +78,7 @@ def _get_stripe_subscription(stripe_subscription_id): stripe_subscription = stripe.Subscription.retrieve(stripe_subscription_id) except stripe.error.StripeError as ex: logger.error(str(ex)) - raise Exception("Failed to get subscription from Stripe.") + raise Exception("Failed to get subscription from Stripe.") from ex return stripe_subscription @@ -94,7 +94,7 @@ def _get_payment_methods(stripe_customer_id): ).invoice_settings.default_payment_method except stripe.error.StripeError as ex: logger.error(str(ex)) - raise Exception("Failed to retrieve customer data from Stripe.") + raise Exception("Failed to retrieve customer data from Stripe.") from ex # get payment methods try: @@ -104,7 +104,7 @@ def _get_payment_methods(stripe_customer_id): ) except stripe.error.StripeError as ex: logger.error(str(ex)) - raise Exception("Failed to retrieve payment methods from Stripe.") + raise Exception("Failed to retrieve payment methods from Stripe.") from ex # normalise payment methods payment_methods = {} @@ -132,7 +132,7 @@ def _get_invoices(stripe_customer_id): stripe_invoices = stripe.Invoice.list(customer=stripe_customer_id) except stripe.error.StripeError as ex: logger.error(str(ex)) - raise Exception("Failed to retrieve invoices data from Stripe.") + raise Exception("Failed to retrieve invoices data from Stripe.") from ex # normalise invoices objects invoice_list = [] @@ -179,7 +179,7 @@ def billing_index(request): stripe_response = stripe.Customer.create() except stripe.error.StripeError as ex: logger.error(str(ex)) - raise Exception("Failed to create customer on Stripe.") + raise Exception("Failed to create customer on Stripe.") from ex request.user.stripe_customer_id = stripe_response["id"] request.user.save() From ecba2ed62d82ddfe76fbb9a9b727ad3720c651e3 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 18:17:26 +0100 Subject: [PATCH 27/30] change localdev variable name --- .envrc.example | 2 +- ansible/.envrc.example | 2 +- ansible/mataroa.service.j2 | 2 +- ansible/vars.yaml | 2 +- mataroa/settings.py | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.envrc.example b/.envrc.example index 73fa8df..d3b937f 100644 --- a/.envrc.example +++ b/.envrc.example @@ -6,7 +6,7 @@ export DEBUG=1 # Stop real emails and turn https off # 1: stop and off # 0: do not stop and on -export LOCALDEV_MODE=1 +export LOCALDEV=1 # Session cookies secret export SECRET_KEY=some-secret-key diff --git a/ansible/.envrc.example b/ansible/.envrc.example index f69f78b..e449623 100644 --- a/ansible/.envrc.example +++ b/ansible/.envrc.example @@ -19,7 +19,7 @@ export DEBUG=1 # Stop real emails and turn https off # 1: stop and off # 0: do not stop and on -export LOCALDEV_MODE=1 +export LOCALDEV=1 # Session cookies secret export SECRET_KEY=some-secret-key diff --git a/ansible/mataroa.service.j2 b/ansible/mataroa.service.j2 index 2fd2e83..993aee4 100644 --- a/ansible/mataroa.service.j2 +++ b/ansible/mataroa.service.j2 @@ -12,7 +12,7 @@ ExecReload=/bin/kill -HUP $MAINPID Environment="DOMAIN={{ domain }}" Environment="EMAIL={{ email }}" Environment="DEBUG={{ debug }}" -Environment="LOCALDEV_MODE={{ localdev_mode }}" +Environment="LOCALDEV={{ localdev }}" Environment="SECRET_KEY={{ secret_key }}" Environment="DATABASE_URL={{ database_url }}" Environment="EMAIL_HOST_USER={{ email_host_user }}" diff --git a/ansible/vars.yaml b/ansible/vars.yaml index 1ad1126..efaad82 100644 --- a/ansible/vars.yaml +++ b/ansible/vars.yaml @@ -3,7 +3,7 @@ domain: "{{ lookup('env', 'DOMAIN') }}" email: "{{ lookup('env', 'EMAIL') }}" debug: "{{ lookup('env', 'DEBUG') }}" -localdev_mode: "{{ lookup('env', 'LOCALDEV_MODE') }}" +localdev: "{{ lookup('env', 'LOCALDEV') }}" secret_key: "{{ lookup('env', 'SECRET_KEY') }}" diff --git a/mataroa/settings.py b/mataroa/settings.py index b2132ec..e7e71d4 100644 --- a/mataroa/settings.py +++ b/mataroa/settings.py @@ -27,7 +27,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = os.getenv("DEBUG") == "1" -LOCALDEV_MODE = os.getenv("LOCALDEV_MODE") == "1" +LOCALDEV = os.getenv("LOCALDEV") == "1" ALLOWED_HOSTS = [ "127.0.0.1", @@ -40,7 +40,7 @@ ADMINS = [("Theodore Keloglou", "zf@sirodoht.com")] CANONICAL_HOST = os.getenv("DOMAIN", "mataroa.blog") -if LOCALDEV_MODE: +if LOCALDEV: CANONICAL_HOST = "mataroalocal.blog:8000" @@ -176,7 +176,7 @@ # Email EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" -if LOCALDEV_MODE: +if LOCALDEV: EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" EMAIL_USE_TLS = True EMAIL_HOST = "smtp.postmarkapp.com" @@ -196,7 +196,7 @@ # Security middleware -if not LOCALDEV_MODE: +if not LOCALDEV: SECURE_CONTENT_TYPE_NOSNIFF = True X_FRAME_OPTIONS = "DENY" SESSION_COOKIE_SECURE = True From f06f356930ec2a75d3efb67cc6dd7478ea15e4f1 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 18:26:12 +0100 Subject: [PATCH 28/30] write new deployment documentation --- docs/src/deployment.md | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/src/deployment.md b/docs/src/deployment.md index d36c65e..9e8542a 100644 --- a/docs/src/deployment.md +++ b/docs/src/deployment.md @@ -1 +1,49 @@ # Deployment + +## Step 1: Ansible + +We use ansible to provision a Debian 12 Linux server. + +(1a) First, set up configuration files: + +```sh +cd ansible/ +# Make a copy of the example file +cp .envrc.example .envrc + +# Edit parameters as required +vim .envrc + +# Load variables into environment +source .envrc +``` + +(1b) Then, provision: + +```sh +ansible-playbook playbook.yaml -v +``` + +## Step 2: Wildcard certificates + +We use Automatic DNS API integration with DNSimple: + +https://github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dnsimple + +```sh +curl https://get.acme.sh | sh -s email=person@example.com +# Note: Installation inserts a cronjob for auto-renewal + +# Setup DNSimple API +echo 'export DNSimple_OAUTH_TOKEN="token-here"' >> /root/.acme.sh/acme.sh.env + +# Issue cert +acme.sh --issue --dns dns_dnsimple -d mataroa.blog -d *.mataroa.blog + +# We "install" (copy) the cert because we should not use the cert from acme.sh's internal store +acme.sh --install-cert -d mataroa.blog -d *.mataroa.blog --key-file /etc/caddy/mataroa-blog-key.pem --fullchain-file /etc/caddy/mataroa-blog-cert.pem --reloadcmd "chown caddy:www-data /etc/caddy/mataroa-blog-{cert,key}.pem && systemctl restart caddy" +``` + +Note: acme.sh's default SSL provider is ZeroSSL which does not accept email with +plus-subaddressing. It will not error gracefully, just fail with a cryptic +message (tested with acmesh v3.0.7). From 2152d8ea7e538e6fc5b5a8dd608d0fa563a05c13 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 30 Jun 2024 18:32:09 +0100 Subject: [PATCH 29/30] add cronjobs document --- docs/src/SUMMARY.md | 3 +-- docs/src/admin-moderation.md | 20 -------------------- docs/src/cronjobs.md | 14 ++++++++++++++ docs/src/deployment.md | 7 +++++++ 4 files changed, 22 insertions(+), 22 deletions(-) delete mode 100644 docs/src/admin-moderation.md create mode 100644 docs/src/cronjobs.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index bba1664..f56cd94 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -7,7 +7,6 @@ - [File Structure Walkthrough](./file-structure-walkthrough.md) - [Dependencies](./dependencies.md) - [Deployment](./deployment.md) -- [Server Playbook](./server-playbook.md) -- [Admin and Moderation](./admin-moderation.md) +- [Cronjobs](./cronjobs.md) - [Database Backup](./database-backup.md) - [Server Migration](./server-migration.md) diff --git a/docs/src/admin-moderation.md b/docs/src/admin-moderation.md deleted file mode 100644 index 7debcf8..0000000 --- a/docs/src/admin-moderation.md +++ /dev/null @@ -1,20 +0,0 @@ -# Admin and Moderation - -There are two kinds of dashboards on mataroa. - -## Django Admin Dashboard - -One is the built-in Django admin, visitable at `/dja/`. - -## Moderation Dashboard - -Second is the custom-built Moderation dashboard, visitable at: - -* `/mod/users/new/` -* `/mod/users/active/` -* `/mod/users/active-nonnew/` -* `/mod/posts/new/` -* `/mod/pages/new/` -* `/mod/comments/` - -et al, see "moderation pages" on [main/urls.py](main/urls.py). diff --git a/docs/src/cronjobs.md b/docs/src/cronjobs.md new file mode 100644 index 0000000..89f9958 --- /dev/null +++ b/docs/src/cronjobs.md @@ -0,0 +1,14 @@ +# Cronjobs + +Two every 5/10 minutes for notifications: + +``` +*/5 * * * * bash -c 'cd /var/www/mataroa && source .venv/bin/activate && source .envrc && python manage.py enqueue_notifications' +*/10 * * * * bash -c 'cd /var/www/mataroa && source .venv/bin/activate && source .envrc && python manage.py process_notifications' +``` + +One monthly for mail exports + +``` +0 0 * * * bash -c 'cd /var/www/mataroa && source .venv/bin/activate && source .envrc && python manage.py mail_exports' +``` diff --git a/docs/src/deployment.md b/docs/src/deployment.md index 9e8542a..0190b64 100644 --- a/docs/src/deployment.md +++ b/docs/src/deployment.md @@ -47,3 +47,10 @@ acme.sh --install-cert -d mataroa.blog -d *.mataroa.blog --key-file /etc/caddy/m Note: acme.sh's default SSL provider is ZeroSSL which does not accept email with plus-subaddressing. It will not error gracefully, just fail with a cryptic message (tested with acmesh v3.0.7). + +## Step 3: Cronjobs and Automated backups + +There are a few cronjobs that need setting up and, of course, backups are essential: + +* (3a) [Cronjobs](./cronjobs.md) +* (3b) [Database Backup](./database-backup.md) From caf2ec5ee4d4aff0d6908f905b007f3f58694af5 Mon Sep 17 00:00:00 2001 From: Theodore Keloglou Date: Sun, 14 Jul 2024 23:38:38 +0100 Subject: [PATCH 30/30] change ci lint to ruff --- .github/workflows/django-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/django-build.yml b/.github/workflows/django-build.yml index 1a59899..051290f 100644 --- a/.github/workflows/django-build.yml +++ b/.github/workflows/django-build.yml @@ -45,4 +45,4 @@ jobs: touch .envrc pip install -r requirements.dev.txt pip install -r requirements.txt - make lint + ruff check .