diff --git a/content/articles/example-information-card/contents.lr b/content/articles/example-information-card/contents.lr deleted file mode 100644 index c2aa206..0000000 --- a/content/articles/example-information-card/contents.lr +++ /dev/null @@ -1,100 +0,0 @@ -_model: entry ---- -title: Example Article: Anatomy of an Information Card ---- -date: 2026-08-11 ---- -updated: 2026-08-11 ---- -author: Example Article Author ---- -tags: lorem-ipsum, information-card, field-mapping, example ---- -kicker: Article ---- -summary: A fully populated example article showing how every information-card value maps to a Lektor content field. ---- -published_urls: - -https://example.com/article -https://publication.example.org/features/anatomy-of-an-article-information-card-demonstration ---- -body: -## Information card field map - -Every available row in the article information card is intentionally visible -on this example page. The values map to this record's `contents.lr` file as -follows: - -`content/articles/example-information-card/contents.lr` - -- **Author** is read from the `author` field. -- **Published** is read from the `date` field. -- **Updated** is read from the optional `updated` field. -- **Reading time** is calculated automatically from the words in the `body` - field, using approximately 200 words per minute. -- **Topics** are read from the controlled checkbox `tags` field. -- **Published online** loops over every item in the multiline `published_urls` - field. - -The first publication URL stays below 40 characters and is displayed in full. -The second is deliberately longer than 40 characters, so its visible text uses -a middle ellipsis while its link destination, tooltip, and accessible label -retain the complete URL. - -## Lorem ipsum demonstration - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere, -libero non posuere luctus, neque tellus cursus sapien, vitae tincidunt erat -metus et velit. Sed dignissim sem vel augue fermentum, vitae tristique lorem -facilisis. Praesent commodo, mauris id faucibus malesuada, augue justo -sollicitudin nibh, vitae efficitur magna arcu sed neque. Nulla facilisi. Donec -tempor turpis sed felis interdum, quis consequat nibh consequat. - -Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere -cubilia curae; Etiam id lectus vel ipsum placerat pellentesque. Morbi vulputate -semper dolor, in facilisis justo volutpat sed. Suspendisse potenti. Fusce -ultricies ipsum at arcu aliquet, a feugiat augue suscipit. Nam interdum -fermentum enim, et commodo sapien pharetra sit amet. Curabitur vitae urna vitae -mauris volutpat consequat non non augue. - -Aliquam erat volutpat. Proin vitae metus eget nunc porttitor elementum. Mauris -euismod, sem sed tincidunt tincidunt, sapien velit consectetur neque, at -viverra nibh eros nec urna. Duis malesuada sapien in velit feugiat, sed -ullamcorper massa tincidunt. Cras condimentum risus at neque vestibulum, quis -tempor justo tristique. Pellentesque habitant morbi tristique senectus et netus -et malesuada fames ac turpis egestas. - -Donec eu feugiat neque. Quisque ac velit vitae odio volutpat vulputate. Nunc -faucibus eros non dolor tempor, nec posuere lacus tristique. Sed euismod -convallis nulla, quis feugiat dolor vulputate sit amet. Aenean commodo feugiat -ipsum, vel dictum sapien ullamcorper quis. Vivamus id enim nec nibh eleifend -convallis. In hac habitasse platea dictumst. Maecenas cursus orci eget dui -aliquet, vitae feugiat elit rhoncus. - -Phasellus dignissim, metus ac tristique convallis, purus massa pulvinar enim, -eu facilisis justo sem sit amet nibh. Nullam gravida interdum quam, a luctus -turpis finibus sed. Sed at magna vel lectus faucibus malesuada. Integer -facilisis quam non purus volutpat, quis tristique nisl blandit. Ut pellentesque -ligula vitae purus porttitor, vitae scelerisque justo feugiat. Duis luctus -metus quis orci egestas, id pellentesque mi faucibus. - -Morbi sit amet nibh et justo sagittis viverra. Nulla vitae odio ac tortor -tempor pretium. Curabitur dignissim massa at justo eleifend, vel feugiat neque -facilisis. Praesent sed tellus quis augue vulputate malesuada. Sed tincidunt -nisi in risus dignissim, a hendrerit ipsum volutpat. Integer faucibus metus et -turpis sodales, sed convallis lectus feugiat. Vivamus finibus, tortor id -efficitur feugiat, odio mauris imperdiet justo, quis pulvinar erat sem at arcu. - -Etiam consequat ligula sed sem faucibus, eu feugiat leo posuere. Pellentesque -congue mauris sit amet sapien vestibulum, quis vulputate nulla malesuada. -Suspendisse vitae ipsum ut sapien consequat tempus. Aenean et lectus in justo -scelerisque feugiat. Cras sed posuere ex. Nam non egestas risus. Vestibulum -mollis mauris eget nisi efficitur, vitae sollicitudin tortor imperdiet. Donec -at consequat velit, non cursus risus. - -Sed vulputate justo at elit gravida, a tristique mauris blandit. In hac -habitasse platea dictumst. Mauris at erat luctus, volutpat risus vitae, -fermentum ipsum. Proin malesuada nibh et orci tristique, eget efficitur nibh -interdum. Quisque feugiat sem at purus pretium, id sodales nunc ullamcorper. -Integer accumsan urna sit amet mi placerat, vitae suscipit tortor lacinia. diff --git a/content/blog/example-deployment-runbook/contents.lr b/content/blog/example-deployment-runbook/contents.lr deleted file mode 100644 index 40022a7..0000000 --- a/content/blog/example-deployment-runbook/contents.lr +++ /dev/null @@ -1,668 +0,0 @@ -_model: entry ---- -title: Example Blog Entry: Labyricorn Deployment Runbook ---- -date: 2026-08-11 ---- -author: Example Blog Author ---- -tags: lektor, deployment, operations, example ---- -kicker: Blog ---- -summary: A complete example blog record whose body mirrors the repository runbook and documents how its information card is populated. ---- -body: -## Information card field map - -This example deliberately exposes how the visible post-information card maps -back to this record's `contents.lr` file: - -`content/blog/example-deployment-runbook/contents.lr` - -- **Author** is read from the `author` field. -- **Published** is read from the `date` field. -- **Tags** are read from the controlled checkbox `tags` field. - -The title, summary, and article body are supplied by `title`, `summary`, and -`body`, respectively, but those values appear outside the information card. - -## Labyricorn website and deployment runbook - -This repository is the canonical source for `www.labyricorn.com`. It contains -the editable Lektor project—not generated production files—and is also the -primary operations guide for building, deploying, verifying, rolling back, and -troubleshooting the site. - -## Quick reference - -| Item | Value | -| --- | --- | -| Production URL | `https://www.labyricorn.com` | -| Canonical Git repository | `https://git.labyricorn.com/Labyricorn/labyricorn-site.git` | -| Production branch | `main` | -| Production host | `ubuntu2-47` (`10.138.2.47`) | -| Repository checkout | `/srv/labyricorn/repo` | -| Active document root | `/srv/labyricorn/current` | -| Release storage | `/srv/labyricorn/releases` | -| Deployment command | `sudo deploy-labyricorn` | -| Rollback listing | `sudo rollback-labyricorn` | -| Rollback command | `sudo rollback-labyricorn RELEASE_NAME` | -| Deployment log | `/srv/labyricorn/logs/deploy.log` | -| nginx site config | `/etc/nginx/sites-available/labyricorn` | -| Lektor executable | `/srv/labyricorn/.local/bin/lektor` | -| Deployment account | `labyricorn-deploy` | - -## Architecture - -```text -Gitea: Labyricorn/labyricorn-site (main) - | - | authenticated Git fetch - v - /srv/labyricorn/repo - | - | Lektor static build - v - /srv/labyricorn/releases/- - | - | validated, atomic symlink switch - v - /srv/labyricorn/current - | - | read-only static files - v - nginx :80 - | - | Cloudflare proxy and public TLS - v - https://www.labyricorn.com -``` - -Gitea is the source of truth. The production checkout is disposable state and -must not contain unpublished edits during deployment. Lektor's development -server is not part of production serving; nginx serves generated files only. - -## Repository contents - -```text -Labyricorn.lektorproject Lektor project definition -content/ Editable site content (`contents.lr` files) -content/tags/ Controlled tag vocabulary and dedicated tag routes -models/ Lektor content models -templates/ Jinja templates -assets/static/ CSS, filtering JavaScript, favicon, and static assets -.gitignore Excludes generated and local files -README.md This runbook -``` - -Generated output such as `build/`, `dist/`, and `.lektor/` is intentionally -ignored and must not be committed. - -## Routine content workflow - -Edit in a normal Git checkout, review the changes, and push them to `main`. -A successful push triggers the repository's Gitea Action, which builds and -atomically activates that exact revision on the production host. - -```bash -git switch main -git pull --ff-only origin main - -# Edit content, templates, models, or assets. - -lektor build --output-path build -git status -git add -git commit -m "Describe the site change" -git push origin main -``` - -Watch the run under **Actions** in Gitea. Manual deployment remains available -for recovery or controlled operations: - -```bash -sudo deploy-labyricorn -``` - -Do not edit generated files under `/srv/labyricorn/current` or -`/srv/labyricorn/releases`. They will be replaced by deployment and are not -source-controlled. - -## Tags and filtering workflow - -`content/tags/` is the single source of truth for the controlled tag -vocabulary. Each child directory is a normal Lektor record whose directory name -is the canonical lowercase, hyphenated slug used in entry data and URLs: - -```text -content/tags/deployment/contents.lr -> /tags/deployment/ -``` - -The tag record supplies the editor label and public description: - - _model: tag - --- - title: Deployment - --- - summary: Build, release, rollout, verification, and rollback workflows. - -The entry model reads its checkbox choices directly from these records. Blog -entries and articles store the selected slugs as a comma-separated `tags` -value: - -```text -tags: lektor, deployment, operations -``` - -To add a tag, create its `content/tags//contents.lr` record, run a build, -and then select it on the relevant entries. Do not add a slug directly to an -entry before its tag record exists. To rename or retire a tag, update every -referencing entry deliberately and verify that no old slug remains before -renaming or removing its record. - -`/tags/` lists every approved tag and counts its usage across projects, project -devlog entries, blog entries, and articles. Dedicated tag URLs combine matching -records from all four content types. Tag links are normal links and work without -JavaScript. On the Projects, Blog, and Articles listing pages, -`assets/static/tags.js` progressively adds instant filtering and keeps the -selected filter in the `tag` query parameter. - -After taxonomy or filtering changes: - -1. Run `python scripts/build_with_projects.py --output-path build`. -2. Verify `/tags/`, at least one dedicated tag URL, the three top-level section - listings, and a project devlog index. -3. Confirm tag counts cover projects, devlog entries, blog entries, and articles - and that every stored entry slug has a matching tag record. -4. Test filtering with JavaScript enabled and confirm tag links remain usable - without JavaScript. -5. Check keyboard operation plus desktop and narrow layouts. -6. If filtering JavaScript or tag styles changed, increment the corresponding - cache-busting version in `templates/base.html`. - -## Local development - -Install Lektor in an isolated Python environment. For example: - -```bash -python3 -m venv .venv -. .venv/bin/activate -python -m pip install --upgrade pip -python -m pip install lektor -``` - -Run the local editor and preview server: - -```bash -lektor server -``` - -Run a production-style build: - -```bash -lektor build --output-path build -test -f build/index.html -``` - -The project currently has no third-party Lektor packages or plugins. - -## Production filesystem and permissions - -```text -/srv/labyricorn/ -├── repo/ Git working copy (not web-accessible) -├── releases/ Successful immutable builds -├── current -> releases/ -├── logs/ -│ ├── deploy.log -│ └── deploy.lock -├── .local/bin/lektor pipx-installed Lektor -├── .netrc Git HTTPS credential (0600; secret) -├── .ssh/ Reserved deployment SSH material -└── README-DEPLOYMENT.md Supplemental host-local notes -``` - -The `labyricorn-deploy` account owns the checkout, releases, logs, Lektor -environment, and Git credential. nginx's `www-data` account can traverse the -base path and read active generated files, but cannot read the source checkout -or credential. nginx cannot modify either source or releases. - -## Deployment behavior - -`/usr/local/bin/deploy-labyricorn` performs the following sequence: - -1. Changes from root to the unprivileged `labyricorn-deploy` account. -2. Acquires an exclusive `flock` lock to prevent concurrent deployments. -3. Refuses to proceed if the working tree contains any tracked or untracked - changes. -4. Fetches and prunes `origin`. -5. Verifies that `origin/main` exists. -6. Switches to local `main` and resets it exactly to `origin/main`. -7. Locates exactly one `.lektorproject` file instead of assuming its name. -8. Creates a unique release named with UTC time and the 12-character commit ID. -9. Runs Lektor with an explicit output directory. -10. Requires the build to succeed and contain `index.html`. -11. Writes the full commit ID to `.labyricorn-commit` in the release. -12. Atomically replaces `/srv/labyricorn/current` with a relative symlink to - the new release. -13. Keeps the active release plus recent prior releases, targeting five total. -14. Logs start, failure, success, release name, and commit. - -Run it with: - -```bash -sudo deploy-labyricorn -``` - -A failed build is removed before activation. The current symlink is not changed, -so the previously working site remains online. - -### Deployment preflight - -```bash -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - git -C /srv/labyricorn/repo status --short --branch - -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - git -C /srv/labyricorn/repo fetch origin -``` - -The status must be clean. Do not bypass a dirty-tree refusal. Determine whether -the files are legitimate unpublished admin edits, then commit and push them or -remove them deliberately before deployment. - -## Verify a deployment - -```bash -readlink -f /srv/labyricorn/current -cat /srv/labyricorn/current/.labyricorn-commit - -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - git -C /srv/labyricorn/repo rev-parse HEAD - -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - git -C /srv/labyricorn/repo ls-remote origin refs/heads/main - -nginx -t -systemctl is-active nginx - -curl -I -H 'Host: www.labyricorn.com' \ - -H 'X-Forwarded-Proto: https' http://127.0.0.1/ - -curl -I https://www.labyricorn.com/ -``` - -The commit in the active release, local `HEAD`, and remote `main` should match. -The local nginx request with `X-Forwarded-Proto: https` should return `200`. -Public HTTP should redirect to HTTPS, and public HTTPS should return `200`. - -## Rollback - -List releases and identify the current one: - -```bash -sudo rollback-labyricorn -``` - -Switch atomically to a previous successful release: - -```bash -sudo rollback-labyricorn 20260812T024742Z-92475d2ec759 -``` - -Use a release name printed by the listing command. Rollback does not build, -fetch, or alter Git. It only changes the `current` symlink and records the event -in the deployment log. - -Verify afterward: - -```bash -readlink -f /srv/labyricorn/current -cat /srv/labyricorn/current/.labyricorn-commit -curl -I -H 'Host: www.labyricorn.com' \ - -H 'X-Forwarded-Proto: https' http://127.0.0.1/ -``` - -A normal deployment after rollback rebuilds and reactivates the latest remote -`main` commit. - -## nginx and URL handling - -The site configuration is: - -```text -/etc/nginx/sites-available/labyricorn -/etc/nginx/sites-enabled/labyricorn -> ../sites-available/labyricorn -``` - -nginx serves `/srv/labyricorn/current` and supports: - -- `index.html` at directory-style URLs; -- direct static assets; -- optional `.html` fallback; -- generated `/404/index.html` with an HTTP `404` response; -- disabled directory browsing; -- rejection of hidden paths and common executable-script extensions; -- dedicated access and error logs. - -Always validate before reloading nginx: - -```bash -nginx -t -systemctl reload nginx -``` - -nginx logs: - -```text -/var/log/nginx/labyricorn-access.log -/var/log/nginx/labyricorn-error.log -``` - -## HTTPS, Cloudflare, and DNS - -Current production HTTPS terminates at Cloudflare. The origin nginx process -currently listens on port `80`, not `443`. For `www.labyricorn.com`, nginx uses -Cloudflare's `X-Forwarded-Proto` header to distinguish public HTTP from HTTPS: - -- public HTTP redirects to `https://www.labyricorn.com`; -- Cloudflare-originated HTTPS requests are served without a redirect loop; -- `labyricorn.com` is configured at nginx to redirect to the canonical HTTPS - `www` hostname. - -The apex `labyricorn.com` did not resolve during initial setup. Its redirect will -not work publicly until DNS/Cloudflare has an apex record routed to this origin. - -Certbot and the nginx integration are installed, and `certbot.timer` is enabled, -but no origin certificate was issued during setup. Do not run Certbot blindly -behind Cloudflare. First decide whether the desired origin mode is a Cloudflare -Origin CA certificate, Let's Encrypt with a compatible challenge, or direct DNS -without the proxy. After changing TLS, test both origin and public behavior for -redirect loops. - -Useful checks: - -```bash -getent ahosts www.labyricorn.com -getent ahosts labyricorn.com -curl -I http://www.labyricorn.com/ -curl -I https://www.labyricorn.com/ -systemctl status certbot.timer -certbot certificates -``` - -## Firewall and exposed services - -UFW is active with default incoming denial. Allowed services are: - -- OpenSSH: TCP 22 -- nginx HTTP/HTTPS profile: TCP 80 and 443 - -Inspect current state: - -```bash -ufw status verbose -ss -lntup -``` - -Lektor's development port must never be opened in UFW or bound to `0.0.0.0`. - -## Optional server-side Lektor admin - -An optional unit exists at: - -```text -/etc/systemd/system/lektor-admin.service -``` - -Current state: **disabled and stopped**. When started, it runs as -`labyricorn-deploy` and binds only to `127.0.0.1:5000`. It is not proxied by -nginx and production remains independent of it. - -Start it temporarily: - -```bash -systemctl start lektor-admin -systemctl status lektor-admin -ss -lntp | grep ':5000' -``` - -Access it securely through an SSH tunnel from an administrator workstation: - -```bash -ssh -L 5000:127.0.0.1:5000 root@10.138.2.47 -``` - -Then browse to `http://127.0.0.1:5000` on that workstation. - -Stop it when finished: - -```bash -systemctl stop lektor-admin -``` - -### Committing admin edits made on the server - -Lektor can edit files, but it does not automatically create Git commits or push -them. The deployment account intentionally has authenticated Git write access so -a controlled admin workflow can publish server-side edits. - -Review everything before committing: - -```bash -sudo -u labyricorn-deploy env HOME=/srv/labyricorn bash -cd /srv/labyricorn/repo -git status -git diff -git add -git commit -m "Describe the admin edit" -git push origin main -exit -``` - -Then run `sudo deploy-labyricorn`. The deployment script will refuse to run -while uncommitted admin edits remain. This is deliberate protection against -silently discarding edits when it resets to `origin/main`. - -Before enabling persistent or public admin access, add authentication and make a -separate security decision. Do not publish port 5000 directly and do not proxy -an unauthenticated editor through nginx. - -## Git authentication and secrets - -The private Gitea repository is accessed over HTTPS because the Gitea SSH port -was not reachable through `git.labyricorn.com` during setup. - -Credential purpose and location: - -| Purpose | Location | Permissions | -| --- | --- | --- | -| Gitea HTTPS fetch/push | `/srv/labyricorn/.netrc` | `0600`, owned by `labyricorn-deploy` | -| Reserved SSH identity | `/srv/labyricorn/.ssh/id_ed25519` | `0600`, owned by `labyricorn-deploy` | - -Never place token contents, passwords, or private keys in this README, Git URLs, -shell scripts, logs, commits, issue trackers, or command history. - -Check credential-file metadata without printing its contents: - -```bash -stat -c '%A %U:%G %n' /srv/labyricorn/.netrc -``` - -If the Gitea token is rotated, replace `.netrc` as `labyricorn-deploy`, preserve -mode `0600`, and verify both fetch and push access before revoking the old token. -Avoid printing either credential during rotation. - -## Logs and diagnostics - -```bash -# Deployment and rollback history -tail -n 100 /srv/labyricorn/logs/deploy.log - -# nginx service and request errors -journalctl -u nginx --since today -tail -n 100 /var/log/nginx/labyricorn-error.log - -# Optional admin service -journalctl -u lektor-admin --since today - -# Repository state -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - git -C /srv/labyricorn/repo status - -# Active release -readlink -f /srv/labyricorn/current -cat /srv/labyricorn/current/.labyricorn-commit - -# Services and sockets -systemctl status nginx -systemctl status certbot.timer -ss -lntup -``` - -## Troubleshooting - -### Deployment says the repository is dirty - -Inspect as the deployment account: - -```bash -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - git -C /srv/labyricorn/repo status --short -``` - -If these are intended admin edits, review, commit, and push them. Otherwise, -identify their origin before removing anything. Never use a destructive reset -until you are certain no work needs to be preserved. - -### Git fetch or push fails - -Check DNS, HTTPS, the remote URL, and credential permissions without displaying -the secret: - -```bash -getent ahosts git.labyricorn.com -curl -I https://git.labyricorn.com/ -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - git -C /srv/labyricorn/repo remote -v -stat -c '%A %U:%G %n' /srv/labyricorn/.netrc -``` - -An authentication failure usually means the token was revoked, expired, or -lacks repository access. - -### Lektor build fails - -Run a disposable diagnostic build; do not build into `current`: - -```bash -test_dir=$(mktemp -d /srv/labyricorn/releases/.diagnostic.XXXXXX) -chown labyricorn-deploy:labyricorn-deploy "$test_dir" -sudo -u labyricorn-deploy env HOME=/srv/labyricorn \ - /srv/labyricorn/.local/bin/lektor \ - --project /srv/labyricorn/repo/Labyricorn.lektorproject \ - build --output-path "$test_dir" -``` - -Inspect the error and source. Remove the diagnostic directory only after -confirming its exact path and that it is not referenced by `current`. - -### nginx returns an error - -```bash -nginx -t -systemctl status nginx -readlink -f /srv/labyricorn/current -test -f /srv/labyricorn/current/index.html -tail -n 100 /var/log/nginx/labyricorn-error.log -``` - -Do not point nginx at the Git checkout or start Lektor as a production server. - -### Public HTTPS loops or behaves differently from local HTTP - -Check Cloudflare proxy mode and the forwarded protocol behavior: - -```bash -curl -I -H 'Host: www.labyricorn.com' http://127.0.0.1/ -curl -I -H 'Host: www.labyricorn.com' \ - -H 'X-Forwarded-Proto: https' http://127.0.0.1/ -curl -I http://www.labyricorn.com/ -curl -I https://www.labyricorn.com/ -``` - -The first origin request should redirect; the simulated Cloudflare HTTPS request -should return the site. A different result indicates a proxy/header or nginx -configuration problem. - -## Automatic deployment - -Pushes to `main` automatically deploy through Gitea Actions. The workflow is -versioned with the site at `.gitea/workflows/deploy.yml` and has one job: - -1. Run on the repository-scoped runner labelled `labyricorn-deploy`. -2. Execute the existing root-owned `deploy-labyricorn` command. -3. Confirm `/srv/labyricorn/current/.labyricorn-commit` equals the pushed commit. -4. Request the site through nginx on the local origin and fail if it is unhealthy. - -The action intentionally does not check out the repository into its own -workspace. The deployment script fetches `origin/main` using the dedicated -`labyricorn-deploy` account, validates a clean checkout, builds a new release, -and atomically changes the `current` symlink. Concurrent action runs share the -`labyricorn-production` concurrency group, and the deployment script also uses -a filesystem lock. - -### Runner installation - -The production host runs official Gitea Runner 3.0.0 directly on Linux; Docker -is not installed or required for this workflow. - -| Item | Value | -|---|---| -| systemd unit | `gitea-runner.service` | -| service account | `gitea-runner` | -| runner name | `labyricorn-production` | -| registration scope | `Labyricorn/labyricorn-site` repository | -| execution label | `labyricorn-deploy:host` | -| runner binary | `/usr/local/bin/gitea-runner` | -| runner configuration | `/etc/gitea-runner/config.yaml` | -| registration state | `/var/lib/gitea-runner/.runner` | -| job workspace | `/var/lib/gitea-runner/work` | -| sudo policy | `/etc/sudoers.d/gitea-runner-labyricorn` | - -The runner account has no general administrative access. Its sudo policy allows -only this exact command without a password: - -```text -/usr/local/bin/deploy-labyricorn -``` - -Useful checks: - -```bash -systemctl status gitea-runner -journalctl -u gitea-runner -n 100 --no-pager -sudo -l -U gitea-runner -``` - -If the runner must be replaced, delete or disable it in **Repository Settings → -Actions → Runners**, generate a fresh repository registration token, and -register the replacement. Registration tokens and `.runner` contents are -credentials: never commit or print them. A push can still be deployed manually -with `sudo deploy-labyricorn` while the runner is unavailable. - -## Change-control checklist - -Before changing deployment, nginx, TLS, firewall, credentials, or admin access: - -1. Inspect the live state and preserve unrelated configuration. -2. Back up the specific file being changed. -3. Validate syntax before reload or restart. -4. Keep SSH reachable before firewall changes. -5. Verify local origin behavior and public Cloudflare behavior separately. -6. Record operational changes in this README. -7. Commit and push source documentation to `main`. - -This README describes the current verified installation on `ubuntu2-47`. Update -it whenever the operational architecture changes. diff --git a/content/blog/hello-world/contents.lr b/content/blog/hello-world/contents.lr deleted file mode 100644 index 77457af..0000000 --- a/content/blog/hello-world/contents.lr +++ /dev/null @@ -1,19 +0,0 @@ -_model: entry ---- -title: Hello from Labyricorn ---- -date: 2026-08-11 ---- -author: Labyricorn ---- -tags: lektor, git, publishing ---- -kicker: Blog ---- -summary: The first entry from the new Git-backed Lektor site. ---- -body: -The new Labyricorn site starts here: an intentionally small publishing system -with content that is easy to edit, review, build, deploy, and roll back. - -More project notes, articles, and experiments will follow.