From 238bb38a6c393a3bc69df20c6bd02cd6c1ac5908 Mon Sep 17 00:00:00 2001 From: Lars Weiler Date: Sat, 7 Feb 2026 23:53:28 +0100 Subject: [PATCH] feat: Install 50ohm webserver, download the content and install the final, static website --- .ansible.cfg | 0 .gitignore | 177 ++++++++++++++++++ README.md | 16 ++ inventory.yml | 3 + requirements.yml | 5 + roles/base/tasks/main.yml | 5 + roles/base/tasks/packages.yml | 9 + roles/base/tasks/users.yml | 45 +++++ roles/build-50ohm/tasks/build.yml | 5 + roles/build-50ohm/tasks/main.yml | 5 + roles/build-50ohm/tasks/prepare.yml | 13 ++ .../install-sources/files/url_shortener.conf | 66 +++++++ roles/install-sources/tasks/main.yml | 43 +++++ roles/refresh-50ohm/files/refresh-50ohm.sh | 7 + roles/refresh-50ohm/tasks/main.yml | 30 +++ roles/refresh-50ohm/templates/service.j2 | 11 ++ roles/refresh-50ohm/templates/timer.j2 | 10 + site.yml | 38 ++++ users.yml | 13 ++ vars.yml | 77 ++++++++ 20 files changed, 578 insertions(+) create mode 100644 .ansible.cfg create mode 100644 .gitignore create mode 100644 README.md create mode 100644 inventory.yml create mode 100644 requirements.yml create mode 100644 roles/base/tasks/main.yml create mode 100644 roles/base/tasks/packages.yml create mode 100644 roles/base/tasks/users.yml create mode 100644 roles/build-50ohm/tasks/build.yml create mode 100644 roles/build-50ohm/tasks/main.yml create mode 100644 roles/build-50ohm/tasks/prepare.yml create mode 100644 roles/install-sources/files/url_shortener.conf create mode 100644 roles/install-sources/tasks/main.yml create mode 100644 roles/refresh-50ohm/files/refresh-50ohm.sh create mode 100644 roles/refresh-50ohm/tasks/main.yml create mode 100644 roles/refresh-50ohm/templates/service.j2 create mode 100644 roles/refresh-50ohm/templates/timer.j2 create mode 100644 site.yml create mode 100644 users.yml create mode 100644 vars.yml diff --git a/.ansible.cfg b/.ansible.cfg new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7e0986 --- /dev/null +++ b/.gitignore @@ -0,0 +1,177 @@ +.logs/* +*.retry +*.vault +collections/* +!collections/ansible_collections +!collections/requirements.yml +collections/ansible_collections/* +# https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# MacOS +.DS_Store + +# Ansible +.ansible/ + +# VS-Code +extensions.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..a5f4f87 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# Ansible Playbook zur Installation von 50ohm.de + +- Installiert die Code Repositories für 50ohm.de und das Content-Repository +- Initialisiert die Python Build-Umgebung +- Baut die Webseite erstmalig +- Konfiguriert Certbot und Nginx +- Installiert einen Systemd-Timer zum regelmäßigen Refresh + +## Voraussetzungen + +Wir verwenden ein Debian 12 System. Nur darauf ist der Code getestet. + +## TODO + +- Umbau auf Docker +- Verwendung von Webhooks statt eines Timers diff --git a/inventory.yml b/inventory.yml new file mode 100644 index 0000000..27efc53 --- /dev/null +++ b/inventory.yml @@ -0,0 +1,3 @@ +webservers: + hosts: + 50ohm.de: diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..1b628bc --- /dev/null +++ b/requirements.yml @@ -0,0 +1,5 @@ +roles: + - name: geerlingguy.certbot + version: ">=5.4.1" + - name: geerlingguy.nginx + version: ">=3.3.0" diff --git a/roles/base/tasks/main.yml b/roles/base/tasks/main.yml new file mode 100644 index 0000000..d4acc49 --- /dev/null +++ b/roles/base/tasks/main.yml @@ -0,0 +1,5 @@ +- name: Include tasks from users.yml + ansible.builtin.include_tasks: users.yml + +- name: Include tasks from packages.yml + ansible.builtin.include_tasks: packages.yml diff --git a/roles/base/tasks/packages.yml b/roles/base/tasks/packages.yml new file mode 100644 index 0000000..f5b7ed8 --- /dev/null +++ b/roles/base/tasks/packages.yml @@ -0,0 +1,9 @@ +- name: Install packages + ansible.builtin.package: + name: + - python3-venv + - python3-pip + - acl + - nginx + - uv + state: present diff --git a/roles/base/tasks/users.yml b/roles/base/tasks/users.yml new file mode 100644 index 0000000..f873571 --- /dev/null +++ b/roles/base/tasks/users.yml @@ -0,0 +1,45 @@ +- name: Ensure 'sudo' group exists + ansible.builtin.group: + name: sudo + state: present + +- name: Create users from users.yml + ansible.builtin.user: + name: "{{ item.name }}" + shell: "{{ item.shell | default('/bin/bash') }}" + password: "!" + update_password: on_create + groups: + - sudo + state: present + loop: "{{ users | flatten(levels=1)}}" + +- name: Add SSH keys for users + ansible.builtin.authorized_key: + user: "{{ item.name }}" + state: present + key: "{{ item.sshkeys }}" + loop: "{{ users | flatten(levels=1) }}" + +- name: Ensure sudo group has passwordless sudo access + ansible.builtin.lineinfile: + path: /etc/sudoers.d/sudo-nopasswd + state: present + create: true + line: "%sudo ALL=(ALL) NOPASSWD: ALL" + validate: '/usr/sbin/visudo -cf %s' + mode: '0440' + +- name: Ensure sudoers uses sudoers.d + ansible.builtin.lineinfile: + path: /etc/sudoers + state: present + line: "@includedir /etc/sudoers.d" + validate: '/usr/sbin/visudo -cf %s' + +- name: Ensure ex-users are removed + ansible.builtin.user: + name: "{{ item }}" + state: absent + remove: true + loop: "{{ ex_users | flatten(levels=1) }}" diff --git a/roles/build-50ohm/tasks/build.yml b/roles/build-50ohm/tasks/build.yml new file mode 100644 index 0000000..448a814 --- /dev/null +++ b/roles/build-50ohm/tasks/build.yml @@ -0,0 +1,5 @@ +- name: Run build.py in {{ destination_path }}/50ohm + ansible.builtin.command: uv run python3 ./build.py + args: + chdir: "{{ destination_path }}/50ohm" + become_user: "{{ fiftyohm_user }}" diff --git a/roles/build-50ohm/tasks/main.yml b/roles/build-50ohm/tasks/main.yml new file mode 100644 index 0000000..adfc2ca --- /dev/null +++ b/roles/build-50ohm/tasks/main.yml @@ -0,0 +1,5 @@ +- name: Run tasks from prepare.yml + ansible.builtin.include_tasks: prepare.yml + +- name: Run tasks from build.yml + ansible.builtin.include_tasks: build.yml diff --git a/roles/build-50ohm/tasks/prepare.yml b/roles/build-50ohm/tasks/prepare.yml new file mode 100644 index 0000000..9fa0baf --- /dev/null +++ b/roles/build-50ohm/tasks/prepare.yml @@ -0,0 +1,13 @@ +- name: Run uv venv in {{ destination_path }}/50ohm + ansible.builtin.command: uv venv + args: + chdir: "{{ destination_path }}/50ohm" + creates: "{{ destination_path }}/50ohm/.venv" + become_user: "{{ fiftyohm_user }}" + +- name: Install dependencies with uv pip in {{ destination_path }}/50ohm + ansible.builtin.command: uv pip sync requirements.txt + args: + chdir: "{{ destination_path }}/50ohm" + creates: "{{ destination_path }}/50ohm/.venv/lib/python3.*/site-packages/uv" + become_user: "{{ fiftyohm_user }}" diff --git a/roles/install-sources/files/url_shortener.conf b/roles/install-sources/files/url_shortener.conf new file mode 100644 index 0000000..f5cb454 --- /dev/null +++ b/roles/install-sources/files/url_shortener.conf @@ -0,0 +1,66 @@ +rewrite ^/vn01/?$ https://www.youtube.com/watch?v=WnOBk1UogjM&t=0s redirect; +rewrite ^/mw/?$ https://www.darc.de/mitgliedschaft/mitglied-werden/ redirect; +rewrite ^/rzp/?$ https://www.bundesnetzagentur.de/DE/Fachthemen/Telekommunikation/Frequenzen/SpezielleAnwendungen/Amateurfunk/DL_Vfg_AFu/Rufzeichenplan_10_24_Auszug_aus_Vfg_15_2025.pdf?__blob=publicationFile&v=3 redirect; +rewrite ^/rzl/?$ https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/Rufzeichenliste/rufzeichenliste_afu.html redirect; +rewrite ^/rza/?$ https://ans.bundesnetzagentur.de/Amateurfunk/Rufzeichen.aspx redirect; +rewrite ^/cll/?$ https://www.darc.de/der-club/referate/ausland/funken-im-ausland/cept-laenderliste/ redirect; +rewrite ^/ra/?$ https://www.darc.de/der-club/referate/ausland/ redirect; +rewrite ^/ww/?$ https://www.bundesnetzagentur.de/DE/Fachthemen/Telekommunikation/Technik/EMF/Standortbescheinigung/_functions/wattwaechter.html redirect; +rewrite ^/a1/?$ https://www.gesetze-im-internet.de/afuv_2005/anlage_1.html redirect; +rewrite ^/rnf/?$ https://www.darc.de/der-club/referate/notfunk/ redirect; +rewrite ^/vde-blitz/?$ https://www.vde.com/resource/blob/2001262/56f5576bbaf617b1e9e5195d1e8411d9/vde-information-blitzschutz-funkanlagen-download-data.pdf redirect; +rewrite ^/bfs/?$ https://www.bfs.de/DE/themen/emf/hff/wirkung/hff-nachgewiesen/hff-nachgewiesen.html redirect; +rewrite ^/hamnet/?$ https://hamnetdb.net/map.cgi redirect; +rewrite ^/sim/?$ https://afup.a36.de/pruefungen/pruefungen2.html redirect; +rewrite ^/dl-de/?$ http://www.govdata.de/dl-de/by-2-0 redirect; +rewrite ^/fs/?$ https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/Fragenkatalog/Pruefungsfragen.pdf?__blob=publicationFile&v=2#page=234 redirect; +rewrite ^/bp/?$ https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/Fragenkatalog/Pruefungsfragen.pdf?__blob=publicationFile&v=2#page=246 redirect; +rewrite ^/hm/?$ https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/AntraegeFormulare/Hilfsmittel_12062024.pdf?__blob=publicationFile&v=3 redirect; +rewrite ^/tr/?$ https://dd3ah.de/wp-content/uploads/2019/01/rechnen.pdf redirect; +rewrite ^/rs/?$ https://www.rohde-schwarz.com/ausbildung redirect; +rewrite ^/ajw/?$ https://ajw.darc.de redirect; +rewrite ^/wl/?$ https://www.wavelog.org redirect; +rewrite ^/wlv/?$ https://www.youtube.com/watch?v=G5mJjrKLJvE redirect; +rewrite ^/log/?$ https://log.darc.de redirect; +rewrite ^/buch/?$ https://darcverlag.de/DARC-Amateurfunklehrgang-Klasse-N redirect; +rewrite ^/fk/?$ https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/Fragenkatalog/Pruefungsfragen.pdf?__blob=publicationFile&v=2 redirect; +rewrite ^/geb/?$ https://www.bundesnetzagentur.de/DE/Beschlusskammern/BK02/BK2_01_Aktuell/Downloads/BK2_3_BMDVTKBGebV_download.pdf?__blob=publicationFile&v=4#page=12 redirect; +rewrite ^/wiki-dds/?$ https://de.wikipedia.org/wiki/Direct_Digital_Synthesis redirect; +rewrite ^/vfg33/?$ https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/AmtsblattverfuegungenAFu/Vfg332007Ver246ffentlicId10701pdf.pdf?__blob=publicationFile&v=4 redirect; +rewrite ^/acw/?$ https://youtu.be/iJ2udTxn3SU?si=VolNcnQxOR1VXpuO redirect; +rewrite ^/assb/?$ https://www.youtube.com/watch?v=NMKZfJSjkbQ redirect; +rewrite ^/itu/?$ https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/call_sign_series.aspx redirect; +rewrite ^/bemfv/?$ https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Verbraucher/ElektromagnetischeFelder/Anzeige_Afu/Erlaeuterung_der_Bewertungsverfahren_nach_BEMFV.pdf?__blob=publicationFile&v=1 redirect; +rewrite ^/BImSchV/?$ https://www.gesetze-im-internet.de/bimschv_26/ redirect; +rewrite ^/so/?$ https://www.bundesnetzagentur.de/DE/Allgemeines/DieBundesnetzagentur/AufgabenStruktur/Standorte/start.html redirect; +rewrite ^/ov/?$ https://www.darc.de/home/#c153658 redirect; +rewrite ^/k01/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894027/Kochen redirect; +rewrite ^/k02/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894047/Fuchsjagd redirect; +rewrite ^/k03/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894050/Rei�~_nagel+Löten redirect; +rewrite ^/k05/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894055/Filmabend redirect; +rewrite ^/k06/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894059/Technik+und+Natur redirect; +rewrite ^/k07/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894064/Schatzsuche redirect; +rewrite ^/k08/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894068/Astronomie redirect; +rewrite ^/k09/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894071/Experimentieren redirect; +rewrite ^/k10/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894074/Technikmuseum redirect; +rewrite ^/k11/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894077/Klasse+N+Kurs redirect; +rewrite ^/k12/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894085/Ausbildungsfunk redirect; +rewrite ^/t02/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894089/Fieldday redirect; +rewrite ^/t01/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894080/Escape+Room redirect; +rewrite ^/t03/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894092/HAMCAMP redirect; +rewrite ^/t04/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894097/3D+Druck redirect; +rewrite ^/t05/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894100/Klasse+E+Kurs redirect; +rewrite ^/t06/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894103/Programmieren redirect; +rewrite ^/t07/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894106/Contest redirect; +rewrite ^/t08/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894110/Planen redirect; +rewrite ^/t09/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894114/Elektronik+Projekt redirect; +rewrite ^/t10/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894117/Wandern redirect; +rewrite ^/t11/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894120/Hackathon redirect; +rewrite ^/e01/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894125/Klasse+A+Kurs redirect; +rewrite ^/e03/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894128/Vorträge redirect; +rewrite ^/e06/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894131/Raumfahrtprojekt redirect; +rewrite ^/e07/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894134/Wetterballon redirect; +rewrite ^/e09/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894141/SDR+Projekt redirect; +rewrite ^/e10/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894145/DX-Pedition redirect; +rewrite ^/e11/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894148/Notfunk redirect; +rewrite ^/e12/?$ https://confluence.darc.de/spaces/AJWCards/pages/183894151/Workshop redirect; diff --git a/roles/install-sources/tasks/main.yml b/roles/install-sources/tasks/main.yml new file mode 100644 index 0000000..ce14c97 --- /dev/null +++ b/roles/install-sources/tasks/main.yml @@ -0,0 +1,43 @@ +- name: Create destination directory {{ destination_path }} + ansible.builtin.file: + dest: "{{ destination_path }}" + state: directory + owner: "{{ fiftyohm_user }}" + group: "{{ fiftyohm_group }}" + mode: '0755' + +- name: Checkout 50ohm source from https://github.com/DARC-e-V/50ohm to {{ destination_path }}/ + ansible.builtin.git: + repo: https://github.com/DARC-e-V/50ohm.git + dest: "{{ destination_path }}/50ohm" + single_branch: true + version: refactor/migrate-from-directus-to-git + force: true + become_user: "{{ fiftyohm_user }}" + +- name: Checkout 50ohm-contents-dl from https://github.com/DARC-e-V/50ohm-contents-dl to {{ destination_path }} + ansible.builtin.git: + repo: https://github.com/DARC-e-V/50ohm-contents-dl.git + dest: "{{ destination_path }}/50ohm-contents-dl" + single_branch: true + version: HEAD + become_user: "{{ fiftyohm_user }}" + +- name: Create {{ destination_path }}/50ohm/config/config.json + ansible.builtin.copy: + dest: "{{ destination_path }}/50ohm/config/config.json" + content: > + { + "content_path": "../50ohm-contents-dl" + } + owner: "{{ fiftyohm_user }}" + group: "{{ fiftyohm_group }}" + mode: '0444' + +- name: Install url_shortener.conf in /srv/50ohm.de/url_shortener.conf + ansible.builtin.copy: + src: files/url_shortener.conf + dest: /srv/50ohm.de/url_shortener.conf + owner: "{{ fiftyohm_user }}" + group: "{{ fiftyohm_group }}" + mode: '0644' diff --git a/roles/refresh-50ohm/files/refresh-50ohm.sh b/roles/refresh-50ohm/files/refresh-50ohm.sh new file mode 100644 index 0000000..37e5c1e --- /dev/null +++ b/roles/refresh-50ohm/files/refresh-50ohm.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +git -C 50ohm pull +git -C 50ohm-contents-dl pull +cd 50ohm +uv run python3 ./build.py diff --git a/roles/refresh-50ohm/tasks/main.yml b/roles/refresh-50ohm/tasks/main.yml new file mode 100644 index 0000000..d4d9b0a --- /dev/null +++ b/roles/refresh-50ohm/tasks/main.yml @@ -0,0 +1,30 @@ +- name: Install refresh-50ohm.sh in {{ destination_path }}/refresh-50ohm.sh + ansible.builtin.copy: + src: files/refresh-50ohm.sh + dest: "{{ destination_path }}/refresh-50ohm.sh" + owner: "{{ fiftyohm_user }}" + group: "{{ fiftyohm_group }}" + mode: '0755' + +- name: Install systemd timer unit for 50ohm refresh in /etc/systemd/system/refresh-50ohm.timer + ansible.builtin.template: + src: templates/timer.j2 + dest: /etc/systemd/system/refresh-50ohm.timer + owner: root + group: root + mode: '0644' + +- name: Install systemd service unit for 50ohm refresh in /etc/systemd/system/refresh-50ohm.service + ansible.builtin.template: + src: templates/service.j2 + dest: /etc/systemd/system/refresh-50ohm.service + owner: root + group: root + mode: '0644' + +- name: Enable and start refresh-50ohm.timer + ansible.builtin.systemd: + name: refresh-50ohm.timer + enabled: true + state: started + daemon_reload: true diff --git a/roles/refresh-50ohm/templates/service.j2 b/roles/refresh-50ohm/templates/service.j2 new file mode 100644 index 0000000..6eaad14 --- /dev/null +++ b/roles/refresh-50ohm/templates/service.j2 @@ -0,0 +1,11 @@ +[Unit] +Description=Refresh 50ohm.de with a timer + +[Service] +Type=oneshot +ExecStart={{ destination_path }}/refresh-50ohm.sh +User={{ fiftyohm_user }} +WorkingDirectory={{ destination_path }}/ + +[Install] +WantedBy=multi-user.target diff --git a/roles/refresh-50ohm/templates/timer.j2 b/roles/refresh-50ohm/templates/timer.j2 new file mode 100644 index 0000000..ed7e06c --- /dev/null +++ b/roles/refresh-50ohm/templates/timer.j2 @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for refreshing 50ohm.de + +[Timer] +OnBootSec=5min +OnUnitAciveSec=15min +Unit=refresh-50ohm.service + +[Install] +WantedBy=timers.target diff --git a/site.yml b/site.yml new file mode 100644 index 0000000..c069a2b --- /dev/null +++ b/site.yml @@ -0,0 +1,38 @@ +# Installs the base system, builds & installs 50ohm server from source +- name: Install 50ohm server + hosts: webservers + become: true + vars_files: + - vars.yml + - users.yml + roles: + - base + - install-sources + - build-50ohm + tags: + - base + - build + +# Obtain a TLS certificate for 50ohm.de using geerlingguy.certbot & configure nginx using geerlingguy.nginx +- name: Configure TLS for 50ohm.de + hosts: webservers + become: true + vars_files: + - vars.yml + roles: + - geerlingguy.certbot + - geerlingguy.nginx + tags: + - webserver + +# Setup systemd-timer for 50ohm-contents-dl renewal & build of 50ohm +- name: Setup systemd timer for 50ohm-contents-dl renewal & build + hosts: webservers + become: true + vars_files: + - vars.yml + roles: + - refresh-50ohm + tags: + - build + - timer diff --git a/users.yml b/users.yml new file mode 100644 index 0000000..f0fc09c --- /dev/null +++ b/users.yml @@ -0,0 +1,13 @@ +ex_users: [] + +users: + - { + name: "dc4lw", + sshkeys: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGJQ5A3Ea1vKUh63Gkv6CyK2pIHbEBe8ggs+kwHi3F3h", + state: "present", + } + - { + name: "dl9mj", + sshkeys: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9fle0ZeS+KOrC+sY+uUQhn+BObbUHbFyaMXvCotACTGt0IBxA8gDG0SSCU/TlW69B4SJA0vgVVVGmXlYpqBx4RbeaPzDn0Ui8AAR5msn+eYWmGREDyQam1ZhFAlKyfU3efwbv7Uu0VeWzamwmrdihhUnsw+kvokZOH5LZzA/if0Yw7SV/hkU/QeAahciYSVTzZLzCmJFK6kMwgR9Doix/gjm69s5lOGvXldfm2LcMdiXdBFdKxG//z1Xn+69fWUg2LLilsz/cy4sGinCxpt5UQs3/VpR/JQO8rGhTEJno5vcFRVnMSv1Cp2VMh+2UXCQKSRRjKfOpsHyz8boFrEjr", + state: "present", + } diff --git a/vars.yml b/vars.yml new file mode 100644 index 0000000..9363ad7 --- /dev/null +++ b/vars.yml @@ -0,0 +1,77 @@ +fiftyohm_user: fiftyohm +fiftyohm_group: fiftyohm +destination_path: /srv/50ohm.de +50ohm_branch: main +50ohm_contents_dl_branch: main + +certbot_install_method: package +certbot_auto_renew: true +certbot_auto_renew_user: www-data +certbot_auto_renew_hour: "5" +certbot_auto_renew_minute: "15" +certbot_create_if_missing: true +certbot_create_method: webroot +certbot_admin_email: 50ohm@darc.de +certbot_certs: + - domains: + - 50ohm.de + - www.50ohm.de + webroot: "{{ destination_path }}/letsencrypt" + +nginx_listen_ipv6: true +nginx_remove_default_vhost: true +nginx_user: www-data +nginx_worker_processes: "{{ ansible_processor_vcpus|default(ansible_processor_count) }}" +nginx_worker_connections: "1024" +nginx_multi_accept: "off" +nginx_error_log: "/var/log/nginx/error.log warn" +nginx_accept_log: "/var/log/nginx/access.log main buffer=16k flush=2m" +nginx_vhosts: + - server_name: "50ohm.de" + listen: "443 ssl http2" + filename: 50ohm-https.conf + root: "{{ destination_path }}/50ohm/build" + index: "index.html" + state: "present" + extra_parameters: | + location "/" { + try_files $uri $uri/ =404; + } + # The old website from July 2025 + location "/past" { + rewrite ^/past$ /past/ permanent; + alias /var/www/50ohm.de/; + try_files $uri $uri/ =404; + } + # Set to a different path for testing purposes + location "/future" { + rewrite ^/future$ /future/ permanent; + alias {{ destination_path }}/50ohm/build/; + try_files $uri $uri/ =404; + } + + ssl_certificate /etc/letsencrypt/live/50ohm.de/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/50ohm.de/privkey.pem; + include /srv/50ohm.de/url_shortener.conf; + - server_name: "www.50ohm.de" + listen: "443 ssl http2" + filename: 50ohm-https-redirect.conf + state: "present" + extra_parameters: | + ssl_certificate /etc/letsencrypt/live/50ohm.de/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/50ohm.de/privkey.pem; + return 301 https://50ohm.de$request_uri; + - server_name: "50ohm.de" + listen: "80" + filename: 50ohm-http.conf + server_name_redirect: "www.50ohm.de" + root: "{{ destination_path }}/50ohm/build" + state: "present" + extra_parameters: | + # Add the letsencrypt webroot for certbot challenges + location "/.well-known/acme-challenge/" { + root {{ destination_path }}/letsencrypt; + } + location "/" { + return 301 https://50ohm.de$request_uri; + }