diff --git a/.gitignore b/.gitignore index b138555..665563f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules/ dist/ .astro/ build/ +__pycache__/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f83df1c..b7e5819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 0.1.5 – 2026-10-23 + +Pages for Update Gaps, Security Monitor, Status Board and Sharewerk, and the versions of today. + +- **Four new project pages** in English and German, each with what it does, security, installation + and questions: Update Gaps and Security Monitor for Cockpit with screenshots, Status Board for + Cockpit without (its screenshots show real host names), and Sharewerk, which shows its app sign + like Lautwerk and says what Meta's terms of use and the rights of a post's author mean for it. + The projects page, the start page and the links between project pages include them. +- **Versions:** Cron Jobs 2.10.2, Image Update Monitor 0.25.1, Stellwerk 0.6.4, Update Gaps 0.7.1, + Security Monitor 0.3.1, Status Board 0.2.3 and Sharewerk 0.1.1. The build reads them from + GitHub, so the live site shows what was current when its release was built; the README now says + that new versions go live with the next website release. +- **Cron Jobs:** the page title names the product without "for Cockpit", like Image Update + Monitor's. +- **Design system:** tokens and component styles from commit 5f4b256; the tokens differ only in a + comment, the components add image previews. +- **README:** every place a new project page needs. +- **Repository:** a Python cache file under `deploy/` is gone, and `__pycache__/` is ignored. + ## 0.1.4 – 2026-10-19 - **Privacy texts in German and English:** describe scroll depth and active time, distinguish daily diff --git a/README.md b/README.md index 4266628..293da5b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ public yet is named anywhere. | --- | --- | | `src/content/tools/{en,de}/.md` | A project page: frontmatter with every section's text, the installation in Markdown below it. The schema is in `src/content.config.ts`. | | `src/content/legal/{en,de}/` | Legal notice and privacy policy. The German versions are binding. | -| `src/data/tools.ts` | The projects: names, category, status, license, screenshots. | +| `src/data/tools.ts` | The projects: names, category, status, license, screenshots or app sign. | | `src/data/routes.mjs` | Every page pair by key; canonical, `hreflang`, language switch and sitemap use it. | | `src/data/versions.json` | The latest release of each project; `npm run versions` updates it from GitHub. | | `src/i18n/ui.ts` | Labels of the interface in both languages. | @@ -44,17 +44,35 @@ public yet is named anywhere. ### A new project page -1. Add the project to `TOOL_SLUGS` in `src/data/routes.mjs`, to the `slug` list in - `src/content.config.ts` and to `TOOLS` in `src/data/tools.ts`, with its screenshots under - `src/assets/screenshots//`. -2. Write `src/content/tools/en/.md` and `src/content/tools/de/.md`. -3. `npm run build`. +1. `src/data/routes.mjs`: the slug in `TOOL_SLUGS`. +2. `src/content.config.ts`: the slug in the `slug` list. +3. `src/data/tools.ts`: the slug in `ToolSlug` and an entry in `TOOLS`, where its place sets the order on + the site. `name` sets the product name as the design system does: `dot: true` for the gold dot + ("Cron Jobs."), `suffix` for the part in italics ("Image Update *Monitor*"). Screenshots go under + `src/assets/screenshots//`; a project without any gets its app sign from `src/assets/icons/` + as `icon`. A new `category` also needs `CATEGORY_ORDER` and the group titles in + `src/components/ProjectsPage.astro`. +4. `src/data/related.ts`: an entry in `PAIRS`, and the slug in the entries of the projects that + belong with it. +5. `scripts/versions.mjs`: the repository in `REPOS`; `npm run versions` then adds it to + `src/data/versions.json`. +6. `src/components/ProjectsPage.astro`: how it is installed (`install`, in both languages). Check + whether the descriptions of the projects page and of the start page (`HomePage.astro`) and the + start page's lead still name what there is. +7. Write `src/content/tools/en/.md` and `src/content/tools/de/.md`: a title of 10 to 60 + and a description of 50 to 155 characters, an `alt` text for every picture key (`icon` for the + app sign). +8. `npm run build`. `scripts/check-dist.mjs` then checks the page pair, the lengths and the links. ### A new version of a project Nothing to do in the texts: `npm run build` reads the latest releases from GitHub. Commit the updated `src/data/versions.json` with the next change, so a build without network shows the same. +The live site shows the versions its release was built with: it changes only with a new release of +the website (see Releases). A project's new release therefore reaches azentrius.com with the next +website release, not before. + ## Releases Actions › **release** › Run workflow, on `main`, after giving the version in `package.json` a dated diff --git a/deploy/__pycache__/azentrius-website.cpython-313.pyc b/deploy/__pycache__/azentrius-website.cpython-313.pyc deleted file mode 100644 index 3152524..0000000 Binary files a/deploy/__pycache__/azentrius-website.cpython-313.pyc and /dev/null differ diff --git a/package-lock.json b/package-lock.json index 708f87f..47f876b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "azentrius-website", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "azentrius-website", - "version": "0.1.4", + "version": "0.1.5", "license": "Apache-2.0", "dependencies": { "@astrojs/sitemap": "3.7.4", diff --git a/package.json b/package.json index 2ae4d21..e2e0019 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "azentrius-website", - "version": "0.1.4", + "version": "0.1.5", "private": true, "description": "The website azentrius.com: project pages for the Azentrius tools, in English and German.", "license": "Apache-2.0", diff --git a/scripts/versions.mjs b/scripts/versions.mjs index 9e56f5f..385fd9b 100644 --- a/scripts/versions.mjs +++ b/scripts/versions.mjs @@ -8,8 +8,12 @@ const FILE = new URL("../src/data/versions.json", import.meta.url); const REPOS = { "cockpit-cronjobs": "Azentrius/cockpit-cronjobs", "cockpit-image-update-monitor": "Azentrius/cockpit-image-update-monitor", + "cockpit-update-gaps": "Azentrius/cockpit-update-gaps", + "cockpit-security-monitor": "Azentrius/cockpit-security-monitor", + "cockpit-status-board": "Azentrius/cockpit-status-board", stellwerk: "Azentrius/stellwerk", lautwerk: "Azentrius/lautwerk", + sharewerk: "Azentrius/sharewerk", "home-assistant-theme": "Azentrius/home-assistant-theme", }; diff --git a/src/assets/icons/sharewerk.svg b/src/assets/icons/sharewerk.svg new file mode 100644 index 0000000..63d54f4 --- /dev/null +++ b/src/assets/icons/sharewerk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/screenshots/cockpit-security-monitor/containers.png b/src/assets/screenshots/cockpit-security-monitor/containers.png new file mode 100644 index 0000000..9578630 Binary files /dev/null and b/src/assets/screenshots/cockpit-security-monitor/containers.png differ diff --git a/src/assets/screenshots/cockpit-security-monitor/exposure-dark.png b/src/assets/screenshots/cockpit-security-monitor/exposure-dark.png new file mode 100644 index 0000000..08438a0 Binary files /dev/null and b/src/assets/screenshots/cockpit-security-monitor/exposure-dark.png differ diff --git a/src/assets/screenshots/cockpit-security-monitor/exposure.png b/src/assets/screenshots/cockpit-security-monitor/exposure.png new file mode 100644 index 0000000..6fad956 Binary files /dev/null and b/src/assets/screenshots/cockpit-security-monitor/exposure.png differ diff --git a/src/assets/screenshots/cockpit-security-monitor/mark-dialog.png b/src/assets/screenshots/cockpit-security-monitor/mark-dialog.png new file mode 100644 index 0000000..337b0c3 Binary files /dev/null and b/src/assets/screenshots/cockpit-security-monitor/mark-dialog.png differ diff --git a/src/assets/screenshots/cockpit-security-monitor/ssh.png b/src/assets/screenshots/cockpit-security-monitor/ssh.png new file mode 100644 index 0000000..e2190d9 Binary files /dev/null and b/src/assets/screenshots/cockpit-security-monitor/ssh.png differ diff --git a/src/assets/screenshots/cockpit-update-gaps/accepted.png b/src/assets/screenshots/cockpit-update-gaps/accepted.png new file mode 100644 index 0000000..f615f21 Binary files /dev/null and b/src/assets/screenshots/cockpit-update-gaps/accepted.png differ diff --git a/src/assets/screenshots/cockpit-update-gaps/overview-dark.png b/src/assets/screenshots/cockpit-update-gaps/overview-dark.png new file mode 100644 index 0000000..789c8d4 Binary files /dev/null and b/src/assets/screenshots/cockpit-update-gaps/overview-dark.png differ diff --git a/src/assets/screenshots/cockpit-update-gaps/overview.png b/src/assets/screenshots/cockpit-update-gaps/overview.png new file mode 100644 index 0000000..bd8e6e6 Binary files /dev/null and b/src/assets/screenshots/cockpit-update-gaps/overview.png differ diff --git a/src/assets/screenshots/cockpit-update-gaps/upkeep.png b/src/assets/screenshots/cockpit-update-gaps/upkeep.png new file mode 100644 index 0000000..68faaba Binary files /dev/null and b/src/assets/screenshots/cockpit-update-gaps/upkeep.png differ diff --git a/src/components/HomePage.astro b/src/components/HomePage.astro index 243f7ce..a2df8ee 100644 --- a/src/components/HomePage.astro +++ b/src/components/HomePage.astro @@ -27,10 +27,10 @@ const text = { en: { title: "Azentrius – open-source tools for self-hosters", description: - "Open-source tools for your infrastructure and devices: Cockpit add-ons for cron and Docker updates, a desk display for Claude Code and Codex, and more.", + "Open-source tools for your infrastructure and devices: Cockpit add-ons for cron, updates and security, a desk display for Claude Code and Codex, and more.", eyebrow: "Digital sovereignty", h1: "Software you own", - lead: "Open-source tools for your own infrastructure and devices: add-ons for Cockpit, a desk display for Claude Code and Codex, an Android voice app and a theme for Home Assistant. Local control, transparent dependencies: each project page says what it needs and what it talks to.", + lead: "Open-source tools for your own infrastructure and devices: add-ons for Cockpit, a desk display for Claude Code and Codex, an Android voice app, a self-hosted tool for passing on Instagram and Facebook posts, and a theme for Home Assistant. Local control, transparent dependencies: each project page says what it needs and what it talks to.", toProjects: "View projects", toPackages: "Set up the package repository", facts: [ @@ -65,10 +65,10 @@ const text = { de: { title: "Azentrius – Open-Source-Werkzeuge für Self-Hoster", description: - "Open-Source-Werkzeuge für eigene Server und Geräte: Cockpit-Add-ons für Cron und Docker-Updates, ein Tischdisplay für Claude Code und Codex und mehr.", + "Open-Source-Werkzeuge für eigene Server und Geräte: Cockpit-Add-ons für Cron, Updates und Sicherheit, ein Tischdisplay für Claude Code und Codex und mehr.", eyebrow: "Digitale Souveränität", h1: "Software, die dir gehört", - lead: "Open-Source-Werkzeuge für deine eigene Infrastruktur und deine Geräte: Erweiterungen für Cockpit, ein Tischdisplay für Claude Code und Codex, eine Sprach-App für Android und ein Theme für Home Assistant. Kontrolle bei dir, Abhängigkeiten offen benannt: Jede Projektseite sagt, was ein Projekt braucht und womit es spricht.", + lead: "Open-Source-Werkzeuge für deine eigene Infrastruktur und deine Geräte: Erweiterungen für Cockpit, ein Tischdisplay für Claude Code und Codex, eine Sprach-App für Android, ein selbst gehostetes Werkzeug zum Weitergeben von Instagram- und Facebook-Beiträgen und ein Theme für Home Assistant. Kontrolle bei dir, Abhängigkeiten offen benannt: Jede Projektseite sagt, was ein Projekt braucht und womit es spricht.", toProjects: "Projekte ansehen", toPackages: "Paketquelle einrichten", facts: [ diff --git a/src/components/ProjectsPage.astro b/src/components/ProjectsPage.astro index 9188b24..d2a4f30 100644 --- a/src/components/ProjectsPage.astro +++ b/src/components/ProjectsPage.astro @@ -21,7 +21,7 @@ const text = { en: { title: "Open-source Cockpit add-ons and developer tools | Azentrius", description: - "Azentrius projects: Cockpit add-ons for cron and Docker updates, a Claude Code and Codex desk display, an Android voice app and a Home Assistant theme.", + "Azentrius projects: Cockpit add-ons for cron, updates and security, a desk display for Claude Code and Codex, tools for Android and Home Assistant.", h1: "Projects", lead: "Everything Azentrius makes is open source under Apache-2.0 and public on GitHub. Each page says what a project needs and what it talks to.", groups: { @@ -35,15 +35,19 @@ const text = { install: { "cockpit-cronjobs": "Package repository, release", "cockpit-image-update-monitor": "Package repository, release", + "cockpit-update-gaps": "Package repository (Debian, Ubuntu), release", + "cockpit-security-monitor": "Package repository (Debian, Ubuntu), release", + "cockpit-status-board": "Package repository, release", stellwerk: "Release", lautwerk: "Build from source", + sharewerk: "Docker Compose", "home-assistant-theme": "HACS, release", }, }, de: { title: "Cockpit-Add-ons und Werkzeuge für Entwickler | Azentrius", description: - "Azentrius-Projekte: Cockpit-Add-ons für Cron und Docker-Updates, ein Tischdisplay für Claude Code und Codex, eine Sprach-App und ein Home-Assistant-Theme.", + "Azentrius-Projekte: Cockpit-Add-ons für Cron, Updates und Sicherheit, ein Tischdisplay für Claude Code und Codex, Werkzeuge für Android und Home Assistant.", h1: "Projekte", lead: "Alles, was Azentrius baut, ist Open Source unter Apache-2.0 und öffentlich auf GitHub. Jede Seite sagt, was ein Projekt braucht und womit es spricht.", groups: { @@ -57,8 +61,12 @@ const text = { install: { "cockpit-cronjobs": "Paketquelle, Release", "cockpit-image-update-monitor": "Paketquelle, Release", + "cockpit-update-gaps": "Paketquelle (Debian, Ubuntu), Release", + "cockpit-security-monitor": "Paketquelle (Debian, Ubuntu), Release", + "cockpit-status-board": "Paketquelle, Release", stellwerk: "Release", lautwerk: "Aus dem Quellcode", + sharewerk: "Docker Compose", "home-assistant-theme": "HACS, Release", }, }, diff --git a/src/components/ToolPage.astro b/src/components/ToolPage.astro index 5e2993c..395482d 100644 --- a/src/components/ToolPage.astro +++ b/src/components/ToolPage.astro @@ -11,7 +11,6 @@ import { tool as findTool, TOOLS, repoUrl } from "../data/tools"; import { t } from "../i18n/ui"; import versions from "../data/versions.json"; import { SITE } from "../data/routes.mjs"; -import lautwerkIcon from "../assets/icons/lautwerk.svg"; interface Props { entry: CollectionEntry<"tools">; @@ -78,7 +77,8 @@ const ogImage = og } : undefined; // A project without screenshots shows its app icon next to the hero text. -const showIcon = !tool.hero && tool.slug === "lautwerk"; +const icon = tool.hero ? undefined : tool.icon; +const showIcon = Boolean(icon); --- { - showIcon && ( + icon && (
- {d.alt.icon + {d.alt.icon
) } diff --git a/src/content.config.ts b/src/content.config.ts index 4842c02..aa45da7 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -22,8 +22,12 @@ const tools = defineCollection({ slug: z.enum([ "cockpit-cronjobs", "cockpit-image-update-monitor", + "cockpit-update-gaps", + "cockpit-security-monitor", + "cockpit-status-board", "stellwerk", "lautwerk", + "sharewerk", "home-assistant-theme", ]), lang: z.enum(["en", "de"]), diff --git a/src/content/tools/de/cockpit-cronjobs.md b/src/content/tools/de/cockpit-cronjobs.md index 5a0cd4a..03f2b5c 100644 --- a/src/content/tools/de/cockpit-cronjobs.md +++ b/src/content/tools/de/cockpit-cronjobs.md @@ -1,7 +1,7 @@ --- slug: cockpit-cronjobs lang: de -title: Cron Jobs für Cockpit – Cronjobs und systemd-Timer verwalten +title: "Cron Jobs: Cronjobs und systemd-Timer in Cockpit verwalten" description: "Cockpit-Seite für cron: alle Cronjobs und systemd-Timer an einem Ort, sichere Crontab-Änderungen, Ergebnis jedes Laufs, Umwandeln in systemd-Timer." eyebrow: Cockpit-Add-on h1: Cronjobs und systemd-Timer in Cockpit verwalten @@ -58,7 +58,7 @@ alt: primaryAction: label: Cron Jobs installieren href: "#install" -updated: 2026-10-19 +updated: 2026-10-23 --- ### Aus der Azentrius-Paketquelle diff --git a/src/content/tools/de/cockpit-security-monitor.md b/src/content/tools/de/cockpit-security-monitor.md new file mode 100644 index 0000000..5318417 --- /dev/null +++ b/src/content/tools/de/cockpit-security-monitor.md @@ -0,0 +1,104 @@ +--- +slug: cockpit-security-monitor +lang: de +title: "Security Monitor: was ist von wo erreichbar (Cockpit)" +description: "Cockpit-Add-on: welche Ports Internet, VPN oder privates Netz erreichen, auch Docker-Ports an UFW vorbei, wer sich anmeldet und was Container schwächt." +eyebrow: Cockpit-Add-on +h1: Was von wo erreichbar ist, wer hereinkommt, was die Container schwächt +lead: "Für jeden Port: ob eine neue Verbindung aus dem Internet, dem VPN, dem privaten Netz oder nur vom Server selbst hereinkommt, für IPv4 und IPv6, und welche Regel entscheidet. Es liest UFW, nftables und iptables und die Ports, die Docker an UFW vorbei weiterleitet." +summary: Je Port, von wo er erreichbar ist und welche Regel entscheidet, dazu SSH, Anmeldungen, Container-Härtung, CrowdSec und fail2ban. +platforms: ["Cockpit", "Debian 12+", "Ubuntu 22.04+"] +problemTitle: UFW ist an, und der Port ist trotzdem offen. +problem: + - "Docker leitet die Ports, die es veröffentlicht, an UFW vorbei: Eine Regel, die den Port sperrt, erreicht den Container dahinter nicht." + - "Die Firewall-Seite von Cockpit zeigt weder UFW noch die Ports, die Docker daran vorbei weiterleitet." + - "Ein fail2ban-Jail, das nur bei INPUT sperrt, erreicht keinen Port, den Docker an einen Container weiterleitet." +features: + - title: Erreichbarkeit je Port + text: "Jeder lauschende Socket und jeder Port, den Docker veröffentlicht: erreichbar aus dem Internet, dem VPN, dem privaten Netz oder nur von diesem Host, je IPv4 und IPv6, mit der Regel oder Richtlinie, die entscheidet." + - title: SSH-Konfiguration und Schlüssel + text: "Die wirksame Konfiguration, wie sshd -T sie ausgibt, und die autorisierten Schlüssel jedes Kontos mit Login-Shell: Typ, Größe, Fingerabdruck, Kommentar und Optionen." + - title: Anmeldungen der letzten 14 Tage + text: "Erfolgreiche Anmeldungen mit Quelle, Konto und Methode und fehlgeschlagene Versuche je Quelle, aus dem Journal. Eine Anmeldung von außerhalb des VPN und der privaten Netze ist eine Warnung." + - title: Container-Härtung + text: "Der eingebundene Docker-Socket, privilegierte Container, Host-PIDs, zusätzliche Capabilities, beschreibbare Host-Ordner, das Host-Netz und Container, die als root oder ohne no-new-privileges laufen." + - title: CrowdSec und fail2ban + text: "Wenn installiert: Dienst, Bouncer und Entscheidungen von CrowdSec; bei fail2ban, was jedes Jail beobachtet, wen es sperrt und wo eine Sperre nicht greift." + - title: Als erwartet markiert + text: "Ein Port, der öffentlich sein soll, oder ein Container, der den Docker-Socket braucht, lässt sich mit einer Notiz als erwartet markieren. Er bleibt sichtbar und hebt den Zustand nicht mehr an." +explainer: + title: Wie es einen Port bewertet + intro: "„In Ordnung“ heißt, dass in dem, was die Seite prüft, nichts gefunden wurde, nie, dass der Server sicher ist. Was sie nicht lesen kann, ist „Nicht beurteilbar“, nie „In Ordnung“." + head: ["Port", "Bewertung"] + rows: + - ["Eine Datenbank, die Docker-API, Cockpit oder SSH offen zum Internet", "Gefahr"] + - ["Alles andere, das offen zum Internet ist", "Achtung, bis du es als erwartet markierst"] + - ["Web (80, 443), WireGuard, der DHCP-Client", "Hinweis"] + - ["Nur von manchen Adressen erreichbar", "Hinweis"] + - ["Von der Hetzner Cloud Firewall gesperrt (optional, mit einem Token nur zum Lesen)", "In Ordnung"] + - ["Von einer Regel entschieden, die die Seite nicht lesen kann", "Nicht beurteilbar"] +security: + - "Nur lesend: Es ändert keine Firewall-Regel und nichts an CrowdSec oder fail2ban. Die Seite ändert nur die eigene regelmäßige Prüfung und die eigene Liste der als erwartet markierten Befunde." + - "Die Prüfung läuft als root ohne Netzwerkzugang außer dem Loopback, mit eingeschränkten Capabilities, und schreibt nur ihren eigenen Ordner." + - "Docker wird nur mit GET gefragt, fail2ban nur, was es ausführt und wen es sperrt." + - "Das Hetzner-Token nutzt ein eigener Dienstbenutzer; es erreicht nie Code, der als root läuft, und nie den Browser." + - "Adressen, Benutzernamen und Schlüsselkommentare liegen in einer Datei, die nur root lesen kann. Das Status Board sieht Zahlen, Zustände, Ports und die Namen von Diensten, Containern und Jails." +requirements: + - "Debian 12 oder neuer oder Ubuntu 22.04 oder neuer, mit systemd" + - "Cockpit 264 oder neuer" + - "Python 3.8 oder neuer (nur die Standardbibliothek) und iproute2" + - "Gelesen, wenn vorhanden: iptables, nftables, UFW, Docker, OpenSSH, CrowdSec, fail2ban" +faq: + - q: Ändert es Firewall-Regeln? + a: "Nein. Die Seite sagt, welche Regel fehlt; du setzt sie von Hand." + - q: Warum ist ein Port offen, obwohl UFW an ist? + a: "Docker leitet die Ports, die es veröffentlicht, an UFW vorbei. Die Seite folgt dem Paketfilter nach Dockers DNAT und nennt die Regel, die entscheidet." + - q: Heißt „In Ordnung“, dass der Server sicher ist? + a: "Nein. Es heißt, dass in dem, was die Seite prüft, nichts gefunden wurde. Jeder Reiter sagt, was er nicht prüft, etwa Firewalls außerhalb des Servers, ausgehende Verbindungen und Schwachstellen in Images." + - q: Welche Systeme werden unterstützt? + a: "Debian 12 und neuer und Ubuntu 22.04 und neuer. Fedora, RHEL und openSUSE werden noch nicht unterstützt, und die Paketquelle bietet das Add-on nur für Debian und Ubuntu an." + - q: Was ist mit Cloud-Firewalls? + a: "Die Hetzner Cloud Firewall liest es mit einem optionalen API-Token, das nur lesen darf. Andere Cloud-Firewalls, Router und Portweiterleitungen außerhalb des Servers werden nicht geprüft." + - q: Kann es Sperren von fail2ban aufheben? + a: "Noch nicht. Es zeigt fail2ban; Jails einrichten und Sperren aufheben folgen in einer späteren Version." +compare: "Die Firewall-Seite von Cockpit zeigt weder UFW noch die Ports, die Docker daran vorbei weiterleitet. Security Monitor folgt jeder Regel, die eine neue Verbindung durchläuft, und sagt, von wo jeder Port erreichbar ist. Es liest nur: Die Seite nennt eine fehlende Regel, du setzt sie. Fehlende Updates sind Sache von Update Gaps, Container-Versionen die von Image Update Monitor." +alt: + exposure: "Security Monitor in Cockpit: die Übersicht und jeder Port mit seiner Erreichbarkeit, ein Docker-Port an UFW vorbei offen zum Internet" + ssh: "SSH: die wirksame Konfiguration, wie sshd -T sie ausgibt, jede Einstellung bewertet, darunter die autorisierten Schlüssel" + containers: "Container: was ihre Grenze zum Host schwächt, vom eingebundenen Docker-Socket bis AppArmor ohne Profil" + mark-dialog: "Port 8080/tcp mit einer Notiz als erwartet markieren: Die Seite schreibt nur ihre eigene Datei, nie eine Firewall-Regel" +primaryAction: + label: Security Monitor installieren + href: "#install" +updated: 2026-10-23 +--- + +### Aus der Azentrius-Paketquelle + +Für Debian und Ubuntu. Richte die Paketquelle einmal ein: + +```sh +curl -fsSLO https://packages.azentrius.com/azentrius-repository.deb +sudo apt install ./azentrius-repository.deb +sudo apt update +``` + +Installiere dann **Security Monitor** in Cockpit unter **Anwendungen** oder auf der Konsole: + +```sh +sudo apt install cockpit-security-monitor +``` + +Die Updates deines Systems halten es aktuell. Installiere es auf jedem Server, den du in Cockpit ansiehst, und öffne die Seite einmal mit Administratorrechten: Sie prüft den Server dann von selbst. Richte dort die regelmäßige Prüfung ein, damit der Zustand und das Status Board aktuell bleiben. + +### Aus den Dateien eines Releases + +Jedes [Release](https://github.com/Azentrius/cockpit-security-monitor/releases) enthält das `.deb`, `SHA256SUMS` und einen signierten Build-Nachweis. Prüfe beides vor der Installation: + +```sh +sha256sum --ignore-missing -c SHA256SUMS +gh attestation verify cockpit-security-monitor_X.Y.Z-1_all.deb --repo Azentrius/cockpit-security-monitor +sudo apt install ./cockpit-security-monitor_X.Y.Z-1_all.deb +``` + +Die Hetzner Cloud Firewall, Markierungen von Hand und die Deinstallation: siehe [README](https://github.com/Azentrius/cockpit-security-monitor#install). diff --git a/src/content/tools/de/cockpit-status-board.md b/src/content/tools/de/cockpit-status-board.md new file mode 100644 index 0000000..8c3f234 --- /dev/null +++ b/src/content/tools/de/cockpit-status-board.md @@ -0,0 +1,106 @@ +--- +slug: cockpit-status-board +lang: de +title: "Status Board: Add-ons aller Hosts auf einer Cockpit-Seite" +description: "Cockpit-Seite für den Host, der die anderen erreicht: eine Zeile je Host des Host-Umschalters, eine Kachel je Azentrius-Add-on. Nur lesend." +eyebrow: Cockpit-Add-on +h1: Der Zustand aller Hosts auf einer Seite +lead: "Eine Zeile je Host des Host-Umschalters von Cockpit, eine Kachel je Azentrius-Add-on, etwa Cron Jobs, Image Update Monitor, Update Gaps und Security Monitor. Es gehört auf den Cockpit-Host, von dem aus die anderen erreicht werden, und liest nur; ein Klick auf eine Kachel öffnet das Add-on auf seinem Host." +summary: Der Zustand der Azentrius-Add-ons auf jedem Host des Host-Umschalters von Cockpit, eine Zeile je Host, eine Kachel je Add-on. +platforms: ["Cockpit", "Debian & Ubuntu", "Fedora & RHEL"] +problemTitle: Jedes Add-on auf jedem Host ist eine eigene Seite. +problem: + - "Jedes Add-on zeigt seinen Zustand auf seinem eigenen Host. Um alles zu sehen, öffnest du jedes Add-on auf jedem Host." + - "Ein Add-on, das auf einem Host fehlt, oder ein Update, das dort vergessen wurde, übersieht man leicht." + - "Ein Host, der nicht antwortet, sollte das sagen, statt unauffällig auszusehen." +features: + - title: Eine Zeile je Host + text: "In der Reihenfolge des Host-Umschalters, dieser Host zuerst, mit dem schwersten Zustand seiner Add-ons oder dem Grund, warum sich der Host nicht lesen lässt." + - title: Eine Kachel je Add-on + text: "Sein Zustand, seine wichtigste Zahl, seine Zusammenfassung und das Alter seiner Daten. Ein Klick öffnet das Add-on auf seinem Host." + - title: Lücken fallen auf + text: "Die Kacheln stehen auf jedem Host in derselben Reihenfolge: Ein Add-on, das auf einem Host fehlt, bekommt dort eine Kachel „Nicht installiert“, und eine Kachel sagt, wenn auf einem anderen Host eine neuere Version läuft." + - title: Jeder Eintrag + text: "Alle Einträge eines Add-ons klappen in einer Tabelle unter der Zeile auf. Ein Eintrag mit einer Stelle im Add-on öffnet es dort." + - title: Nur Auffälliges + text: "Ein Schalter in der Kopfzeile blendet die Kacheln aus, die keine Aufmerksamkeit brauchen. Der Browser merkt sich die Wahl." + - title: Aktuell ohne dein Zutun + text: "Es lädt beim Öffnen, bei „Aktualisieren“ und alle 5 Minuten, solange die Seite sichtbar ist. Daten, die älter sind, als das Add-on erlaubt, machen die Kachel zur Warnung." +explainer: + title: Was eine Kachel sagen kann + intro: "Eine Kachel „In Ordnung“ heißt, dass das Add-on in dem, was es prüft, nichts gefunden hat, nicht, dass der Host sicher ist." + head: ["Anzeige", "Bedeutung"] + rows: + - ["In Ordnung, Hinweis, Achtung, Problem, Unbekannt", "Der Zustand des Add-ons selbst, in der Statussprache, die alle Azentrius-Add-ons teilen"] + - ["Nicht installiert", "Das Add-on läuft auf einem anderen Host, aber nicht auf diesem"] + - ["Kein Status", "Die Version des Add-ons auf diesem Host kennt den Status-Vertrag noch nicht"] + - ["Kein Zugriff", "Ohne Administratorzugriff auf diesem Host hat das Add-on nichts zu melden"] + - ["Status nicht lesbar", "Die Antwort passt nicht zum Vertrag; die Kachel nennt den Grund"] + - ["Nicht erreichbar, Schlüssel gesperrt", "Der Host hat nicht geantwortet, oder der SSH-Schlüssel ist gesperrt"] +security: + - "Nur lesend: Es führt den Status-Befehl jedes Add-ons aus, fragt nach keinen Administratorrechten und ändert auf keinem Host etwas." + - "Status-Befehle laufen nur aus /usr/lib/cockpit-… und immer mit status --lang en oder de; andere Argumente aus einem Manifest werden ignoriert." + - "Was ein Host sendet, sind Daten: gegen den Status-Vertrag geprüft und nur als Text gezeigt. Ein kompromittierter Host kann einen falschen Zustand melden, aber keinen Code in der Sitzung ausführen." + - "Die Seite lädt nichts aus dem Netz: Schriften und Symbole bringt sie selbst mit." +requirements: + - "Auf dem Host mit dem Board: Cockpit mit dem Host-Umschalter, entwickelt mit Cockpit 360" + - "Um ein Add-on auf einem anderen Host per Klick zu öffnen: AllowMultiHost in Cockpit" + - "Auf den anderen Hosts: cockpit-bridge, eine Anmeldung per SSH-Schlüssel und die Add-ons" + - "Add-ons mit Status-Vertrag: Cron Jobs 2.8.1, Image Update Monitor 0.20.0, Update Gaps 0.1.0, Security Monitor 0.1.0 oder neuer" +faq: + - q: Wo installiere ich es? + a: "Auf dem Cockpit-Host, von dem aus die anderen erreicht werden, etwa einer Bastion. Die anderen Hosts brauchen nur die Add-ons." + - q: Braucht es Administratorrechte auf den anderen Hosts? + a: "Nein. Jedes Add-on meldet, was es ohne root lesen kann; für Hosts, die per Schlüssel erreicht werden, ist das der Normalfall." + - q: Benachrichtigt es mich? + a: "Nein. Es lädt nur, solange die Seite offen ist, und benachrichtigt niemanden." + - q: Sucht es nach neuen Releases? + a: "Nein. Es vergleicht die Versionen, die auf den Hosts laufen, miteinander, damit ein vergessenes Update auffällt." + - q: Welche Hosts zeigt es? + a: "Die aus der Liste des Host-Umschalters in /etc/cockpit/machines.d. Ein Host, der ohne Administratorrechte hinzugefügt wurde und den der Umschalter nur für eine Browsersitzung behält, steht nicht auf dem Board." + - q: Speichert es Daten? + a: "Nein, auf keinem Host. Nur der Browser merkt sich den Schalter „Nur Auffälliges“." +compare: "Status Board ist kein Monitoring-System: Es speichert keine Daten, verschickt keine Warnungen und lädt nur, solange die Seite offen ist. Es erreicht die Hosts über die eigenen SSH-Verbindungen des Host-Umschalters; sie brauchen nur cockpit-bridge, eine Anmeldung per Schlüssel und die Add-ons." +alt: {} +primaryAction: + label: Status Board installieren + href: "#install" +updated: 2026-10-23 +--- + +Installiere das Board auf dem Host mit dem Host-Umschalter; die anderen Hosts brauchen nur die Add-ons. + +### Aus der Azentrius-Paketquelle + +Für Debian, Ubuntu, Fedora und RHEL. Richte die Paketquelle einmal ein: + +```sh +# Debian und Ubuntu +curl -fsSLO https://packages.azentrius.com/azentrius-repository.deb +sudo apt install ./azentrius-repository.deb +sudo apt update + +# Fedora und RHEL +sudo rpm --import https://packages.azentrius.com/azentrius.asc +sudo dnf install https://packages.azentrius.com/azentrius-repository.rpm +``` + +Installiere dann **Status Board** in Cockpit unter **Anwendungen** oder auf der Konsole: + +```sh +sudo apt install cockpit-status-board # Debian, Ubuntu +sudo dnf install cockpit-status-board # Fedora, RHEL +``` + +Die Updates deines Systems halten es aktuell. Status Board erscheint im Menü von Cockpit bei der Übersicht; wenn noch nicht, melde dich neu bei Cockpit an. + +### Aus den Dateien eines Releases + +Unter openSUSE ist das der einzige Weg. Jedes [Release](https://github.com/Azentrius/cockpit-status-board/releases) enthält `.deb`, `.rpm`, `SHA256SUMS` und einen signierten Build-Nachweis. Prüfe beides vor der Installation: + +```sh +sha256sum --ignore-missing -c SHA256SUMS +gh attestation verify --repo Azentrius/cockpit-status-board +``` + +Das `.rpm` eines Releases trägt keine Paketsignatur, deshalb braucht `zypper` die Option `--allow-unsigned-rpm`; die beiden Prüfungen treten an ihre Stelle. Einzelheiten stehen im [README](https://github.com/Azentrius/cockpit-status-board#install-update-uninstall). diff --git a/src/content/tools/de/cockpit-update-gaps.md b/src/content/tools/de/cockpit-update-gaps.md new file mode 100644 index 0000000..0969caa --- /dev/null +++ b/src/content/tools/de/cockpit-update-gaps.md @@ -0,0 +1,105 @@ +--- +slug: cockpit-update-gaps +lang: de +title: "Update Gaps: fehlende Updates und warum (Cockpit)" +description: "Cockpit-Add-on: wo einem Server Updates fehlen, obwohl Software-Updates keine zeigt, etwa gehaltene Pakete oder Fixes nur mit Ubuntu Pro, und warum." +eyebrow: Cockpit-Add-on +h1: Die Updates finden, die Software-Updates nicht anzeigt +lead: "Gehaltene Pakete, Fixes nur mit Ubuntu Pro, ein ausstehender Neustart, ein Kernel-Update, dem in /boot der Platz ausging: Zu jedem Befund sagt die Seite, was fehlt, woher die Angabe stammt, warum Software-Updates in Cockpit es nicht zeigt und was du tun kannst." +summary: Wo einem Server Updates fehlen, obwohl Software-Updates keine zeigt, und zu jedem Befund, warum und was du tun kannst. +platforms: ["Cockpit", "Debian 12+", "Ubuntu 22.04+"] +problemTitle: Keine Updates heißt nicht aktuell. +problem: + - "Ein gehaltenes Paket aktualisiert apt nie, und Software-Updates listet es nicht." + - "Ist der letzte Signaturschlüssel einer Paketquelle abgelaufen, liest apt diese Quelle nicht mehr, und ihre Updates fallen aus jeder Liste. Nur apt update warnt." + - "Ein Kernel-Update, dem in /boot der Platz ausgeht, bleibt auf halbem Weg stehen und lässt dpkg halb fertig zurück. Software-Updates meldet nur, dass es gescheitert ist." +features: + - title: Was Software-Updates auslässt + text: "Gehaltene Pakete, Fixes nur mit Ubuntu Pro, ein ausstehender Neustart, CPU-Schwachstellen laut Kernel, Firmware (mit fwupd), Snaps, die nicht aktualisiert werden, Pakete ohne Paketquelle, Backports, Software außerhalb des Paketmanagers und das Ende der Unterstützung." + - title: Wenn die Pflege schiefging + text: "Pakete, die dpkg halb fertig liegen ließ, zu wenig Platz in /boot für den nächsten Kernel, abgelaufene Signaturschlüssel, alte Paketlisten, schrittweise verteilte Updates, an denen Software-Updates scheitert, und was der letzte Lauf der automatischen Updates getan hat." + - title: Warum, und was du tun kannst + text: "Jede Karte sagt, warum Software-Updates es nicht zeigt, was du tun kannst und woher die Daten stammen. Befehle stehen zum Kopieren für ein Terminal bereit; die Seite installiert nichts." + - title: Seit wann + text: "Ein Befund, den schon eine frühere Prüfung sah, sagt, seit wann es ihn gibt. Die Seite sagt immer, wie alt ihre Daten sind und wann apt zuletzt seine Paketlisten aktualisiert hat." + - title: Für eine Weile quittieren + text: "Mit Administratorrechten lässt sich ein Befund, der so sein soll, bis zu einem Tag deiner Wahl quittieren, höchstens 90 Tage im Voraus, auf Wunsch mit Grund. Die Seite zeigt ihn weiter; der Status zählt ihn nicht mehr." + - title: Netzdaten, wenn du willst + text: "Einmal eingerichtet, holt ein Dienst ohne Root-Rechte einmal am Tag Sicherheitslücken, die Ubuntu noch nicht behoben hat, Fixes, die die Projekte selbst veröffentlicht haben, und neuere Versionen anderswo in Ubuntu." +explainer: + title: Warum Software-Updates sie nicht zeigt + intro: "Einige der Bereiche, die das Add-on prüft, und warum Software-Updates in Cockpit sie übersieht. Ein leerer Abschnitt heißt nie „sicher“: Die Seite nennt, was sie nicht geprüft hat." + head: ["Bereich", "Warum Software-Updates es nicht zeigt"] + rows: + - ["Gehaltene Pakete", "Ein gehaltenes Paket aktualisiert apt nie, und PackageKit listet es nicht."] + - ["Fixes nur mit Ubuntu Pro", "Ohne Ubuntu Pro hat apt keine Quelle für esm-apps und esm-infra."] + - ["Neustart ausstehend", "Unter Debian und Ubuntu sagt Cockpit nicht, wann ein Neustart aussteht."] + - ["Schrittweise verteilte Updates (Ubuntu)", "Software-Updates listet sie, aber die Installation scheitert an ihnen und an jedem anderen Update, das mit ihnen kommt."] + - ["Signaturschlüssel der Paketquellen", "Ist der letzte Schlüssel einer Quelle abgelaufen, liest apt sie nicht mehr; nur apt update warnt."] + - ["Ende der Unterstützung", "Cockpit zeigt nicht, wann ein Release keine Updates mehr bekommt."] +security: + - "Nur lesend: Die Prüfung führt nie apt update aus und installiert, entfernt oder startet nichts neu. Die Seite kann nur die eigene regelmäßige Prüfung und die Netzdaten ein- und ausschalten und Befunde quittieren." + - "Jede Prüfung läuft als gehärteter systemd-Dienst ohne Netzwerkzugang, auch wenn du auf „Aktualisieren“ klickst." + - "Netzdaten gibt es erst, wenn du sie einrichtest, von einem eigenen Dienst ohne Root-Rechte. Was den Server verlässt: der Name des Release, die Namen ausgewählter Quellpakete und welche aus einer festen Liste von Projekten installiert sind." + - "Zugangsdaten in den Adressen der Paketquellen werden aus dem Zustand entfernt, den jeder lokale Benutzer lesen kann." + - "Der Browser stellt keine externen Anfragen: Die Schriften liefert das Add-on mit." +requirements: + - "Debian 12 oder neuer oder Ubuntu 22.04 oder neuer, mit systemd" + - "Cockpit 264 oder neuer" + - "Python 3.8 oder neuer (nur die Standardbibliothek)" + - "Optional, genutzt, wenn vorhanden: needrestart, ubuntu-pro-client, distro-info-data, unattended-upgrades, gpg, fwupd" +faq: + - q: Installiert es Updates? + a: "Nein. Es liest nur. Wo eine Karte Befehle nennt, sind sie zum Kopieren in ein Terminal gedacht." + - q: Heißt eine leere Seite, dass der Server sicher ist? + a: "Nein. Ein leerer Abschnitt heißt nie „sicher“: Die Seite sagt immer, was sie nicht geprüft hat, was ausgelassen wurde und wie alt ihre Daten sind." + - q: Welche Systeme prüft es? + a: "Debian 12 und neuer und Ubuntu 22.04 und neuer. Fedora, RHEL und openSUSE werden noch nicht geprüft, und die Paketquelle bietet das Add-on nur für Debian und Ubuntu an." + - q: Sendet es Daten irgendwohin? + a: "Nur wenn du die Netzdaten einrichtest. Dann geht einmal am Tag der Name des Release an die Sicherheitsdaten von Canonical, die Namen ausgewählter Quellpakete an Launchpad und welche aus einer festen Liste von Projekten installiert sind an GitHub." + - q: Kann ich einen bekannten Befund ausblenden? + a: "Ja, mit Administratorrechten: Quittiere ihn bis zu einem Tag höchstens 90 Tage im Voraus. Er bleibt auf der Seite und zählt nach diesem Tag wieder, oder sobald er sich auf eine Weise ändert, die zählt. Manche Befunde, etwa ein ausstehender Neustart, lassen sich nicht quittieren." + - q: Prüft es Container-Images? + a: "Nein. Image Update Monitor zeigt die Versionen deiner Container." + - q: Brauche ich es auf jedem Server? + a: "Ja, auf jedem Server, den du in Cockpit ansiehst, auch hinter einer Cockpit-Bastion. Status Board zeigt den Zustand aller auf einer Seite." +compare: "Software-Updates vergleicht die installierten Pakete mit den Paketquellen. Update Gaps sieht sich an, was dieser Vergleich auslässt, und den Zustand des Systems drumherum. Es ändert von sich aus nichts. Container-Images sind Sache von Image Update Monitor, was von wo erreichbar ist, die von Security Monitor." +alt: + overview: "Update Gaps in Cockpit: Befunde in sieben Bereichen auf einem Server mit gehaltenen Paketen, Fixes nur mit Ubuntu Pro und einem ausstehenden Neustart" + upkeep: "Pflege, die schiefging: ein Kernel-Paket, das dpkg halb konfiguriert liegen ließ, und zu wenig Platz in /boot, mit den Befehlen, die es abschließen" + accepted: "Gehaltene Docker-Pakete, quittiert bis zum Wartungsfenster: weiter sichtbar, im Status nicht mehr gezählt" +primaryAction: + label: Update Gaps installieren + href: "#install" +updated: 2026-10-23 +--- + +### Aus der Azentrius-Paketquelle + +Für Debian und Ubuntu. Richte die Paketquelle einmal ein: + +```sh +curl -fsSLO https://packages.azentrius.com/azentrius-repository.deb +sudo apt install ./azentrius-repository.deb +sudo apt update +``` + +Installiere dann **Update Gaps** in Cockpit unter **Anwendungen** oder auf der Konsole: + +```sh +sudo apt install cockpit-update-gaps +``` + +Die Updates deines Systems halten es aktuell. Installiere es auf jedem Server, den du in Cockpit ansiehst, und öffne die Seite einmal mit Administratorrechten: Sie prüft den Server dann von selbst. Richte dort die regelmäßige Prüfung ein und, wenn du willst, die Netzdaten. + +### Aus den Dateien eines Releases + +Jedes [Release](https://github.com/Azentrius/cockpit-update-gaps/releases) enthält das `.deb`, `SHA256SUMS` und einen signierten Build-Nachweis. Prüfe beides vor der Installation: + +```sh +sha256sum --ignore-missing -c SHA256SUMS +gh attestation verify cockpit-update-gaps_X.Y.Z-1_all.deb --repo Azentrius/cockpit-update-gaps +sudo apt install ./cockpit-update-gaps_X.Y.Z-1_all.deb +``` + +Unterstützte Systeme, Einstellungen und Deinstallation: siehe [README](https://github.com/Azentrius/cockpit-update-gaps#install-update-uninstall). diff --git a/src/content/tools/de/sharewerk.md b/src/content/tools/de/sharewerk.md new file mode 100644 index 0000000..15452ba --- /dev/null +++ b/src/content/tools/de/sharewerk.md @@ -0,0 +1,112 @@ +--- +slug: sharewerk +lang: de +title: "Sharewerk: Instagram- und Facebook-Beiträge zum Weitergeben" +description: "Selbst gehostet, mit Web-App für Android: Teile einen Instagram- oder Facebook-Beitrag und bekomm Bilder, Video-Standbilder, Transkript und Text zurück." +eyebrow: Selbst gehostet, für Android +h1: Einen Beitrag teilen, ihn als sauberes Paket zurückbekommen +lead: "Teile einen Instagram- oder Facebook-Beitrag von deinem Android-Telefon an Sharewerk und bekomm jedes Bild eines Karussells, Standbilder und ein Transkript bei Videos und die Bildunterschrift als Text zurück. Gib es dann an eine KI-Chat-App, einen Messenger oder alles andere im Teilen-Menü weiter." +summary: Ein selbst gehosteter Dienst mit Web-App für Android, der aus einem geteilten Beitrag Bilder, Standbilder, ein Transkript und Text macht. +platforms: ["Docker Compose", "Android mit Chrome", "Instagram & Facebook"] +notice: "Ein persönliches Projekt, veröffentlicht, falls es anderen nützt. Ohne Support-Zusage: Es kann jederzeit brechen, wenn Instagram oder Facebook etwas ändern." +problemTitle: Keine Screenshots mehr von jeder Folie. +problem: + - "Ein Karussell weiterzugeben heißt, von jeder Folie einen Screenshot zu machen, ein Reel, den Bildschirm aufzuzeichnen. Sharewerk holt den Beitrag selbst: seine Bilder, die Bildunterschrift als Text und bei Videos Standbilder und das Gesprochene." +features: + - title: Aus dem Teilen-Menü + text: "Aus Chrome installiert, erscheint Sharewerk im Teilen-Menü von Android. Das Telefon schickt nur den Link; Herunterladen und Aufbereiten geschehen auf deinem Server." + - title: Bilder, die sich lesen lassen + text: "Jedes Bild als JPEG mit 1568 px an der langen Kante: scharf genug, um Text zu lesen, klein genug, um es schnell zu teilen." + - title: Videos als Standbilder und Text + text: "Standbilder bei Szenenwechseln und ein Transkript mit Zeitmarken, erstellt mit ffmpeg und faster-whisper auf deinem Server." + - title: Der ganze Beitrag in einem Teilen + text: "Eine post.txt mit Quelle, Autor, Datum, Bildunterschrift und einem Verzeichnis aller Bilder. Android nimmt höchstens 10 Dateien pro Teilen; mehr Bilder werden zu nummerierten Kontaktbögen zusammengefasst." + - title: Dein Server, deine Anmeldung + text: "Ein eigenes Zugangstoken, oder keins hinter einem anmeldenden Proxy wie Pomerium, oauth2-proxy oder Authelia. Auf Deutsch und Englisch, hell und dunkel." + - title: Aktuell gehalten + text: "Instagram und Facebook ändern sich ständig. Das Image wird jeden Montag mit den neuesten Versionen von gallery-dl und yt-dlp neu gebaut; ein Update ist ein Pull." +keeps: + title: Cookies, Nutzungsbedingungen und Rechte + text: "Ausgeloggten Besuchern zeigt Instagram fast nichts, deshalb braucht Sharewerk die Cookies eines angemeldeten Kontos. Nimm ein Zweitkonto: Automatisierter Zugriff auf Instagram und Facebook verstößt gegen die Nutzungsbedingungen von Meta, und so genutzte Konten können gedrosselt oder gesperrt werden. Der Inhalt eines Beitrags gehört seinem Urheber. Sharewerk ist ein Werkzeug für den persönlichen Gebrauch, und du bist dafür verantwortlich, wie du es nutzt." +security: + - "Die Downloader bekommen nur Links auf einer Liste erlaubter Instagram- und Facebook-Hosts, damit sich der Server nicht für andere oder interne Adressen einspannen lässt." + - "Der Container läuft als Benutzer ohne root, mit schreibgeschütztem Root-Dateisystem und ohne Linux-Capabilities." + - "Die Cookie-Datei ist eine angemeldete Sitzung: Behandle sie wie ein Passwort. Nur der Container-Benutzer kann sie lesen." + - "Ergebnisse werden standardmäßig nach 24 Stunden gelöscht, oder sofort aus der Liste der zuletzt aufbereiteten Beiträge." + - "Betreib es nie als offenen Dienst für andere: Die Cookies sind deine, und damit auch die Verantwortung für das, was mit ihnen heruntergeladen wird." + - "Die Container-Images tragen einen signierten Build-Nachweis." +requirements: + - "Ein Server mit Docker und Docker Compose; 2 CPU-Kerne und 3 GB RAM reichen gut" + - "Eine Domain mit HTTPS davor: Web-Apps lassen sich nur von sicheren Adressen installieren" + - "Ein Android-Telefon mit Chrome; das iPhone wird nicht unterstützt" + - "Für Instagram: die Cookies eines Zweitkontos" +faq: + - q: Funktioniert es auf dem iPhone? + a: "Nein. Safari unterstützt die Web Share Target API nicht, deshalb kann eine Web-App nicht im Teilen-Menü von iOS erscheinen." + - q: Warum braucht es Cookies? + a: "Ausgeloggten Besuchern zeigt Instagram fast nichts. Nimm ein Zweitkonto, nicht dein Hauptkonto. Facebook-Videos funktionieren oft ohne Cookies." + - q: Wo wird ein Beitrag verarbeitet? + a: "Auf deinem Server. Das Telefon schickt nur den Link; der Server lädt den Beitrag herunter, bereitet ihn auf und löscht die Ergebnisse standardmäßig nach 24 Stunden." + - q: Was tun, wenn Downloads scheitern? + a: "Meist haben Instagram oder Facebook etwas geändert, und eine neuere Version von gallery-dl oder yt-dlp behebt es. Hol das Image neu: Es wird jede Woche neu gebaut." + - q: Gibt es eine App zum Herunterladen? + a: "Nein. Sharewerk ist eine Web-App: Du öffnest deine Sharewerk-Adresse in Chrome und installierst sie über das Menü von Chrome." +alt: + icon: "Das App-Symbol von Sharewerk: zwei gestapelte Karten, auf der vorderen ein Pfeil nach außen, dazu ein Punkt, in Gold auf Tinte" +primaryAction: + label: Sharewerk einrichten + href: "#install" +notes: + - "Instagram und Facebook sind Marken von Meta Platforms, Inc., Android von Google LLC. Sharewerk ist ein unabhängiges Projekt und nicht mit Meta oder Google verbunden." + - "Das Sharewerk-Zeichen ist eine Marke von Azentrius und steht nicht unter der Apache-Lizenz." +updated: 2026-10-23 +--- + +### Auf deinem Server + +Mit Docker und Docker Compose: + +```sh +git clone https://github.com/Azentrius/sharewerk.git +cd sharewerk +cp .env.example .env +sed -i "s/^SHAREWERK_AUTH_TOKEN=.*/SHAREWERK_AUTH_TOKEN=$(openssl rand -hex 32)/" .env +mkdir -p secrets +docker compose up -d +``` + +Sharewerk lauscht dann auf `127.0.0.1:8080`, aus dem fertigen Image `ghcr.io/azentrius/sharewerk:latest`. Stell einen Reverse-Proxy mit TLS davor, zum Beispiel Caddy: + +```caddyfile +sharewerk.example.com { + reverse_proxy 127.0.0.1:8080 +} +``` + +Das erste Video, das du aufbereitest, lädt das Sprachmodell von Whisper (etwa 500 MB für `small`) in das Datenvolume. + +### Cookies für Instagram + +Melde dich in einem eigenen Browserprofil bei einem Zweitkonto an, exportiere dessen Cookies im Netscape-Format `cookies.txt` und schließe das Profil, ohne dich abzumelden. Kopiere die Datei auf den Server, leg sie für den Container-Benutzer ab und lösche die Kopie: + +```sh +sudo install -o 10001 -g 10001 -m 600 cookies.txt secrets/cookies.txt +shred -u cookies.txt +``` + +Lösche den Export auch auf deinem Rechner. Meldet Sharewerk „login required“, exportiere die Cookies neu. Das [README](https://github.com/Azentrius/sharewerk#cookies) erklärt jeden Schritt. + +### Auf dem Telefon + +1. Öffne deine Sharewerk-Adresse in **Chrome** und melde dich mit dem Token aus `.env` an. +2. Wähle im Menü von Chrome **App installieren**. +3. Tippe in Instagram auf **Teilen** und wähle **Sharewerk**. Ist das Paket fertig, tippe auf **Teilen** und wähle die App, an die es gehen soll. + +### Aktualisieren + +```sh +docker compose pull && docker compose up -d +gh attestation verify oci://ghcr.io/azentrius/sharewerk:latest --repo Azentrius/sharewerk +``` + +Hinter Pomerium oder einem anderen anmeldenden Proxy, alle Einstellungen und Fehlersuche: siehe [README](https://github.com/Azentrius/sharewerk#readme). diff --git a/src/content/tools/en/cockpit-cronjobs.md b/src/content/tools/en/cockpit-cronjobs.md index ee8372b..727cc36 100644 --- a/src/content/tools/en/cockpit-cronjobs.md +++ b/src/content/tools/en/cockpit-cronjobs.md @@ -1,7 +1,7 @@ --- slug: cockpit-cronjobs lang: en -title: Cron Jobs for Cockpit – manage cron and systemd timers +title: "Cron Jobs: manage cron and systemd timers in Cockpit" description: "Open-source Cockpit page for cron: every job and systemd timer in one place, safe crontab edits, run history, run now, convert to systemd timers." eyebrow: Cockpit add-on h1: Manage cron jobs and systemd timers in Cockpit @@ -58,7 +58,7 @@ alt: primaryAction: label: Install Cron Jobs href: "#install" -updated: 2026-10-19 +updated: 2026-10-23 --- ### From the Azentrius package repository diff --git a/src/content/tools/en/cockpit-security-monitor.md b/src/content/tools/en/cockpit-security-monitor.md new file mode 100644 index 0000000..ccc1c79 --- /dev/null +++ b/src/content/tools/en/cockpit-security-monitor.md @@ -0,0 +1,104 @@ +--- +slug: cockpit-security-monitor +lang: en +title: "Security Monitor: what is reachable from where (Cockpit)" +description: "Cockpit add-on: which ports the internet, VPN or private network reach, including Docker's past UFW, who logs in and what weakens containers." +eyebrow: Cockpit add-on +h1: What is reachable from where, who logs in, what weakens the containers +lead: "For every port: whether a new connection gets in from the internet, the VPN, the private network or only the server itself, for IPv4 and IPv6, and which rule decides. It reads UFW, nftables and iptables, and the ports Docker forwards past UFW." +summary: Per port where it is reachable from and which rule decides, plus SSH, logins, container hardening, CrowdSec and fail2ban. +platforms: ["Cockpit", "Debian 12+", "Ubuntu 22.04+"] +problemTitle: UFW is on, and the port is open anyway. +problem: + - "Docker forwards the ports it publishes past UFW: a rule that blocks the port does not reach the container behind it." + - "Cockpit's own firewall page does not show UFW, nor the ports Docker forwards past it." + - "A fail2ban jail that bans only at INPUT does not reach a port Docker forwards to a container." +features: + - title: Exposure per port + text: "Every listening socket and every port Docker publishes: reachable from the internet, the VPN, the private network or this host, per IPv4 and IPv6, with the rule or policy that decides." + - title: SSH configuration and keys + text: "The effective configuration as sshd -T prints it, and the authorized keys of every account with a login shell: type, size, fingerprint, comment and options." + - title: Logins of 14 days + text: "Successful logins with source, account and method, and failed attempts per source, from the journal. A login from outside the VPN and private networks is a warning." + - title: Container hardening + text: "The Docker socket mounted, privileged containers, host PIDs, extra capabilities, writable host folders, the host network, and containers that run as root or without no-new-privileges." + - title: CrowdSec and fail2ban + text: "When installed: CrowdSec's service, bouncers and decisions; for fail2ban what each jail watches, whom it bans and where a ban does not take effect." + - title: Marked as expected + text: "A port that is meant to be public, or a container that needs the Docker socket, can be marked as expected with a note. It stays visible and no longer raises the state." +explainer: + title: How it judges a port + intro: "OK means that nothing was found in what the page checks, never that the server is safe. What it cannot read is “Not assessable”, never OK." + head: ["Port", "Assessment"] + rows: + - ["A database, Docker's API, Cockpit or SSH open to the internet", "Danger"] + - ["Anything else open to the internet", "Warning, until you mark it as expected"] + - ["Web (80, 443), WireGuard, the DHCP client", "Note"] + - ["Reachable only from some addresses", "Note"] + - ["Blocked by the Hetzner Cloud Firewall (optional, with a read-only token)", "OK"] + - ["Decided by a rule the page cannot read", "Not assessable"] +security: + - "Read only: it changes no firewall rule and nothing in CrowdSec or fail2ban. The page changes only its own regular check and its own list of findings marked as expected." + - "The scan runs as root without network access except the loopback, with a reduced set of capabilities, and writes only its own folder." + - "Docker is asked with GET only, fail2ban only what it runs and whom it bans." + - "The Hetzner token is used by a service user of its own and never reaches root code or the browser." + - "Addresses, user names and key comments stay in a file only root can read. The Status Board sees numbers, states, ports and the names of services, containers and jails." +requirements: + - "Debian 12 or newer, or Ubuntu 22.04 or newer, with systemd" + - "Cockpit 264 or newer" + - "Python 3.8 or newer (standard library only) and iproute2" + - "Read when present: iptables, nftables, UFW, Docker, OpenSSH, CrowdSec, fail2ban" +faq: + - q: Does it change firewall rules? + a: "No. The page says which rule is missing; you set it by hand." + - q: Why does it say a port is open although UFW is on? + a: "Docker forwards the ports it publishes past UFW. The page follows the packet filter after Docker's DNAT and names the rule that decides." + - q: Does OK mean the server is safe? + a: "No. OK means that nothing was found in what the page checks. Every tab says what it does not check, such as firewalls outside the server, outgoing connections and vulnerabilities in images." + - q: Which systems are supported? + a: "Debian 12 and newer and Ubuntu 22.04 and newer. Fedora, RHEL and openSUSE are not supported yet, and the package repository serves the add-on for Debian and Ubuntu only." + - q: What about cloud firewalls? + a: "The Hetzner Cloud Firewall is read with an optional read-only API token. Other cloud firewalls, routers and port forwarding outside the server are not checked." + - q: Can it lift fail2ban bans? + a: "Not yet. It shows fail2ban; setting up jails and lifting bans from the page follow in a later version." +compare: "Cockpit's own firewall page does not show UFW or the ports Docker forwards past it. Security Monitor follows every rule a new connection passes and says from where each port is reachable. It only reads: the page names a missing rule, you set it. Missing updates are for Update Gaps, container versions for Image Update Monitor." +alt: + exposure: "Security Monitor in Cockpit: the overview and every port with where it is reachable from, one Docker port open to the internet past UFW" + ssh: "SSH: the effective configuration as sshd -T prints it, each setting assessed, and the authorized keys below" + containers: "Containers: what weakens their boundary to the host, from the Docker socket mounted to AppArmor unconfined" + mark-dialog: "Marking port 8080/tcp as expected with a note: the page writes only its own file, never a firewall rule" +primaryAction: + label: Install Security Monitor + href: "#install" +updated: 2026-10-23 +--- + +### From the Azentrius package repository + +For Debian and Ubuntu. Set up the repository once: + +```sh +curl -fsSLO https://packages.azentrius.com/azentrius-repository.deb +sudo apt install ./azentrius-repository.deb +sudo apt update +``` + +Then install **Security Monitor** in Cockpit under **Applications**, or on the console: + +```sh +sudo apt install cockpit-security-monitor +``` + +The system's updates keep it current. Install it on every server you look at in Cockpit, then open the page once with administrative access: it checks the server by itself. Set up the regular check there to keep the state, and the Status Board, current. + +### From the files of a release + +Every [release](https://github.com/Azentrius/cockpit-security-monitor/releases) has the `.deb`, `SHA256SUMS` and a signed build provenance. Check both before you install: + +```sh +sha256sum --ignore-missing -c SHA256SUMS +gh attestation verify cockpit-security-monitor_X.Y.Z-1_all.deb --repo Azentrius/cockpit-security-monitor +sudo apt install ./cockpit-security-monitor_X.Y.Z-1_all.deb +``` + +The Hetzner Cloud Firewall, marks by hand and uninstalling: see the [README](https://github.com/Azentrius/cockpit-security-monitor#install). diff --git a/src/content/tools/en/cockpit-status-board.md b/src/content/tools/en/cockpit-status-board.md new file mode 100644 index 0000000..bf649fb --- /dev/null +++ b/src/content/tools/en/cockpit-status-board.md @@ -0,0 +1,106 @@ +--- +slug: cockpit-status-board +lang: en +title: "Status Board: every host's add-ons on one Cockpit page" +description: "Cockpit page for the host that reaches the others: one row per host of the host switcher, one tile per Azentrius add-on. Read-only." +eyebrow: Cockpit add-on +h1: The state of every host on one page +lead: "One row per host of Cockpit's host switcher, one tile per Azentrius add-on, such as Cron Jobs, Image Update Monitor, Update Gaps and Security Monitor. It belongs on the Cockpit host from which the others are reached and only reads; a click on a tile opens the add-on on its host." +summary: The state of the Azentrius add-ons on every host of Cockpit's host switcher, one row per host, one tile per add-on. +platforms: ["Cockpit", "Debian & Ubuntu", "Fedora & RHEL"] +problemTitle: Every add-on on every host is a page of its own. +problem: + - "Each add-on shows its state on its own host. To see everything, you open every add-on on every host." + - "An add-on missing on one host, or an update forgotten there, is easy to miss." + - "A host that does not answer should say so instead of looking fine." +features: + - title: One row per host + text: "In the order of the host switcher, this host first, with the most severe state of its add-ons, or why the host cannot be read." + - title: One tile per add-on + text: "Its state, its most important figure, its summary and the age of its data. A click opens the add-on on its host." + - title: Gaps show + text: "The tiles stand in the same order on every host: an add-on missing on one host gets a tile “Not installed” there, and a tile says when another host runs a newer version." + - title: Every entry + text: "All entries of an add-on fold out in a table below the row. An entry with a place in the add-on opens it there." + - title: Only what needs attention + text: "A switch in the header leaves out the tiles that need none. The browser keeps the choice." + - title: Current without you + text: "It loads on opening, on Refresh and every 5 minutes while the page is visible. Data older than the add-on allows makes the tile a warning." +explainer: + title: What a tile can say + intro: "A tile in OK means that the add-on found nothing in what it checks, not that the host is safe." + head: ["Label", "Meaning"] + rows: + - ["OK, Notice, Warning, Problem, Unknown", "The add-on's own state, in the status language all Azentrius add-ons share"] + - ["Not installed", "The add-on runs on another host, but not on this one"] + - ["No status", "The add-on's version on this host does not have the status contract yet"] + - ["No access", "Without administrative access on this host, the add-on has nothing to report"] + - ["Status unreadable", "The answer does not fit the contract; the tile gives the reason"] + - ["Unreachable, Key locked", "The host did not answer, or the SSH key is locked"] +security: + - "Read-only: it runs each add-on's status command, asks for no administrative access and changes nothing on any host." + - "Status commands run only from /usr/lib/cockpit-…, always with status --lang en or de; other arguments from a manifest are ignored." + - "What a host sends is data: checked against the status contract and shown as text only. A compromised host can report a false state, but it cannot run code in the session." + - "The page loads nothing from the network: it brings its own fonts and icons." +requirements: + - "On the host with the board: Cockpit with the host switcher, developed against Cockpit 360" + - "To open an add-on on another host with a click: AllowMultiHost in Cockpit" + - "On the other hosts: cockpit-bridge, a login by SSH key, and the add-ons" + - "Add-ons with the status contract: Cron Jobs 2.8.1, Image Update Monitor 0.20.0, Update Gaps 0.1.0, Security Monitor 0.1.0 or newer" +faq: + - q: Where do I install it? + a: "On the Cockpit host from which the others are reached, such as a bastion. The other hosts need only the add-ons." + - q: Does it need administrative access on the other hosts? + a: "No. Each add-on reports what it can read without root; that is the normal case for hosts reached with a key." + - q: Does it notify me? + a: "No. It loads only while the page is open and notifies no one." + - q: Does it look for new releases? + a: "No. It compares the versions the hosts run with each other, so a forgotten update shows." + - q: Which hosts does it show? + a: "Those in the host switcher's list in /etc/cockpit/machines.d. A host added without administrative access, which the switcher keeps for one browser session only, is not on the board." + - q: Does it keep any data? + a: "No, on no host. Only the browser keeps the switch “Only what needs attention”." +compare: "Status Board is not a monitoring system: it keeps no data, sends no alerts and loads only while the page is open. It reaches the hosts over the host switcher's own SSH connections; they need only cockpit-bridge, a login by key and the add-ons." +alt: {} +primaryAction: + label: Install Status Board + href: "#install" +updated: 2026-10-23 +--- + +Install the board on the host with the host switcher; the other hosts need only the add-ons. + +### From the Azentrius package repository + +For Debian, Ubuntu, Fedora and RHEL. Set up the repository once: + +```sh +# Debian and Ubuntu +curl -fsSLO https://packages.azentrius.com/azentrius-repository.deb +sudo apt install ./azentrius-repository.deb +sudo apt update + +# Fedora and RHEL +sudo rpm --import https://packages.azentrius.com/azentrius.asc +sudo dnf install https://packages.azentrius.com/azentrius-repository.rpm +``` + +Then install **Status Board** in Cockpit under **Applications**, or on the console: + +```sh +sudo apt install cockpit-status-board # Debian, Ubuntu +sudo dnf install cockpit-status-board # Fedora, RHEL +``` + +The system's updates keep it current. Status Board appears in Cockpit's menu near Overview; if it does not show yet, log in to Cockpit again. + +### From the files of a release + +On openSUSE this is the only way. Every [release](https://github.com/Azentrius/cockpit-status-board/releases) has the `.deb`, the `.rpm`, `SHA256SUMS` and a signed build provenance. Check both before you install: + +```sh +sha256sum --ignore-missing -c SHA256SUMS +gh attestation verify --repo Azentrius/cockpit-status-board +``` + +The `.rpm` of a release carries no package signature, so `zypper` needs `--allow-unsigned-rpm`; the two checks take its place. The [README](https://github.com/Azentrius/cockpit-status-board#install-update-uninstall) has the details. diff --git a/src/content/tools/en/cockpit-update-gaps.md b/src/content/tools/en/cockpit-update-gaps.md new file mode 100644 index 0000000..e6b7a72 --- /dev/null +++ b/src/content/tools/en/cockpit-update-gaps.md @@ -0,0 +1,105 @@ +--- +slug: cockpit-update-gaps +lang: en +title: "Update Gaps: missing updates and why (Cockpit)" +description: "Cockpit add-on: where a server misses updates although Software Updates lists none, such as held packages or Ubuntu Pro fixes, and why." +eyebrow: Cockpit add-on +h1: Find the updates Software Updates does not list +lead: "Held packages, fixes only with Ubuntu Pro, a pending restart, a kernel update that ran out of room in /boot: for every finding the page says what is missing, where the information comes from, why Cockpit's Software Updates does not show it and what you can do." +summary: Where a server misses updates although Software Updates lists none, and for every finding why and what you can do. +platforms: ["Cockpit", "Debian 12+", "Ubuntu 22.04+"] +problemTitle: No updates is not the same as up to date. +problem: + - "A package on hold is never upgraded, and Software Updates does not list it." + - "Once the last signing key of a source has expired, apt reads that source no more and its updates drop out of every list. Only apt update warns." + - "A kernel update that runs out of room in /boot stops halfway and leaves dpkg half done. Software Updates only says that it failed." +features: + - title: What Software Updates leaves out + text: "Held packages, fixes only with Ubuntu Pro, a pending restart, CPU vulnerabilities the kernel reports, firmware (with fwupd), snaps that are not refreshed, packages without a source, backports, software outside the package manager and the end of support." + - title: Upkeep gone wrong + text: "Packages dpkg left half done, too little room in /boot for the next kernel, expired signing keys, old package lists, phased updates Software Updates fails on, and what the last run of the automatic updates did." + - title: Why, and what you can do + text: "Every card says why Software Updates does not show it, what you can do and where the data come from. Commands are there to copy into a terminal; the page installs nothing." + - title: Since when + text: "A finding an earlier check saw as well says since when it has been there. The page always says how old its data is and when apt last updated its package lists." + - title: Acknowledge for a while + text: "With administrative access, a finding that is meant to be there can be acknowledged until a day you pick, at most 90 days ahead, with an optional reason. The page keeps showing it; the status stops counting it." + - title: Network data, if you want them + text: "Once set up, an unprivileged service fetches once a day the security issues Ubuntu has not fixed yet, fixes released upstream and newer versions elsewhere in Ubuntu." +explainer: + title: Why Software Updates does not show them + intro: "A few of the areas the add-on checks, and why Cockpit's Software Updates misses them. An empty section never means safe: the page lists what it did not check." + head: ["Area", "Why Software Updates does not show it"] + rows: + - ["Held packages", "A package on hold is never upgraded, and PackageKit does not list it."] + - ["Fixes only with Ubuntu Pro", "Without Ubuntu Pro, apt has no source for esm-apps and esm-infra."] + - ["Restart pending", "On Debian and Ubuntu, Cockpit does not tell when a restart is pending."] + - ["Phased updates (Ubuntu)", "Software Updates lists them, but its install fails on them, and on every other update with them."] + - ["Signing keys of the sources", "Once the last key of a source has expired, apt reads that source no more; only apt update warns."] + - ["End of support", "Cockpit does not show when a release stops getting updates."] +security: + - "Read only: the check never runs apt update and never installs, removes or restarts anything. The page can only switch its own regular check and the network data on or off, and acknowledge findings." + - "Every check runs as a hardened systemd service without network access, also when you press Refresh." + - "Network data come only once you set them up, from an unprivileged service of their own. What leaves the server: the release name, the names of selected source packages and which of a fixed list of projects are installed." + - "Credentials in the addresses of package sources are removed from the state, which every local user can read." + - "The browser makes no external requests: the fonts ship with the add-on." +requirements: + - "Debian 12 or newer, or Ubuntu 22.04 or newer, with systemd" + - "Cockpit 264 or newer" + - "Python 3.8 or newer (standard library only)" + - "Optional, used when present: needrestart, ubuntu-pro-client, distro-info-data, unattended-upgrades, gpg, fwupd" +faq: + - q: Does it install updates? + a: "No. It only reads. Where a card gives commands, they are for you to copy into a terminal." + - q: Does an empty page mean the server is safe? + a: "No. An empty section never means safe: the page always says what it did not check, what was skipped and how old its data is." + - q: Which systems does it check? + a: "Debian 12 and newer and Ubuntu 22.04 and newer. Fedora, RHEL and openSUSE are not checked yet, and the package repository serves the add-on for Debian and Ubuntu only." + - q: Does it send data anywhere? + a: "Only once you set up the network data. Then, once a day, the release name goes to Canonical's security metadata, the names of selected source packages to Launchpad, and which of a fixed list of projects are installed to GitHub." + - q: Can I silence a finding I know about? + a: "Yes, with administrative access: acknowledge it until a day at most 90 days ahead. It stays on the page and counts again after that day, or as soon as it changes in a way that matters. Some findings, such as a pending restart, cannot be acknowledged." + - q: Does it check container images? + a: "No. Image Update Monitor shows the versions of your containers." + - q: Do I need it on every server? + a: "Yes, on each server you look at in Cockpit, also behind a Cockpit bastion. Status Board shows the state of all of them on one page." +compare: "Software Updates compares the installed packages with the package sources. Update Gaps looks at what that comparison leaves out, and at the state of the system around it. It changes nothing on its own. Container images are for Image Update Monitor, what is reachable from where for Security Monitor." +alt: + overview: "Update Gaps in Cockpit: findings in seven areas on a server with held packages, fixes only with Ubuntu Pro and a pending restart" + upkeep: "Upkeep gone wrong: a kernel package dpkg left half configured and too little room in /boot, with the commands that finish it" + accepted: "Held Docker packages acknowledged until the maintenance window: still shown, no longer counted in the status" +primaryAction: + label: Install Update Gaps + href: "#install" +updated: 2026-10-23 +--- + +### From the Azentrius package repository + +For Debian and Ubuntu. Set up the repository once: + +```sh +curl -fsSLO https://packages.azentrius.com/azentrius-repository.deb +sudo apt install ./azentrius-repository.deb +sudo apt update +``` + +Then install **Update Gaps** in Cockpit under **Applications**, or on the console: + +```sh +sudo apt install cockpit-update-gaps +``` + +The system's updates keep it current. Install it on every server you look at in Cockpit, then open the page once with administrative access: it checks the server by itself. Set up the regular check there, and the network data if you want them. + +### From the files of a release + +Every [release](https://github.com/Azentrius/cockpit-update-gaps/releases) has the `.deb`, `SHA256SUMS` and a signed build provenance. Check both before you install: + +```sh +sha256sum --ignore-missing -c SHA256SUMS +gh attestation verify cockpit-update-gaps_X.Y.Z-1_all.deb --repo Azentrius/cockpit-update-gaps +sudo apt install ./cockpit-update-gaps_X.Y.Z-1_all.deb +``` + +Supported systems, settings and uninstalling: see the [README](https://github.com/Azentrius/cockpit-update-gaps#install-update-uninstall). diff --git a/src/content/tools/en/sharewerk.md b/src/content/tools/en/sharewerk.md new file mode 100644 index 0000000..d8ac9f9 --- /dev/null +++ b/src/content/tools/en/sharewerk.md @@ -0,0 +1,112 @@ +--- +slug: sharewerk +lang: en +title: "Sharewerk: Instagram and Facebook posts, ready to share" +description: "Self-hosted, with an Android web app: share an Instagram or Facebook post and get its images, video key frames, transcript and caption back." +eyebrow: Self-hosted, for Android +h1: Share a post, get it back as a clean pack +lead: "Share an Instagram or Facebook post from your Android phone to Sharewerk and get back every image of a carousel, key frames and a transcript for videos, and the caption as text. Then pass it on to an AI chat app, a messenger or anything else in the share menu." +summary: A self-hosted service with an Android web app that turns a shared post into images, key frames, a transcript and its text. +platforms: ["Docker Compose", "Android with Chrome", "Instagram & Facebook"] +notice: "A personal project, published in case it is useful. No support promise: it may break whenever Instagram or Facebook change something." +problemTitle: No more screenshots of every slide. +problem: + - "Passing on a carousel means a screenshot of every slide, and a reel a screen recording. Sharewerk fetches the post itself: its pictures, its caption as text and, for videos, key frames and what is said." +features: + - title: From the share menu + text: "Installed from Chrome, Sharewerk appears in Android's share menu. The phone only sends the link; downloading and processing happen on your server." + - title: Images that read well + text: "Every image as JPEG with a long edge of 1568 px: sharp enough to read text, small enough to share fast." + - title: Videos as frames and text + text: "Key frames at scene changes and a timestamped transcript, made with ffmpeg and faster-whisper on your server." + - title: The whole post in one share + text: "A post.txt with source, author, date, caption and an index of all pictures. Android takes at most 10 files per share; more pictures are combined into numbered contact sheets." + - title: Your server, your login + text: "An access token of its own, or none behind an authenticating proxy such as Pomerium, oauth2-proxy or Authelia. English and German, light and dark." + - title: Kept current + text: "Instagram and Facebook change constantly. The image is rebuilt every Monday with the newest gallery-dl and yt-dlp, so updating is a pull." +keeps: + title: Cookies, terms and rights + text: "Instagram shows almost nothing to logged-out visitors, so Sharewerk needs the cookies of a logged-in account. Use a secondary account: automated access to Instagram and Facebook is against Meta's terms of use, and accounts used this way can be rate-limited or blocked. The content of a post belongs to its author. Sharewerk is a tool for personal use, and you are responsible for how you use it." +security: + - "The downloaders only receive links on an allowlist of Instagram and Facebook hosts, so the server cannot be made to fetch other or internal addresses." + - "The container runs as a non-root user with a read-only root filesystem and no Linux capabilities." + - "The cookie file is a logged-in session: treat it like a password. Only the container user can read it." + - "Results are deleted after 24 hours by default, or right away from the list of recently prepared posts." + - "Never run it as an open service for other people: the cookies are yours, and so is the responsibility for what is downloaded with them." + - "The container images carry a signed build provenance." +requirements: + - "A server with Docker and Docker Compose; 2 CPU cores and 3 GB RAM are plenty" + - "A domain with HTTPS in front of it: web apps install only from secure origins" + - "An Android phone with Chrome; iPhone is not supported" + - "For Instagram: the cookies of a secondary account" +faq: + - q: Does it work on an iPhone? + a: "No. Safari does not implement the Web Share Target API, so a web app cannot appear in the iOS share sheet." + - q: Why does it need cookies? + a: "Instagram shows almost nothing to logged-out visitors. Use a secondary account, not your main one. Facebook videos often work without cookies." + - q: Where is a post processed? + a: "On your server. The phone only sends the link; the server downloads and processes the post and deletes the results after 24 hours by default." + - q: What if downloads start failing? + a: "Usually Instagram or Facebook changed something, and a newer gallery-dl or yt-dlp fixes it. Pull the image again: it is rebuilt every week." + - q: Is there an app to download? + a: "No. Sharewerk is a web app: you open your Sharewerk address in Chrome and install it from Chrome's menu." +alt: + icon: "The Sharewerk app icon: two stacked cards, the front one with an arrow pointing out, and a dot, in gold on ink" +primaryAction: + label: Set up Sharewerk + href: "#install" +notes: + - "Instagram and Facebook are trademarks of Meta Platforms, Inc., Android of Google LLC. Sharewerk is an independent project and not affiliated with Meta or Google." + - "The Sharewerk sign is a mark of Azentrius and is not licensed under the Apache License." +updated: 2026-10-23 +--- + +### On your server + +With Docker and Docker Compose: + +```sh +git clone https://github.com/Azentrius/sharewerk.git +cd sharewerk +cp .env.example .env +sed -i "s/^SHAREWERK_AUTH_TOKEN=.*/SHAREWERK_AUTH_TOKEN=$(openssl rand -hex 32)/" .env +mkdir -p secrets +docker compose up -d +``` + +Sharewerk now listens on `127.0.0.1:8080`, from the prebuilt image `ghcr.io/azentrius/sharewerk:latest`. Put a TLS reverse proxy in front of it, for example Caddy: + +```caddyfile +sharewerk.example.com { + reverse_proxy 127.0.0.1:8080 +} +``` + +The first video you process downloads the Whisper speech model (about 500 MB for `small`) into the data volume. + +### Cookies for Instagram + +Log in to a secondary account in a browser profile of its own, export its cookies in Netscape `cookies.txt` format and close the profile without logging out. Copy the file to the server, put it in place for the container user and delete the copy: + +```sh +sudo install -o 10001 -g 10001 -m 600 cookies.txt secrets/cookies.txt +shred -u cookies.txt +``` + +Delete the export on your computer as well. When Sharewerk reports “login required”, export the cookies again. The [README](https://github.com/Azentrius/sharewerk#cookies) explains each step. + +### On the phone + +1. Open your Sharewerk address in **Chrome** and sign in with the token from `.env`. +2. In Chrome's menu, choose **Install app**. +3. In Instagram, tap **Share** and pick **Sharewerk**. When the pack is ready, tap **Share** and pick the app to pass it on to. + +### Updating + +```sh +docker compose pull && docker compose up -d +gh attestation verify oci://ghcr.io/azentrius/sharewerk:latest --repo Azentrius/sharewerk +``` + +Behind Pomerium or another authenticating proxy, all settings and troubleshooting: see the [README](https://github.com/Azentrius/sharewerk#readme). diff --git a/src/data/related.ts b/src/data/related.ts index 92d5783..d997360 100644 --- a/src/data/related.ts +++ b/src/data/related.ts @@ -3,10 +3,14 @@ import type { CollectionEntry } from "astro:content"; const PAIRS: Record = { - "cockpit-cronjobs": ["cockpit-image-update-monitor", "home-assistant-theme"], - "cockpit-image-update-monitor": ["cockpit-cronjobs", "home-assistant-theme"], + "cockpit-cronjobs": ["cockpit-image-update-monitor", "cockpit-status-board"], + "cockpit-image-update-monitor": ["cockpit-update-gaps", "cockpit-cronjobs"], + "cockpit-update-gaps": ["cockpit-security-monitor", "cockpit-image-update-monitor", "cockpit-status-board"], + "cockpit-security-monitor": ["cockpit-update-gaps", "cockpit-image-update-monitor", "cockpit-status-board"], + "cockpit-status-board": ["cockpit-update-gaps", "cockpit-security-monitor", "cockpit-cronjobs"], stellwerk: ["lautwerk", "cockpit-cronjobs"], - lautwerk: ["stellwerk", "home-assistant-theme"], + lautwerk: ["stellwerk", "sharewerk"], + sharewerk: ["lautwerk", "stellwerk"], "home-assistant-theme": ["cockpit-cronjobs", "cockpit-image-update-monitor"], }; diff --git a/src/data/routes.mjs b/src/data/routes.mjs index 693ed7f..490a7c4 100644 --- a/src/data/routes.mjs +++ b/src/data/routes.mjs @@ -7,8 +7,12 @@ export const SITE = "https://azentrius.com"; export const TOOL_SLUGS = [ "cockpit-cronjobs", "cockpit-image-update-monitor", + "cockpit-update-gaps", + "cockpit-security-monitor", + "cockpit-status-board", "stellwerk", "lautwerk", + "sharewerk", "home-assistant-theme", ]; diff --git a/src/data/tools.ts b/src/data/tools.ts index a386796..c59de8b 100644 --- a/src/data/tools.ts +++ b/src/data/tools.ts @@ -15,17 +15,32 @@ import iumDialog from "../assets/screenshots/cockpit-image-update-monitor/update import iumDone from "../assets/screenshots/cockpit-image-update-monitor/update-done.png"; import iumBackups from "../assets/screenshots/cockpit-image-update-monitor/backups.png"; import iumVersion from "../assets/screenshots/cockpit-image-update-monitor/version-dialog.png"; +import gapsOverview from "../assets/screenshots/cockpit-update-gaps/overview.png"; +import gapsOverviewDark from "../assets/screenshots/cockpit-update-gaps/overview-dark.png"; +import gapsUpkeep from "../assets/screenshots/cockpit-update-gaps/upkeep.png"; +import gapsAccepted from "../assets/screenshots/cockpit-update-gaps/accepted.png"; +import secExposure from "../assets/screenshots/cockpit-security-monitor/exposure.png"; +import secExposureDark from "../assets/screenshots/cockpit-security-monitor/exposure-dark.png"; +import secSsh from "../assets/screenshots/cockpit-security-monitor/ssh.png"; +import secContainers from "../assets/screenshots/cockpit-security-monitor/containers.png"; +import secMarkDialog from "../assets/screenshots/cockpit-security-monitor/mark-dialog.png"; import stellwerkDisplay from "../assets/screenshots/stellwerk/display.png"; import themeLight from "../assets/screenshots/home-assistant-theme/light.png"; import themeDark from "../assets/screenshots/home-assistant-theme/dark.png"; import themeLightDialog from "../assets/screenshots/home-assistant-theme/light-dialog.png"; import themeDarkDialog from "../assets/screenshots/home-assistant-theme/dark-dialog.png"; +import lautwerkIcon from "../assets/icons/lautwerk.svg"; +import sharewerkIcon from "../assets/icons/sharewerk.svg"; export type ToolSlug = | "cockpit-cronjobs" | "cockpit-image-update-monitor" + | "cockpit-update-gaps" + | "cockpit-security-monitor" + | "cockpit-status-board" | "stellwerk" | "lautwerk" + | "sharewerk" | "home-assistant-theme"; export type Category = "cockpit" | "desktop" | "android" | "home-assistant"; @@ -51,6 +66,8 @@ export interface Tool { hero?: Shot; /** Light and dark side by side instead of one picture that follows the device. */ heroPair?: boolean; + /** The app's sign, shown next to the hero text of a project without screenshots (alt text: key "icon"). */ + icon?: ImageMetadata; gallery: Shot[]; docs: { changelog: boolean; roadmap: boolean; security: boolean }; } @@ -92,6 +109,52 @@ export const TOOLS: Tool[] = [ ], docs: { changelog: true, roadmap: true, security: true }, }, + { + slug: "cockpit-update-gaps", + repo: "Azentrius/cockpit-update-gaps", + name: { base: "Update Gaps", dot: true }, + plainName: "Update Gaps", + category: "cockpit", + status: "stable", + license: "Apache-2.0", + package: "cockpit-update-gaps", + hero: { key: "overview", image: gapsOverview, dark: gapsOverviewDark }, + gallery: [ + { key: "upkeep", image: gapsUpkeep }, + { key: "accepted", image: gapsAccepted }, + ], + docs: { changelog: true, roadmap: false, security: true }, + }, + { + slug: "cockpit-security-monitor", + repo: "Azentrius/cockpit-security-monitor", + name: { base: "Security", suffix: "Monitor" }, + plainName: "Security Monitor", + category: "cockpit", + status: "stable", + license: "Apache-2.0", + package: "cockpit-security-monitor", + hero: { key: "exposure", image: secExposure, dark: secExposureDark }, + gallery: [ + { key: "ssh", image: secSsh }, + { key: "containers", image: secContainers }, + { key: "mark-dialog", image: secMarkDialog }, + ], + docs: { changelog: true, roadmap: false, security: true }, + }, + { + slug: "cockpit-status-board", + repo: "Azentrius/cockpit-status-board", + name: { base: "Status Board", dot: true }, + plainName: "Status Board", + category: "cockpit", + status: "stable", + license: "Apache-2.0", + package: "cockpit-status-board", + // No screenshots: the ones in the repository show real host names. + gallery: [], + docs: { changelog: true, roadmap: false, security: true }, + }, { slug: "stellwerk", repo: "Azentrius/stellwerk", @@ -112,9 +175,22 @@ export const TOOLS: Tool[] = [ category: "android", status: "prototype", license: "Apache-2.0", + icon: lautwerkIcon, gallery: [], docs: { changelog: true, roadmap: true, security: true }, }, + { + slug: "sharewerk", + repo: "Azentrius/sharewerk", + name: { base: "Sharewerk", dot: true }, + plainName: "Sharewerk", + category: "android", + status: "prototype", + license: "Apache-2.0", + icon: sharewerkIcon, + gallery: [], + docs: { changelog: true, roadmap: false, security: true }, + }, { slug: "home-assistant-theme", repo: "Azentrius/home-assistant-theme", diff --git a/src/data/versions.json b/src/data/versions.json index 33b31fc..d7839b3 100644 --- a/src/data/versions.json +++ b/src/data/versions.json @@ -1,17 +1,33 @@ { "cockpit-cronjobs": { - "version": "2.7.4", - "date": "2026-10-18" + "version": "2.10.2", + "date": "2026-10-23" }, "cockpit-image-update-monitor": { - "version": "0.19.1", - "date": "2026-10-18" + "version": "0.25.1", + "date": "2026-10-23" + }, + "cockpit-update-gaps": { + "version": "0.7.1", + "date": "2026-10-23" + }, + "cockpit-security-monitor": { + "version": "0.3.1", + "date": "2026-10-23" + }, + "cockpit-status-board": { + "version": "0.2.3", + "date": "2026-10-22" }, "stellwerk": { - "version": "0.5.1", - "date": "2026-10-18" + "version": "0.6.4", + "date": "2026-10-23" }, "lautwerk": null, + "sharewerk": { + "version": "0.1.1", + "date": "2026-10-20" + }, "home-assistant-theme": { "version": "1.0.5", "date": "2026-10-18" diff --git a/src/styles/tokens.css b/src/styles/tokens.css index 0cb8d24..6a83e27 100644 --- a/src/styles/tokens.css +++ b/src/styles/tokens.css @@ -1,5 +1,5 @@ /* Generated by scripts/design.mjs from vendor/design-system/tokens.css, without @font-face. Do not edit. */ -/* Azentrius Design System — generated from tokens.json */ +/* Azentrius Design System: generated from tokens.json */ :root, [data-theme="cockpit-hell"] { --bg-page: #f2f2f2; --bg-card: #ffffff; diff --git a/vendor/design-system/COMMIT b/vendor/design-system/COMMIT index fb0674c..618ab67 100644 --- a/vendor/design-system/COMMIT +++ b/vendor/design-system/COMMIT @@ -1 +1 @@ -94009ab6e4b1ef895aeac324fa98989e17ce863e +5f4b256dde14cb9fbcfc49f9ca9faaa025a949d8 diff --git a/vendor/design-system/bundle.css b/vendor/design-system/bundle.css index 64f8cda..b432dd6 100644 --- a/vendor/design-system/bundle.css +++ b/vendor/design-system/bundle.css @@ -1,4 +1,4 @@ -/* Azentrius — Komponenten +/* Azentrius: Komponenten Reine CSS-Klassen ohne Build-Schritt. Alle Farben, Abstände und Radien kommen aus tokens.css. In Cockpit-Addons wird dieselbe Datei geladen; das Dunkel-Thema schaltet dort .pf-v6-theme-dark (siehe Abschnitt „Cockpit-Addons“). */ @@ -359,6 +359,33 @@ code, .az-mono { font-family: var(--az-font-code); font-size: 0.875rem; } .az-empty__body { margin: 0; max-width: 46ch; color: var(--text-subtle); } .az-empty__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-sm); margin-block-start: var(--space-md); } +/* ---------- Bildvorschau ---------- */ +/* Vorschau der Bilder, die eine App erzeugt oder weitergibt. Nur zum Ansehen, nicht bedienbar. */ +.az-thumbs { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); + gap: var(--space-md) var(--space-sm); + inline-size: 100%; + margin: 0; + padding: 0; + list-style: none; +} +.az-thumb { display: flex; flex-direction: column; gap: var(--space-xs); min-width: 0; } +/* Hochformat 4:5, nie beschnitten; was nicht 4:5 ist, steht auf bg-control. */ +.az-thumb__image { + display: block; + inline-size: 100%; + aspect-ratio: 4 / 5; + object-fit: contain; + box-sizing: border-box; + background: var(--bg-control); + border: 1px solid var(--line); + border-radius: var(--radius-small); +} +/* Beschriftung unter dem Bild, nie darauf: auf einem fremden Bild ist 4,5:1 nicht zu garantieren. */ +.az-thumb__caption { font-size: 12px; line-height: 1.5; color: var(--text-subtle); overflow-wrap: anywhere; } +.az-thumb__number { color: var(--text); font-weight: 600; } + /* ---------- Signatur ---------- */ .az-signature { display: flex; diff --git a/vendor/design-system/tokens.css b/vendor/design-system/tokens.css index 33df678..80e444d 100644 --- a/vendor/design-system/tokens.css +++ b/vendor/design-system/tokens.css @@ -1,4 +1,4 @@ -/* Azentrius Design System — generated from tokens.json */ +/* Azentrius Design System: generated from tokens.json */ @font-face { font-family: "Red Hat Text"; src: url("fonts/RedHatText-VF.woff2") format("woff2"); font-weight: 300 700; font-style: normal; font-display: swap; } @font-face { font-family: "Red Hat Text"; src: url("fonts/RedHatText-VF-Italic.woff2") format("woff2"); font-weight: 300 700; font-style: italic; font-display: swap; } @font-face { font-family: "Red Hat Display"; src: url("fonts/RedHatDisplay-VF.woff2") format("woff2"); font-weight: 300 900; font-style: normal; font-display: swap; }