Compare commits
43 Commits
ac51f7e6c4
...
main
Author | SHA1 | Date | |
---|---|---|---|
858b18d33e | |||
568eeed18e | |||
4167963ce3 | |||
7345f0ebc4 | |||
fa78ccec80 | |||
e4e432790c | |||
2eb833436e | |||
f14e379996 | |||
a02e3eb569 | |||
664b195cf3 | |||
c08ae199f9 | |||
e1ed459c59 | |||
2f7506fbad | |||
416a9be424 | |||
8f71737822 | |||
2d2e1866fa | |||
16052c6218 | |||
682a999cdb | |||
d7c75324b3 | |||
3fd639bd9a | |||
8afbd539de | |||
c186102be1 | |||
317de5e09a | |||
275426d7a3 | |||
503b7b134f | |||
2e8e9f5f93 | |||
fd71ea2590 | |||
c2df6c42aa | |||
a9564ba3b2 | |||
c4b54a375c | |||
2b404604f2 | |||
044713c8a0 | |||
03afdaa60d | |||
495f60003e | |||
9695785e5c | |||
00b49683fd | |||
19b0aad18e | |||
98aed49586 | |||
6e1c5bc28e | |||
3f2e0cfdd8 | |||
a390110d99 | |||
778deb5fc6 | |||
01cd37f30a |
41
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,41 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
|
||||
{
|
||||
"name": "Existing Docker Compose (Extend)",
|
||||
|
||||
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
|
||||
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
|
||||
"dockerComposeFile": [
|
||||
"../docker-compose.yml",
|
||||
"docker-compose.yml"
|
||||
],
|
||||
|
||||
// The 'service' property is the name of the service for the container that VS Code should
|
||||
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
|
||||
"service": "server",
|
||||
|
||||
// The optional 'workspaceFolder' property is the path VS Code should open by default when
|
||||
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
|
||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}"
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.>
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Uncomment the next line if you want start specific services in your Docker Compose config.
|
||||
// "runServices": [],
|
||||
|
||||
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
|
||||
// "shutdownAction": "none",
|
||||
|
||||
// Uncomment the next line to run commands after the container is created.
|
||||
// "postCreateCommand": "cat /etc/os-release",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "devcontainer"
|
||||
}
|
26
.devcontainer/docker-compose.yml
Normal file
@ -0,0 +1,26 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
# Update this to the name of the service you want to work with in your docker-compose.yml file
|
||||
server:
|
||||
# Uncomment if you want to override the service's Dockerfile to one in the .devcontainer
|
||||
# folder. Note that the path of the Dockerfile and context is relative to the *primary*
|
||||
# docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
|
||||
# array). The sample below assumes your primary file is in the root of your project.
|
||||
#
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: .devcontainer/Dockerfile
|
||||
|
||||
volumes:
|
||||
# Update this to wherever you want VS Code to mount the folder of your project
|
||||
- ..:/workspaces:cached
|
||||
|
||||
# Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
|
||||
# cap_add:
|
||||
# - SYS_PTRACE
|
||||
# security_opt:
|
||||
# - seccomp:unconfined
|
||||
|
||||
# Overrides default command so things don't shut down after the process ends.
|
||||
# command: sleep infinity
|
||||
|
12
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for more information:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# https://containers.dev/guide/dependabot
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "devcontainers"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
@ -6,6 +6,7 @@ draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images: []
|
||||
tags: []
|
||||
---
|
||||
|
@ -4,8 +4,9 @@ $text: hsl(204, 28%, 93%);
|
||||
$light-grey: #292e32; // #494f5c;
|
||||
$dark-grey: #3B3E48;
|
||||
$highlight-grey: #7d828a;
|
||||
$midnightblue: #2c3e50;
|
||||
$typewriter: hsl(172, 100%, 36%);
|
||||
$codebackground: #1c2023 !default;
|
||||
$midnightblue: $codebackground;
|
||||
|
||||
// Scroll to Top Default colors
|
||||
|
||||
@ -21,7 +22,7 @@ kbd {
|
||||
|
||||
// Fonts
|
||||
$fonts: "IBM Plex Sans Light", "Segoe UI", Candara, sans-serif;
|
||||
$code-fonts: "IBM Plex Mono", Consolas, "Andale Mono WT", "Andale Mono", Menlo, Monaco, monospace;
|
||||
$code-fonts: "IBM Plex Mono Light", Consolas, "Andale Mono WT", "Andale Mono", Menlo, Monaco, monospace;
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Sans Light';
|
||||
@ -45,18 +46,18 @@ $code-fonts: "IBM Plex Mono", Consolas, "Andale Mono WT", "Andale Mono", Menlo,
|
||||
font-family: 'IBM Plex Sans Light';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('IBM Plex Sans Medm'),
|
||||
local('IBMPlexSans-Medm'),
|
||||
url('/fonts/IBMPlexSans-Medium.woff2') format('woff2');
|
||||
src: local('IBM Plex Sans Bold'),
|
||||
local('IBMPlexSans-Bold'),
|
||||
url('/fonts/IBMPlexSans-Bold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Sans Light';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: local('IBM Plex Sans Medm Italic'),
|
||||
local('IBMPlexSans-MedmItalic'),
|
||||
url('/fonts/IBMPlexSans-MediumItalic.woff2') format('woff2');
|
||||
src: local('IBM Plex Sans Bold Italic'),
|
||||
local('IBMPlexSans-BoldItalic'),
|
||||
url('/fonts/IBMPlexSans-BoldItalic.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
17
config.toml
@ -13,7 +13,7 @@ pygmentsUseClasses = true
|
||||
|
||||
rssLimit = 10
|
||||
|
||||
copyright = "2024 Daniel Kraus"
|
||||
copyright = "2024-2025 Daniel Kraus"
|
||||
enableEmoji = true
|
||||
|
||||
[permalinks]
|
||||
@ -98,13 +98,17 @@ expiryDate = ["expiryDate"]
|
||||
initialPublish = "Initally Posted on: "
|
||||
human = ["single","posts"]
|
||||
|
||||
[[params.socialLinks]]
|
||||
name = "bluesky"
|
||||
url = "https://bsky.app/profile/bovender.bsky.social"
|
||||
|
||||
[[params.socialLinks]]
|
||||
name = "mastodon"
|
||||
url = "https://neph.social/@daniel_kraus"
|
||||
|
||||
[[params.socialLinks]]
|
||||
name = "x"
|
||||
url = "https://twitter.com/bovender_de"
|
||||
# [[params.socialLinks]]
|
||||
# name = "x"
|
||||
# url = "https://twitter.com/bovender_de"
|
||||
|
||||
[[params.socialLinks]]
|
||||
name = "github"
|
||||
@ -134,3 +138,8 @@ expiryDate = ["expiryDate"]
|
||||
name = "Impressum"
|
||||
url = "impressum/"
|
||||
weight = 30
|
||||
|
||||
[[menu.main]]
|
||||
name = "Cheat sheet"
|
||||
url = "cheatsheet/"
|
||||
weight = 15
|
||||
|
@ -3,12 +3,18 @@ title: "About bovender"
|
||||
toc: true
|
||||
---
|
||||
|
||||
{{< figure src="plesse.png" alt="Image of the Plesse castle" title="The Plesse castle (© Daniel Kraus)">}}
|
||||
|
||||
I'm a physician-scientist from Germany.
|
||||
|
||||
[Bovenden](https://www.bovenden.de) is the name of the village/small town
|
||||
in lovely Lower Saxony, Germany, where I grew up. Hence I'm a bovender --
|
||||
not _the_ bovender, of course, just one of many, but proud to be one :-)
|
||||
|
||||
Not far from our village is the [Plesse
|
||||
castle](https://en.wikipedia.org/wiki/Plesse_Castle) which was built c. 1015 AD
|
||||
and which is one of my favorite places to be.
|
||||
|
||||
Computers have been part of my life ever since I programmed my dad's
|
||||
calculator back in the 1980's.
|
||||
|
||||
@ -16,18 +22,31 @@ calculator back in the 1980's.
|
||||
|
||||
### [ggap-ev.org](https://ggap-ev.org)
|
||||
|
||||
GGAP is a registered charity in Germany. This NGO uses donated money to fund the
|
||||
vocational training of young adults on the Philippines who would otherwise have
|
||||
to "earn" their living in an unlawful way.
|
||||
|
||||
{{< figure src="ggap-ev.png">}}
|
||||
|
||||
### [nephrowiki.de](https://nephrowiki.de)
|
||||
|
||||
NephroWiki is a closed wiki system that has been up and running since 2011.
|
||||
|
||||
{{< figure src="nephrowiki.png">}}
|
||||
|
||||
## Portfolio -- software
|
||||
|
||||
### [Daniel's XL Toolbox](https://xltoolbox.net)
|
||||
|
||||
Daniel's XL Toolbox is an add-in for Excel that assists with data analysis
|
||||
and visualization.
|
||||
|
||||
{{< figure src="xltoolbox.png">}}
|
||||
|
||||
Even though I haven't been able to work on this project for quite some time,
|
||||
I am very happy to see that the latest release has been downloaded more than
|
||||
100,000 times. :-)
|
||||
|
||||
### [LinkTitles](https://github.com/bovender/linktitles)
|
||||
|
||||
LinkTitles is a [MediaWiki](https://mediawiki.org) extension that automatically
|
||||
@ -38,6 +57,10 @@ links terms to existing pages in a Wiki.
|
||||
PubmedParser is a [MediaWiki](https://mediawiki.org) extension to include and
|
||||
reference articles from [Pubmed](https://pubmed.gov) by PMID.
|
||||
|
||||
### Github Star History
|
||||
|
||||
[![Star History Chart][sh-img]][sh-link]
|
||||
|
||||
## Server administration
|
||||
|
||||
I have 10+ years experience with running and administrating my own server.
|
||||
@ -45,3 +68,7 @@ This includes running a mail and an IMAP server, hosting my own
|
||||
[Nextcloud](https://nextcloud.com) and [Gitea](https://gitea.io) instances,
|
||||
[Mastodon for Nephrology](https://neph.social)
|
||||
and more. Almost all of my services are dockerized.
|
||||
|
||||
|
||||
[sh-img]: https://api.star-history.com/svg?repos=bovender/linktitles,bovender/pubmedparser,bovender/imapcli,bovender/xltoolbox&type=Date
|
||||
[sh-link]: https://www.star-history.com/#bovender/linktitles&bovender/pubmedparser&bovender/imapcli&bovender/xltoolbox&Date
|
BIN
content/about/plesse.png
Normal file
After Width: | Height: | Size: 597 KiB |
97
content/cheatsheet.md
Normal file
@ -0,0 +1,97 @@
|
||||
---
|
||||
title: bovender's personal cheat sheet
|
||||
description: >
|
||||
On this page, I collect bits and pieces of information that I
|
||||
never seem to be able to memorize. This stuff is helpful for me
|
||||
and maybe it is helpful for you, too, internet wanderer.
|
||||
date: 2024-11-05T08:00:00+0100
|
||||
draft: false
|
||||
---
|
||||
{{< git-info >}}
|
||||
{{< param "description" >}}
|
||||
|
||||
## R
|
||||
|
||||
### Print R objects so that they can be re-generated from code
|
||||
|
||||
```r
|
||||
# dput takes an R object
|
||||
dput(x, file = "", control = c("keepNA", "keepInteger", "niceNames", "showAttributes"))
|
||||
dget(file, keep.source = FALSE)
|
||||
|
||||
# dump takes a list of R object names
|
||||
dump(list, file = "dumpdata.R", append = FALSE, control = "all", envir = parent.frame(), evaluate = TRUE)
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
``` r
|
||||
library(dplyr)
|
||||
my_data <-
|
||||
starwars |>
|
||||
select(species, homeworld)
|
||||
dput(my_data)
|
||||
#> structure(list(species = c("Human", "Droid", "Droid", "Human",
|
||||
#> "Human", "Human", "Human", "Droid", "Human", "Human", "Human",
|
||||
#> "Human", "Wookiee", "Human", "Rodian", "Hutt", "Human", NA, "Yoda's species",
|
||||
#> "Human", "Human", "Droid", "Trandoshan", "Human", "Human", "Mon Calamari",
|
||||
#> "Human", "Human", "Ewok", "Sullustan", "Human", "Neimodian",
|
||||
#> "Human", "Human", "Gungan", "Gungan", "Gungan", "Human", "Toydarian",
|
||||
#> "Dug", "Human", "Human", "Zabrak", "Twi'lek", "Twi'lek", "Aleena",
|
||||
#> "Vulptereen", "Xexto", "Toong", "Human", "Cerean", "Nautolan",
|
||||
#> "Zabrak", "Tholothian", "Iktotchi", "Quermian", "Kel Dor", "Chagrian",
|
||||
#> NA, NA, "Human", "Geonosian", "Mirialan", "Mirialan", "Human",
|
||||
#> "Human", "Human", "Human", "Clawdite", "Besalisk", "Kaminoan",
|
||||
#> "Kaminoan", "Human", "Droid", "Skakoan", "Muun", "Togruta", "Kaleesh",
|
||||
#> "Wookiee", "Human", NA, "Pau'an", "Human", "Human", "Human",
|
||||
#> "Droid", "Human"), homeworld = c("Tatooine", "Tatooine", "Naboo",
|
||||
#> "Tatooine", "Alderaan", "Tatooine", "Tatooine", "Tatooine", "Tatooine",
|
||||
#> "Stewjon", "Tatooine", "Eriadu", "Kashyyyk", "Corellia", "Rodia",
|
||||
#> "Nal Hutta", "Corellia", "Bestine IV", NA, "Naboo", "Kamino",
|
||||
#> NA, "Trandosha", "Socorro", "Bespin", "Mon Cala", "Chandrila",
|
||||
#> NA, "Endor", "Sullust", NA, "Cato Neimoidia", "Coruscant", "Naboo",
|
||||
#> "Naboo", "Naboo", "Naboo", "Naboo", "Toydaria", "Malastare",
|
||||
#> "Naboo", "Tatooine", "Dathomir", "Ryloth", "Ryloth", "Aleen Minor",
|
||||
#> "Vulpter", "Troiken", "Tund", "Haruun Kal", "Cerea", "Glee Anselm",
|
||||
#> "Iridonia", "Coruscant", "Iktotch", "Quermia", "Dorin", "Champala",
|
||||
#> "Naboo", "Naboo", "Tatooine", "Geonosis", "Mirial", "Mirial",
|
||||
#> "Naboo", "Serenno", "Alderaan", "Concord Dawn", "Zolan", "Ojom",
|
||||
#> "Kamino", "Kamino", "Coruscant", NA, "Skako", "Muunilinst", "Shili",
|
||||
#> "Kalee", "Kashyyyk", "Alderaan", "Umbara", "Utapau", NA, NA,
|
||||
#> NA, NA, NA)), row.names = c(NA, -87L), class = c("tbl_df", "tbl",
|
||||
#> "data.frame"))
|
||||
```
|
||||
|
||||
<sup>Created on 2024-11-05 with [reprex v2.1.1](https://reprex.tidyverse.org)</sup>
|
||||
|
||||
### Calculate percentages of subgroups
|
||||
|
||||
Principle: `Group` the dataset and `summarize` by counting (`n()`), drop the last group
|
||||
while doing so, then `mutate` the dataset by adding the count divided by the sum of counts.
|
||||
|
||||
Hint to better understand the example: Look at the sexes in black-eyed subjects.
|
||||
|
||||
``` r
|
||||
library(dplyr)
|
||||
starwars |>
|
||||
group_by(eye_color, gender) |>
|
||||
summarize(n = n(), .groups = "drop_last") |>
|
||||
mutate(p = n/sum(n))
|
||||
#> # A tibble: 23 × 4
|
||||
#> # Groups: eye_color [15]
|
||||
#> eye_color gender n p
|
||||
#> <chr> <chr> <int> <dbl>
|
||||
#> 1 black feminine 2 0.2
|
||||
#> 2 black masculine 8 0.8
|
||||
#> 3 blue feminine 6 0.316
|
||||
#> 4 blue masculine 12 0.632
|
||||
#> 5 blue <NA> 1 0.0526
|
||||
#> 6 blue-gray masculine 1 1
|
||||
#> 7 brown feminine 4 0.190
|
||||
#> 8 brown masculine 15 0.714
|
||||
#> 9 brown <NA> 2 0.0952
|
||||
#> 10 dark masculine 1 1
|
||||
#> # ℹ 13 more rows
|
||||
```
|
||||
|
||||
<sup>Created on 2024-11-05 with [reprex v2.1.1](https://reprex.tidyverse.org)</sup>
|
@ -3,15 +3,16 @@ title: "Impressum und Datenschutz"
|
||||
date: 2024-07-31T12:42:53Z
|
||||
draft: false
|
||||
---
|
||||
|
||||
Dr. Daniel Kraus
|
||||
H‌ö‌hen‌str‌aße 1‌5
|
||||
65451 K‌e‌l‌s‌t‌e‌r‌b‌a‌c‌h
|
||||
Tel. (0 61 07‌) 7 5‌6 88 4‌0
|
||||
<bovender@bovender.de>
|
||||
Mail: <bovender@bovender.de>
|
||||
|
||||
Ich bitte, von Anrufen abzusehen. Über Mail oder die verlinkten
|
||||
sozialen Netzwerke (siehe Icons) bin ich i.d.R. kurzfristig
|
||||
Ladungsfähige Anschrift bei meinem Arbeitgeber: Unimedizin Mainz, Langenbeckstr.
|
||||
1, 55131 Mainz. Dies ist eine rein private Homepage und in keiner Weise von
|
||||
meinem Arbeitgeber beworben oder unterstützt. Meine Privatanschrift ist zu
|
||||
meinem persönlichen Schutz und dem Schutz meiner Familie hier nicht
|
||||
veröffentlicht. **Ich bitte, von Anrufen abzusehen.** Über Mail oder die
|
||||
verlinkten sozialen Netzwerke (siehe Icons) bin ich i.d.R. kurzfristig
|
||||
erreichbar.
|
||||
|
||||
## Mailserver bovender.de
|
||||
|
215
content/posts/2024/dane-tlsa-record-for-letsencrypt/index.md
Normal file
@ -0,0 +1,215 @@
|
||||
---
|
||||
title: "How to create or renew a TLSA record for DANE with certificates from Let's Encrypt"
|
||||
slug: create-or-renew-tlsa-records
|
||||
description: >
|
||||
I had to renew my TLSA records for DNS-based Authentication of Named Entities (DANE)
|
||||
on my server that uses SSL certificates from Let's Encrypt.
|
||||
date: 2024-10-03T09:26:58Z
|
||||
draft: false
|
||||
ShowLastmod: true
|
||||
toc: true
|
||||
scrolltotop: true
|
||||
tags:
|
||||
- email
|
||||
- server
|
||||
- security
|
||||
---
|
||||
|
||||
I have been operating my own mail server for some 10 years. Recently, some
|
||||
e-mails that others attempted to send to me any my family would not longer be
|
||||
delivered. This is a very unfortunate situation, because most senders will not
|
||||
make a second attempt (e.g., with a different recipient address), leave alone
|
||||
provide you with an error message. However, luckily, this morning (Reunification
|
||||
Day in Germany!), I received this screenshot:
|
||||
|
||||
{{< figure src="outlook-error.jpg"
|
||||
alt="(German) screenshot of an e-mail delivery error due to an invalid TLSA record"
|
||||
caption="(German) screenshot of an e-mail delivery error due to an invalid TLSA record">}}
|
||||
|
||||
And then it was all clear to me. The resource records (RR) in my domain-name
|
||||
system (DNS) configuration that configure [DNS-based Authentication of Named
|
||||
Entities (DANE)][dane] were no longer valid. I use certificates issued by Let's
|
||||
Encrypt, and evidently their chain of trust had changed so that the trust
|
||||
anchors that I had written into my DNS records were no longer valid.
|
||||
|
||||
Correctly setting up TLSA records for DANE is everything but trivial. After some
|
||||
trial and error, I found the following resource most useful:
|
||||
|
||||
<https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html>
|
||||
|
||||
Key points from this and other pages to remember:
|
||||
|
||||
- When using TLSA RR in the form `2 1 1 ...`, i.e., declaring that the payload
|
||||
(`...`) of the record is the digest of a "trust anchor", be aware that this
|
||||
must be the `SHA256` digest of the _public key_ of your trust anchor.
|
||||
- Let's Encrypt's `certbot` tool places three files on your server: `cert.pem`,
|
||||
`chain.pem` and `fullchain.pem`, where `cert.pem` is the mail server's
|
||||
certificate, `chain.pem` is the trust chain _excluding the root CA_ and
|
||||
`fullchain.pem` is `cert.pem` + `chain.pem`. The important bit here is that
|
||||
**none of these certificate files contain the root CA**!
|
||||
- As a consequence, do not use a digest of Let's Encrypt's root CAs in your TLSA
|
||||
record, _unless_ you want to add that root CA to the certificate files on your
|
||||
server (don't).
|
||||
- Configure TLSA records for _all_ intermediate CAs, e.g., R10-R14.
|
||||
|
||||
Interstingly and embarassingly, the Information Sciences Institute (ISI) on
|
||||
their page linked to above has a list of mail servers that still use a TLSA
|
||||
record with a _retired_ CA from Let's Encrypt -- and that list contains
|
||||
`bovender.de' :-/ I guess it's about time to fix that!
|
||||
|
||||
## Let's Encrypt's chains of trust
|
||||
|
||||
Let's Encrypt's chains of trust are described here:
|
||||
|
||||
<https://letsencrypt.org/certificates/>
|
||||
|
||||
For the reasons mentioned above, we are not interested in the root CAs (ISRG
|
||||
Root X1 and ISRG Root X2). Instead, we want to use the digests of the public
|
||||
keys of the subordinate (intermediate) CAs. At the time of writing (2024-10),
|
||||
Let's Encrypt lists four active intermediate CAs:
|
||||
|
||||
- E5 and E6 for certificates with ECDSA public keys
|
||||
- R10 and R11 for certificates with RSA public keys
|
||||
|
||||
To find out which of the two algorithms (ECDSA and RSA) was used to generate
|
||||
your mail server's certificate, ssh into your server, navigate to
|
||||
`/etc/letsencrypt/live/<mailserver-certificate-name>` as root and issue:
|
||||
|
||||
```text
|
||||
$ openssl x509 -in cert.pem -noout -text
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
03:d3:73:ef:60:97:31:88:bc:e5:31:99:f3:00:d5:b0:c1:92
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C = US, O = Let's Encrypt, CN = R11
|
||||
Validity
|
||||
Not Before: Sep 24 22:37:51 2024 GMT
|
||||
Not After : Dec 23 22:37:50 2024 GMT
|
||||
Subject: CN = bovender.de
|
||||
Subject Public Key Info:
|
||||
# ...
|
||||
```
|
||||
|
||||
Thus, my mail server's current (!) certificate was issued by **R11**.
|
||||
|
||||
This may be different in the future when the certificate is renewed.
|
||||
|
||||
Currently my web server's certificate uses the ECDSA algorithm:
|
||||
|
||||
```text
|
||||
$ cd ../bovender/
|
||||
$ openssl x509 -in cert.pem -noout -text
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
04:22:00:17:8a:ed:51:09:56:15:62:2e:b5:85:49:70:05:ac
|
||||
Signature Algorithm: ecdsa-with-SHA384
|
||||
Issuer: C = US, O = Let's Encrypt, CN = E6
|
||||
Validity
|
||||
Not Before: Aug 19 11:34:11 2024 GMT
|
||||
Not After : Nov 17 11:34:10 2024 GMT
|
||||
Subject: CN = bovender.de
|
||||
```
|
||||
|
||||
This certificate was issued by the **E6** intermediate CA.
|
||||
|
||||
An alternative way to find out more about a web server's SSL certificate is to
|
||||
use `curl`:
|
||||
|
||||
```plain
|
||||
$ curl -I --write-out '%{certs}' https://bovender.de
|
||||
HTTP/2 301
|
||||
server: nginx/1.27.1
|
||||
date: Thu, 03 Oct 2024 09:25:05 GMT
|
||||
content-type: text/html
|
||||
content-length: 169
|
||||
location: https://www.bovender.de/
|
||||
strict-transport-security: max-age=63072000; includeSubDomains; preload
|
||||
|
||||
# ...
|
||||
|
||||
Subject:C = US, O = Let's Encrypt, CN = E6
|
||||
Issuer:C = US, O = Internet Security Research Group, CN = ISRG Root X1
|
||||
|
||||
# ...
|
||||
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
E6 again (surprise!).
|
||||
|
||||
The key type that `certbot` uses to renew certificates is contained in
|
||||
`/etc/letsencrypt/renewal/<mailserver-certificate-name>.conf`:
|
||||
|
||||
```plain
|
||||
$ cat mail.conf
|
||||
# renew_before_expiry = 30 days
|
||||
version = 2.11.0
|
||||
archive_dir = /etc/letsencrypt/archive/mail
|
||||
cert = /etc/letsencrypt/live/mail/cert.pem
|
||||
privkey = /etc/letsencrypt/live/mail/privkey.pem
|
||||
chain = /etc/letsencrypt/live/mail/chain.pem
|
||||
fullchain = /etc/letsencrypt/live/mail/fullchain.pem
|
||||
|
||||
# Options used in the renewal process
|
||||
[renewalparams]
|
||||
account = [REDACTED]
|
||||
authenticator = webroot
|
||||
server = https://acme-v02.api.letsencrypt.org/directory
|
||||
key_type = rsa
|
||||
# ...
|
||||
```
|
||||
|
||||
The line `key_type` declares that RSA be used for my mail server's certificate.
|
||||
|
||||
## Setting up TLSA RRs in your DNS zone
|
||||
|
||||
As advised by [ISI.edu][isi], it is best practive to have TLSA records for all
|
||||
possible intermediate CAs as you will never know which intermediate CA will be
|
||||
the next to issue a renewed certificate. This is even more important if you have
|
||||
a cron job set up to automatically renew certificates that are about to expire.
|
||||
|
||||
For the record (pun intended), here are my `_25._tcp` entries. Everything after
|
||||
the pound sign (`#`) MUST NOT be included in the record, of course.
|
||||
|
||||
```plain
|
||||
2 1 1 2bbad93ab5c79279ec121507f272cbe0c6647a3aae52e22f388afab426b4adba # R10
|
||||
2 1 1 6ddac18698f7f1f7e1c69b9bce420d974ac6f94ca8b2c761701623f99c767dc7 # R11
|
||||
```
|
||||
|
||||
Following the advice by _viktor_ on [ISI.edu][isi], I have left only those two
|
||||
records in my DNS zone that represent currently used intermediate CAs (R10 and
|
||||
R11). I know that `certbot` will not issue ECDSA certificates for my mail server
|
||||
because the configuration file (see above) contains the line `key_type=RSA`. My
|
||||
web server has an ECDSA certificate, but I currently see no use for DANE for my
|
||||
web server as [Chrome and Firefox do not support it][dane].
|
||||
|
||||
## Verify the validity of the TLSA record
|
||||
|
||||
To test that DANE works as expected, try one of these sites:
|
||||
|
||||
- <https://www.mailhardener.com/tools/dane-validator?domain=bovender.de>
|
||||
- <https://dane.sys4.de/smtp/bovender.de>
|
||||
|
||||
Query TLSA records:
|
||||
|
||||
- <https://www.nslookup.io/domains/_25._tcp.bovender.de/dns-records/tlsa/>
|
||||
|
||||
## "Die Moral von der Geschicht"
|
||||
|
||||
"The moral of the story":
|
||||
|
||||
- Server administration was, is, and will always be complicated.
|
||||
- Always mistrust yourself.
|
||||
- Regularly verify that everything works as expected, especially
|
||||
security-related stuff.
|
||||
- If something does not work, spend more time researching on the world wide web.
|
||||
I came across the [ISI.edu][isi] page only after several hours and is was far
|
||||
more useful for me than all the websites and blog and forum posts that I had
|
||||
previously read.
|
||||
|
||||
[dane]: https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities
|
||||
[isi]: https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html
|
After Width: | Height: | Size: 306 KiB |
BIN
content/posts/2024/halloween/IMGP8429_G.JPG
Normal file
After Width: | Height: | Size: 399 KiB |
BIN
content/posts/2024/halloween/IMGP8436_G.JPG
Normal file
After Width: | Height: | Size: 256 KiB |
BIN
content/posts/2024/halloween/IMGP8437_G.JPG
Normal file
After Width: | Height: | Size: 268 KiB |
90
content/posts/2024/halloween/index.md
Normal file
@ -0,0 +1,90 @@
|
||||
---
|
||||
title: My gripes with Halloween in Germany
|
||||
description: >
|
||||
Celebrating Halloween in Germany is a relatively new phenomenon that
|
||||
I believe is a manifestation of the ego-centered and hedonistic
|
||||
state of the German society.
|
||||
date: 2024-10-31T23:00:00+0200
|
||||
draft: false
|
||||
ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images:
|
||||
- IMGP8436_G.JPG
|
||||
tags:
|
||||
- opinion
|
||||
---
|
||||
|
||||
{{< figure src="IMGP8429_G.JPG" alt="Halloween in Jamaica Plain, 2009"
|
||||
title="Halloween in '09, Jamaica Plain, Boston, MA © Daniel Kraus">}}
|
||||
|
||||
In the three years that I lived in Boston, Massachusetts, while persuing my
|
||||
postdoctoral fellowship at [Beth Israel Deaconess Medical Center][bidmc],
|
||||
Halloween was a wonderful event. We had a little appartment literally under the
|
||||
roof of a very nice and welcoming family in Boston's Jameica Plain
|
||||
neighbourhood. The family was not just our landlords -- they quickly became
|
||||
friends. We celebrated all kinds of events together: the [Red Sox' Win of the
|
||||
World Series in 2007][sox], birthdays, Thanksgiving, ... and [Halloween][].
|
||||
|
||||
{{< figure src="IMGP8436_G.JPG" alt="Halloween in Jamaica Plain, 2009"
|
||||
title="Halloween in '09, Jamaica Plain, Boston, MA © Daniel Kraus">}}
|
||||
|
||||
Halloween has a long tradition in the United States and elsewhere. Where we used
|
||||
to live in Boston, the entire street celebrated together. The street was divided
|
||||
into two halves that took turns in organizing the event each year. Everybody met
|
||||
outside. There was live music, and of course the kids did the trick-or-treat thing.
|
||||
I loved it.
|
||||
|
||||
{{< figure src="IMGP8437_G.JPG" alt="Halloween in Jamaica Plain, 2009"
|
||||
title="Halloween in '09, Jamaica Plain, Boston, MA © Daniel Kraus">}}
|
||||
|
||||
Growing up in Germany in the 1980s, I was accustomed to [St. Martin's
|
||||
Day][martin] on or around 11 November in commemoration of St. Martin of Tours
|
||||
who is said to have divided his coat to share it with a poor person.
|
||||
|
||||
We would walk through our neighbourhood, ring people's door bells, and when
|
||||
someone opened we would sing a song about St. Martin and ask for sweets. When I
|
||||
thought about this now and before it occurred to me to write a blog post about
|
||||
this, I seemed to remember that we would afterwards give most of the sweets to
|
||||
children in need (refugees, in fact) that had found shelter in a nearby
|
||||
facility. However, I now believe that we did this only on a similar occasion in
|
||||
early January when we celebrated [Epiphany with the Star singers][epiphany]
|
||||
which also involved walking around, singing, and collecting sweets. So St.
|
||||
Martin's day had a lot to do with asking for sweets for our own consumption and
|
||||
pleasure and not so much about caring and sharing, and this is important to keep
|
||||
in mind. It is also important to realize that this tradition around St. Martin
|
||||
was a regional thing and nothing nationwide (as I learned from an [article on
|
||||
Wikipedia][martin-in-germany]).
|
||||
|
||||
In recent years, Halloween has grown very strong in Germany, and I believe that
|
||||
this is a result of deliberately injecting the tradition into our culture.
|
||||
Interestingly, this is also [Wikipedia's view][germany] (see references in the
|
||||
linked article).
|
||||
|
||||
And that's my gripe with celebrating Halloween in Germany. There's nothing wrong
|
||||
with partying and having a good time with friends and family. But this event is
|
||||
tightly linked to buying and consuming stuff, and it is driven by "the
|
||||
industry". Again, there's nothing wrong in itself with "the industry" trying to
|
||||
sell stuff to people. But I do think that this is an example of how people can
|
||||
be made to do things. Just like [lemmings][], everybody is following suit.
|
||||
|
||||
Halloween in Germany, as I see it, is a festival of hedonism. It has nothing to
|
||||
to with sharing, it has nothing to do with taking a break and thinking about the
|
||||
[faithful departed][halloween], but it has a lot to do with buying stuff and
|
||||
consuming stuff that you don't really need.
|
||||
|
||||
For me, Halloween in Germany is an example for the state of our society.
|
||||
|
||||
---
|
||||
|
||||
Having said that, I greatly enjoyed the more or less spontaneous Halloween party
|
||||
that we had at our neighbors' place tonight ;-)
|
||||
|
||||
[bidmc]: https://bidmc.org
|
||||
[epiphany]: https://en.wikipedia.org/wiki/Star_singers
|
||||
[germany]: https://en.wikipedia.org/wiki/Geography_of_Halloween#Germany
|
||||
[halloween]: https://en.wikipedia.org/wiki/Halloween
|
||||
[lemmings]:https://en.wikipedia.org/wiki/St._Martin%27s_Day
|
||||
[martin]: https://en.wikipedia.org/wiki/St._Martin%27s_Day
|
||||
[martin-in-germany]: https://en.wikipedia.org/wiki/Martinisingen#Present-day_customs
|
||||
[sox]: https://en.wikipedia.org/wiki/2007_World_Series
|
@ -248,6 +248,27 @@ replace `ffmpeg-free` with the non-free `ffmpeg` on F40:
|
||||
After doing that and restarting Kdenlive, I was able to render my project using
|
||||
the H.264 and H.265 codecs as I used to be able to do with Ubuntu-based systems.
|
||||
|
||||
## Update 2024-11-10
|
||||
|
||||
In the last couple of months, battery life has improved significantly. As
|
||||
described above, in summer, battery drained almost completely (from ~90% to
|
||||
~15%) within 3.5 hours even without heavy workload.
|
||||
|
||||
Today I spent about the same amount of time on a train, working constantly on my
|
||||
laptop (browsing, downloading articles), and the battery level only dropped from
|
||||
~90% to ~40% within 3 hours. Some system update, be it a kernel update or some
|
||||
other software running in the background, must have reduced energy consumption
|
||||
considerably :-)
|
||||
|
||||
{{< figure src="p14s-battery-drain-2.png">}}
|
||||
|
||||
(I am well aware that there are laptops whose battery run time is in an entirely
|
||||
different ball park, and even some of my own Thinkpads used to do better, but
|
||||
I'm overall quite happy with battery life on this machine with bright 3k display
|
||||
and dedicated GPU. I _could_ have bought a machine which can run on battery like
|
||||
forever, but that's not my use case and plus, I'd never buy anything else but a
|
||||
Thinkpad...)
|
||||
|
||||
[Darktable]: https://darktable.org
|
||||
[fancontrol]: https://ounapuu.ee/posts/2022/09/26/minimum-viable-fan-control-script/
|
||||
[Fedora]: https://fedoraproject.org/
|
||||
|
BIN
content/posts/2024/p14s/p14s-battery-drain-2.png
Normal file
After Width: | Height: | Size: 188 KiB |
@ -29,3 +29,12 @@ Link: <https://kde.org/announcements/plasma/5/5.27.0/>
|
||||
|
||||
I wish there were keyboard shortcuts to move windows into one of the custom tile
|
||||
layouts as well: <https://discuss.kde.org/t/keyboard-shortcuts-for-new-tiling-feature/1843>
|
||||
|
||||
---
|
||||
|
||||
### Added 2025-03-02
|
||||
|
||||
With Plasma 5.3, you can now define keyboard shortcuts to move a window to
|
||||
a custom tile. On my system, there were now shortcuts defined by default, but
|
||||
it is very easy to do so in `System Settings > Shortcuts > KWin`. I have now
|
||||
mapped `META`+`SHIFT` and the arrow keys to move windows to custom tiles.
|
||||
|
@ -0,0 +1,85 @@
|
||||
---
|
||||
title: "Reconcile Docker With Deutsche Bahn"
|
||||
description: >
|
||||
If WiFi does not work on Deutsche Bahn's ICE trains and you have Docker installed,
|
||||
there may be network interference which can be fixed easily.
|
||||
date: 2024-09-26T09:07:30Z
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
#featuredImg: reconcile-docker-with-deutsche-bahn.png
|
||||
tags:
|
||||
- network
|
||||
- Deutsche Bahn
|
||||
- Docker
|
||||
- travel
|
||||
---
|
||||
|
||||

|
||||
|
||||
If you happen to be a (Linux) power user travelling on a Deutsche Bahn [ICE
|
||||
long-distance train][ice] and you wonder why you don't get a working network
|
||||
connection with the complemenatary "WIFIonICE" wireless network, there may be a
|
||||
network interference on your laptop.
|
||||
|
||||
There are multiple solutions for this on the web. My favorite solution is to
|
||||
change Docker's network configuration by editing (or creating) the file
|
||||
`/etc/docker/daemons.json`. However, you may need to prune existing Docker
|
||||
networks first. Otherwise the Docker service will fail to start with the
|
||||
following message:
|
||||
|
||||
```plain
|
||||
failed to start daemon: Error initializing network controller: error creating default "bridge" network: all predefined address pools have been fully subnetted
|
||||
```
|
||||
|
||||
Therefore, I recommend the following steps (this is on a Fedora Linux system with *systemd*):
|
||||
|
||||
1. Stop any docker containers that you may have running, including services managed by docker compose.
|
||||
2. Prune the networks:
|
||||
|
||||
```bash
|
||||
docker network prune
|
||||
```
|
||||
|
||||
3. Create or edit `/etc/docker/daemon.json` so that it contains the following:
|
||||
|
||||
```plain
|
||||
{
|
||||
"default-address-pools":
|
||||
[
|
||||
{"base":"172.19.0.0/16","size":24}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
4. Restart docker:
|
||||
|
||||
```bash
|
||||
systemctl restart docker
|
||||
```
|
||||
|
||||
5. Connect to `WIFIonICE` and enjoy your network connection :-)
|
||||
|
||||
## References
|
||||
|
||||
- StackExchange answer that provides the solution as presented here -- see also
|
||||
the answer about pruning the networks below.
|
||||
|
||||
<https://unix.stackexchange.com/a/539258/110635>
|
||||
|
||||
- If you don't want to or cannot configure your Docker networks, you can also
|
||||
turn Docker off and on again when you travel:
|
||||
|
||||
<https://kuttler.eu/code/ice-wlan-linux-docker/>
|
||||
|
||||
This is what I used to do myself, but nowadays I prefer to just configure the
|
||||
Docker network differently.
|
||||
|
||||
- There are many more internet sources (and I have just added another one...), I
|
||||
won't copy all those links into my post, see DuckDuckGo search results
|
||||
for yourself:
|
||||
|
||||
<https://duckduckgo.com/?q=docker+wifi+on+ice>
|
||||
|
||||
[ice]: https://int.bahn.de/en/trains/long-distance-trains
|
After Width: | Height: | Size: 750 KiB |
BIN
content/posts/2025/install-pynitrokey/IMGP0069.jpg
Normal file
After Width: | Height: | Size: 213 KiB |
58
content/posts/2025/install-pynitrokey/index.md
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Install pynitrokey on Fedora 41
|
||||
description: Here's how I installed pynitrokey on my Fedora 41 KDE laptop, resolving missing dependencies.
|
||||
date: 2025-03-30T10:53:35+0100
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images: []
|
||||
tags:
|
||||
- security
|
||||
- Linux
|
||||
- Fedora
|
||||
---
|
||||
|
||||
{{< figure src="IMGP0069.jpg"
|
||||
alt="My Nitrokey 3A mini"
|
||||
title="My Nitrokey 3A mini on the right side of the picture" >}}
|
||||
|
||||
I use [Yubikey][]s and [Nitrokey][]s as a second factor during 2FA
|
||||
authentication.
|
||||
|
||||
My experiences with Nitrokey devices have been mixed. Currently my 3A mini
|
||||
stopped working. I wanted to investigate what's going on, only to find out that
|
||||
the commandline tool `nitropy` no longer worked on my machine either! :-(
|
||||
|
||||
Here's how I got it to work again. I'm a Python noob, so maybe there's a better
|
||||
way to install the dependencies. The operating system is Fedora 41.
|
||||
|
||||
```bash
|
||||
sudo dnf install systemd-devel python3-devel
|
||||
pipx install pynitrokey
|
||||
```
|
||||
|
||||
Afterwards I was greeted with this:
|
||||
|
||||
```text
|
||||
$ nitropy nk3 test
|
||||
Command line tool to interact with Nitrokey devices 0.8.1
|
||||
Critical error:
|
||||
No connected NK3 devices found
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
Critical error occurred, exiting now
|
||||
Unexpected? Is this a bug? Would you like to get support/help?
|
||||
- You can report issues at: https://support.nitrokey.com/
|
||||
- Writing an e-mail to support@nitrokey.com is also possible
|
||||
- Please attach the log: '/tmp/nitropy.log._p6mpa3e' with any support/help request!
|
||||
- Please check if you have udev rules installed: https://docs.nitrokey.com/nitrokeys/nitrokey3/firmware-update#troubleshooting-linux
|
||||
```
|
||||
|
||||
I made sure that I had the abovementioned `udev` rules in place. The key is not
|
||||
detected by any system, be it my personal Linux laptop or any Windows machine
|
||||
that I could access. [D'oh][]!
|
||||
|
||||
[Nitrokey]: https://www.nitrokey.com
|
||||
[Yubikey]: https://www.yubico.com
|
||||
[d'oh]: https://en.wikipedia.org/wiki/D'oh!
|
BIN
content/posts/2025/leaving-x/account-deactivated.png
Normal file
After Width: | Height: | Size: 48 KiB |
40
content/posts/2025/leaving-x/index.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
title: Leaving X
|
||||
description: German academic institutions are leaving Twitter/X. I'm not an academic institution, but still I'm following suit.
|
||||
date: 2025-01-14T21:30:00+0100
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images: []
|
||||
tags:
|
||||
- academia
|
||||
- social media
|
||||
---
|
||||
Several academic institutions in Germany have decided to terminate their
|
||||
presence on X, formerly known as Twitter.
|
||||
|
||||
Press release of the "Informationsdienst Wissenschaft" (scientific news service,
|
||||
in German): <https://idw-online.de/de/news845520>
|
||||
|
||||
Ironically, the press release page has several buttons to share this information
|
||||
on social media, right now still including a sharing button for X :smile:
|
||||
Surely just a matter of time.
|
||||
|
||||
{{< figure src="press-release-with-x-sharing-button.png"
|
||||
title="Press release (in German) informing about German academic institutions leaving X, with X sharing button." >}}
|
||||
|
||||
I got aware of this by reading my former university's newsletter:
|
||||
<https://www.uni-wuerzburg.de/aktuelles/einblick/single/news/universitaet-wuerzburg-kehrt-plattform-x-den-ruecken-1>
|
||||
|
||||
I'm following suit. I've just now deleted my account on X.
|
||||
|
||||
{{< figure src="account-deactivated.png"
|
||||
title="I did it! My account on X has been deactivated. (Screenshot in German.)" >}}
|
||||
|
||||
If you would like to connect with me on social media, please head over to my profiles on [Mastodon][] or [Bluesky][].
|
||||
|
||||
See you!
|
||||
|
||||
[Mastodon]: https://neph.social/@daniel_kraus
|
||||
[Bluesky]: https://bsky.app/profile/bovender.bsky.social
|
After Width: | Height: | Size: 105 KiB |
80
content/posts/2025/media-mounts-at-dm/index.md
Normal file
@ -0,0 +1,80 @@
|
||||
---
|
||||
title: "[In German] USB-Sticks in den Fotostationen von dm"
|
||||
description:
|
||||
date: 2025-03-22T22:20:07+0100
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images: []
|
||||
tags:
|
||||
- German
|
||||
---
|
||||
|
||||
(This post is in German.)
|
||||
|
||||
In den letzten Wochen habe ich ein paar Mal Fotoabzüge benötigt und bin mit
|
||||
einem USB-Stick zur örtlichen Drogerie. Zu meiner Überraschung konnten keinerlei
|
||||
Bilder auf dem Stick gefunden werden. Inzwischen habe ich das mit mehreren
|
||||
Sticks und an verschiedenen Foto-Stationen (aber immer in demselben Laden)
|
||||
probiert, Fehlanzeige. Interessanterweise hat es mit einer SD-Karte problemlos
|
||||
geklappt.
|
||||
|
||||
Offenbar bin ich weder der erste noch der einzige, der dieses Problem schon
|
||||
einmal hatte, es gibt zu einem ähnlichen Problem mit einer CEWE-Fotostation
|
||||
einen [Forumsthread][].
|
||||
|
||||
In diesem Blog-Beitrag sammele ich einfach mal meine Beobachtungen, vielleicht
|
||||
hilft es ja einmal jemandem. Von Mal zu Mal werde ich dies updaten.
|
||||
|
||||
## Beispiele für "geht" und "geht nicht"
|
||||
|
||||
Ich hatte zuletzt zwei Speichermedien dabei, einen USB-Stick und eine SD-Karte:
|
||||
|
||||
```plain
|
||||
$ lsblk -f
|
||||
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
|
||||
sda
|
||||
└─sda1 exfat 1.0 [REDACTED] E7F3-FDF9 114,5G 0% /run/media/daniel/[REDACTED]
|
||||
sdb
|
||||
└─sdb1 exfat 1.0 7FDE-A701 119G 0% /run/media/daniel/7FDE-A701
|
||||
```
|
||||
|
||||
`sda` ist ein USB-Stick, den ich häufig in anderen Zusammenhängen im Einsatz
|
||||
habe. `sdb` ist eine ältere SD-Karte. Beide haben nominell 128 GB Kapazität, und
|
||||
beide haben eine Partitionstabelle im herkömmlichen MSDOS-Format und eine
|
||||
Primärpartition, die mit dem Dateisystem EXFAT formatiert ist. Das Dateisystem
|
||||
auf dem USB-Stick hat ein Label, welches aus wenigen Buchstaben ohne
|
||||
Sonderzeichen besteht.
|
||||
|
||||
Auf beiden Speichermedien hatte ich denselben Foto-Ordner kopiert, mit etwa
|
||||
einer Handvoll Fotos. Die Bilder lagen also auf beiden Medien in einem
|
||||
Unterorder.
|
||||
|
||||
**Interessanterweise wurden die Bilder auf der SD-Karte gefunden, die Bilder auf
|
||||
dem USB-Stick jedoch nicht.**
|
||||
|
||||
Hier meine Beobachtungen im einzelnen, denn entsprechende Überlegungen findet
|
||||
man auch im Netz:
|
||||
|
||||
### Dateisystem
|
||||
|
||||
Bevor ich es sowohl mit dem Stick als auch mit der SD-Karte probierte, habe ich
|
||||
folgende Dateisysteme auf dem USB-Stick ausprobiert:
|
||||
|
||||
- EXFAT
|
||||
- FAT32
|
||||
|
||||
Mit beiden Dateisystemen wurden keine Bilder gefunden.
|
||||
|
||||
### Root-Verzeichnis vs. Unterverzeichnis
|
||||
|
||||
Es hat keinen Unterschied gemacht, ob ich die Bilder (JPG-Dateien) im
|
||||
Wurzelverzeichnis oder in einem Unterordner auf dem Stick hatte.
|
||||
|
||||
### Verschiedene Terminals
|
||||
|
||||
Ich habe meinen USB-Stick an verschiedenen Foto-Terminals ausprobiert, an keinem
|
||||
von ihnen wurden die Bilder gefunden.
|
||||
|
||||
[Forumsthread]: https://www.cewe-community.com/forum/fb/viewtopic.php?t=13036&p=135162
|
After Width: | Height: | Size: 130 KiB |
127
content/posts/2025/nvidia-drivers-on-fedora/index.md
Normal file
@ -0,0 +1,127 @@
|
||||
---
|
||||
title: "Nvidia Drivers on Fedora"
|
||||
description: >
|
||||
My own up-to-date instructions for installing Nvidia drivers on a Fedora Linux system.
|
||||
date: 2025-03-02T08:28:26Z
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images: []
|
||||
tags:
|
||||
- nvidia
|
||||
- fedora
|
||||
- linux
|
||||
---
|
||||
|
||||
My [Thinkpad P14s]({{< relref "p14s" >}}) has a dedicated Nvidia GPU, which
|
||||
requires proprietary drivers. There is a gazillion of instructions on the web
|
||||
for installing theses drivers on a Fedora system. Every now and then (with
|
||||
kernel updates, I guess), my drivers stop working and I have to research _again_
|
||||
how to (re-)install these drivers. Usually I notice this when developing raw
|
||||
images with [Darktable][]. It gets dead slow and then I find out that OpenCL is
|
||||
not working.
|
||||
|
||||
This post mainly serves as a reminder for myself how to re-install the NVidia
|
||||
drivers on a Fedora laptop. It should be fairly up to date, because as I wrote,
|
||||
I keep running into this problem over and over again.
|
||||
|
||||
The prerequisite is to have the [RPM Fusion][] repositories enabled.
|
||||
|
||||
{{< figure src="discover-settings-rpm-fusion.png" >}}
|
||||
|
||||
## Installing the NVidia drivers
|
||||
|
||||
I found out that I basically only need two packages:
|
||||
|
||||
- `nvidia-settings` and
|
||||
- `xorg-x11-drv-nvidia-cuda`
|
||||
|
||||
The first one suffices to pull in the actual drivers and other packages as
|
||||
dependencies. The latter is required in order for Darktable to make use of OpenCL.
|
||||
|
||||
```fish
|
||||
sudo dnf install nvidia-settings xorg-x11-drv-nvidia-cuda
|
||||
```
|
||||
|
||||
```plain
|
||||
Updating and loading repositories:
|
||||
Repositories loaded.
|
||||
Package Arch Version Repository Size
|
||||
Installing:
|
||||
nvidia-settings x86_64 3:570.86.16-1.fc41 rpmfusion-nonfree-updates 4.4 MiB
|
||||
Installing dependencies:
|
||||
akmod-nvidia x86_64 3:570.86.16-3.fc41 rpmfusion-nonfree-updates 92.4 KiB
|
||||
egl-gbm x86_64 2:1.1.2^20240919gitb24587d-3.fc41 fedora 29.3 KiB
|
||||
egl-wayland x86_64 1.1.18~20250114git26ba0e3-2.fc41 updates 80.9 KiB
|
||||
egl-x11 x86_64 1.0.1~20241213git61e70b0-1.fc41 updates 161.1 KiB
|
||||
nvidia-modprobe x86_64 3:570.86.16-1.fc41 rpmfusion-nonfree-updates 51.0 KiB
|
||||
xorg-x11-drv-nvidia x86_64 3:570.86.16-5.fc41 rpmfusion-nonfree-updates 190.2 MiB
|
||||
xorg-x11-drv-nvidia-kmodsrc x86_64 3:570.86.16-5.fc41 rpmfusion-nonfree-updates 75.4 MiB
|
||||
xorg-x11-drv-nvidia-libs x86_64 3:570.86.16-5.fc41 rpmfusion-nonfree-updates 361.9 MiB
|
||||
Installing weak dependencies:
|
||||
xorg-x11-drv-nvidia-cuda-libs x86_64 3:570.86.16-5.fc41 rpmfusion-nonfree-updates 273.2 MiB
|
||||
xorg-x11-drv-nvidia-power x86_64 3:570.86.16-5.fc41 rpmfusion-nonfree-updates 233.7 KiB
|
||||
|
||||
Transaction Summary:
|
||||
Installing: 11 packages
|
||||
|
||||
Total size of inbound packages is 351 MiB. Need to download 114 KiB.
|
||||
After this operation, 906 MiB extra will be used (install 906 MiB, remove 0 B).
|
||||
Is this ok [y/N]:
|
||||
```
|
||||
|
||||
## Testing the installation
|
||||
|
||||
```fish
|
||||
inxi -G
|
||||
```
|
||||
|
||||
This will output the following if everything is configured correctly.
|
||||
|
||||
```plain
|
||||
Graphics:
|
||||
Device-1: Intel Meteor Lake-P [Intel Arc Graphics] driver: i915 v: kernel
|
||||
Device-2: NVIDIA AD107GLM [RTX 500 Ada Generation Laptop GPU]
|
||||
driver: nvidia v: 570.86.16
|
||||
Device-3: Syntek Integrated Camera driver: uvcvideo type: USB
|
||||
Display: wayland server: Xwayland v: 24.1.6 compositor: kwin_wayland
|
||||
driver: gpu: i915 resolution: 1: 3840x2160~60Hz 2: 3072x1920
|
||||
API: EGL v: 1.5 drivers: iris,nvidia
|
||||
platforms: gbm,wayland,x11,surfaceless,device
|
||||
API: OpenGL v: 4.6.0 compat-v: 4.6 vendor: intel mesa v: 25.0.0
|
||||
renderer: Mesa Intel Arc Graphics (MTL)
|
||||
API: Vulkan v: 1.4.304 drivers: N/A surfaces: xcb,xlib,wayland
|
||||
Info: Tools: api: clinfo, eglinfo, glxinfo, vulkaninfo
|
||||
de: kscreen-console,kscreen-doctor gpu: nvidia-settings,nvidia-smi
|
||||
wl: wayland-info x11: xdriinfo, xdpyinfo, xprop, xrandr```
|
||||
```
|
||||
|
||||
If the drivers aren't installed and loaded properly, the graphics card's name
|
||||
will be some generic term, not the exact name of the model.
|
||||
|
||||
To test if Darktable can use the CUDA driver, start if from the commandline
|
||||
like so:
|
||||
|
||||
```fish
|
||||
darktable -d opencl
|
||||
```
|
||||
|
||||
This should output a lot of technical information about the graphics card.
|
||||
|
||||
If it doesn't, but instead complains along the lines of
|
||||
|
||||
> FINALLY: opencl is NOT AVAILABLE on this system
|
||||
|
||||
then there is something wrong.
|
||||
|
||||
---
|
||||
|
||||
## Addendum 2025-04-17
|
||||
|
||||
Yesterday I upgraded from Fedora 41 to Fedora 42 (KDE), and of course the NVIDIA
|
||||
drivers were removed. Using the instructions above effortlessly installed the
|
||||
driver (currently version 570). :-)
|
||||
|
||||
[Darktable]: https://www.darktable.org
|
||||
[RPM fusion]: https://rpmfusion.org
|
After Width: | Height: | Size: 3.4 MiB |
After Width: | Height: | Size: 4.8 MiB |
36
content/posts/2025/schwanheimer-wiese/index.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
title: "Schwanheimer Wiese"
|
||||
description: Two images from Schwanheimer Wiese, Frankfurt, Germany
|
||||
date: 2025-03-04T06:21:18Z
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images: []
|
||||
tags:
|
||||
- photos
|
||||
- landscape
|
||||
- pentax
|
||||
---
|
||||
|
||||
I have decided to publish some of my photos on my blog.
|
||||
|
||||
Here are the first two of them, both taken on
|
||||
["Schwanheimer Wiese"][wiese] a meadow in the forests
|
||||
of [Frankfurt-Schwanheim][Schwanheim].
|
||||
|
||||
{{< figure src="20250223_152944 IMGP9786.jpg" >}}
|
||||
|
||||
The "Struwwelpeter" is a tree named after a figure from
|
||||
a famous [children's book][struwwelpeter]:
|
||||
|
||||
{{< figure src="20250223_153306 IMGP9790.jpg" >}}
|
||||
|
||||
Camera: Pentax K-3 APS-C, 18-55 mm kit lens (crop factor 1.5),
|
||||
image developed in [Darktable][]. Raw image file available
|
||||
upon reasonable request. All rights reserved.
|
||||
|
||||
[darktable]: https://darktable.org
|
||||
[Schwanheim]: https://en.wikipedia.org/wiki/Schwanheim_(Frankfurt_am_Main)
|
||||
[struwwelpeter]: https://en.wikipedia.org/wiki/Struwwelpeter
|
||||
[wiese]: https://de.wikipedia.org/wiki/Frankfurt-Schwanheim#Schwanheimer_Wiese
|
BIN
content/posts/2025/soleier/20250414_203010.jpg
Normal file
After Width: | Height: | Size: 584 KiB |
BIN
content/posts/2025/soleier/20250414_203911.jpg
Normal file
After Width: | Height: | Size: 289 KiB |
116
content/posts/2025/soleier/index.md
Normal file
@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "Soleier: Pickled eggs for Easter"
|
||||
description: >
|
||||
Pickled eggs – "Soleier" – are a favorite Easter tradition in my
|
||||
family. Here's my personal recipe.
|
||||
date: 2025-04-17T17:55:07+02:00
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: false
|
||||
scrolltotop: true
|
||||
images: []
|
||||
tags:
|
||||
- recipes
|
||||
---
|
||||
|
||||
My family has a long-running tradition of producing pickled eggs for Easter
|
||||
breakfast. We call these "Soleier" which is a composite of "Sole" (brine) and
|
||||
"Eier" (eggs). Varous theories exist how pickled eggs came into existence, and
|
||||
there are various ways to relish these eggs. As for the theories, the reader is
|
||||
kindly referred to the [Wikipedia article][pickled eggs]
|
||||
(also [in German][Soleier]).
|
||||
|
||||
As for the recipe and the way we eat pickled eggs in my family: read on.
|
||||
|
||||
{{< figure src="20250414_203010.jpg"
|
||||
alt="My 2025 Soleier preparation."
|
||||
caption="My 2025 Soleier preparation. Smartphone raw image file edited with darktable."
|
||||
>}}
|
||||
|
||||
## How many eggs?
|
||||
|
||||
How many eggs you want to prepare depends on the number of people who want to
|
||||
eat the pickled eggs, the number of days you want to have them for breakfast (or
|
||||
any other meal to your liking) and last, but not least, what size of jar you
|
||||
have to prepare them in.
|
||||
|
||||
My 1.5 L [Weck jar][] holds 13 medium-sized eggs.
|
||||
|
||||
Typically an adult will have 2 of those eggs for breakfast. With 13 eggs, this
|
||||
leaves one spare egg (and toast), but there's usually a kid or two who doesn't
|
||||
eat these eggs in pairs (if at all).
|
||||
|
||||
{{< figure src="20250414_203911.jpg"
|
||||
alt="Pickled eggs with cracks."
|
||||
caption="I love my pickled eggs to have cracks so that they let some of the brine in."
|
||||
>}}
|
||||
|
||||
## Recipe
|
||||
|
||||
### Ingredients and materials
|
||||
|
||||
This recipe is for 13 eggs and a 1.5 L jar.
|
||||
|
||||
- 13 eggs
|
||||
- 0.75 L water
|
||||
- 50 g salt
|
||||
- 1-2 tablespoons of caraway seeds (if you like)
|
||||
- 1.5 L [Weck jar][] (doesn't need to be original Weck brand, of course, but must be sealed tight)
|
||||
- 13 slices of toast
|
||||
- butter
|
||||
- oil, e.g. rapeseed oil, to your liking
|
||||
- vinegar, e.g. any herb-flavored variant, to your liking
|
||||
|
||||
### Directions
|
||||
|
||||
You should prepare the pickled eggs a few days before you want to eat them. In
|
||||
my family we typically do this 7 days before Easter, i.e. on Palm Sunday.
|
||||
|
||||
1. Boil the eggs so they get hard. I usually place the eggs in a pot, cover them
|
||||
with water, and then slowly heat the water until it boils. Let it boil until
|
||||
10 minutes have passed since the eggs were placed on the stove. Your mileage
|
||||
may vary depending on your stove.
|
||||
2. Pour out the hot water and shock the eggs with cold tap water.
|
||||
3. Place the eggs into the jar using a clean spoon (not your hands!). I usually
|
||||
let them drop into the jar so they get nice little cracks, this makes for
|
||||
beautiful texture inside the eggs (see image).
|
||||
4. Add the salt and caraway seeds to the jar.
|
||||
5. Bring the water to boiling and pour it over the eggs in the jar.
|
||||
6. Close the jar.
|
||||
7. Invert the jar a couple of times (you may want to wear gloves while doing
|
||||
this, the jar is hot!).
|
||||
8. Store the jar in a cool place -- in our house, this is usually the basement.
|
||||
|
||||
## How to eat Soleier
|
||||
|
||||
There seem to be two fundamentally different ways to eat a _Solei_.
|
||||
|
||||
### Our way of eating Soleier
|
||||
|
||||
My family's tradition is to peel two eggs, place them on a dish, cut them into
|
||||
pieces, then pour some oil and vinegar over the pieces and mash the eggs with a
|
||||
fork. This leaves an ugly mess on the plate and I will update this post with a
|
||||
picture of this year's appearance.
|
||||
|
||||
Brown two slices of toast, spread butter on them, and eat the _Solei_ mash/mess
|
||||
using a fork while intermittently taking a bite from the bread.
|
||||
|
||||
### The more sophisticated way to eat Soleier
|
||||
|
||||
There is an alternative way to have your pickled eggs that supposedly is less
|
||||
messy. The [German Wikipedia article][Soleier] claims it's the 'proper' or let's
|
||||
say usual way to eat these eggs. I tried it once and I was totally unhappy with
|
||||
the experience, so I stick with our traditional way.
|
||||
|
||||
Peel two eggs, cut the eggs into halves, remove the egg yolk and mash the egg
|
||||
yolk with oil and vinegar. Transfer the mashed egg yolk back into the eggs. I
|
||||
will look slightly less ugly, but I promise you will have a hard time getting
|
||||
all the egg yolk--oil--vinegar mixture back into the eggs, the plate will look
|
||||
like someone's been having _Soleier_ the traditional way, and when trying to put
|
||||
the egg halves into your mouth, be prepared for everyone else who sits at the
|
||||
table with you bursting into spontaneous laughter. At least that's what happened
|
||||
to me one time... ;-)
|
||||
|
||||
[pickled eggs]: https://en.wikipedia.org/wiki/Pickled_egg
|
||||
[Soleier]: https://de.wikipedia.org/wiki/Solei
|
||||
[Weck jar]: https://en.wikipedia.org/wiki/Weck_jar
|
@ -1,15 +1,17 @@
|
||||
services:
|
||||
build:
|
||||
image: hugomods/hugo:latest
|
||||
image: hugomods/hugo:ci
|
||||
command: hugo
|
||||
volumes:
|
||||
- ".:/src"
|
||||
user: 1000:1000
|
||||
server:
|
||||
image: hugomods/hugo:latest
|
||||
image: hugomods/hugo:ci
|
||||
command: server --buildDrafts --buildFuture
|
||||
volumes:
|
||||
- ".:/src"
|
||||
ports:
|
||||
- "127.0.0.1:1313:1313"
|
||||
user: 1000:1000
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
|
12
layouts/shortcodes/git-info.html
Normal file
@ -0,0 +1,12 @@
|
||||
<p>
|
||||
{{ partial "svg.html" (dict "context" . "name" "posts_single_date") }} {{ dateFormat .Site.Params.dateformNumTime .Page.Date.Local }}
|
||||
{{ if and (not (eq .Page.Params.ShowLastmod nil)) (.Page.Params.ShowLastmod) }}
|
||||
{{ if and .GitInfo .Site.Params.gitUrl }}
|
||||
[{{ partial "svg.html" (dict "context" . "name" "posts_single_git_commit") }}<a href="{{ .Site.Params.gitUrl -}}{{ .Page.GitInfo.Hash }}" target="_blank" rel="noopener">{{ .Page.GitInfo.AbbreviatedHash -}}</a> @ {{ dateFormat .Site.Params.dateformNum .Page.GitInfo.AuthorDate.Local }}]
|
||||
{{ else if not (eq .Page.Lastmod .Page.Date ) }}
|
||||
[{{.Site.Params.initialPublish | default "Initial Published on : "}} {{ dateFormat .Site.Params.dateformNumTime .Page.Lastmod.Local }}]
|
||||
{{ else }}
|
||||
{{ errorf "Lastmod is not found in Page Frontmatter or Lastmod is same as Date" }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</p>
|