Schaut gut aus, will aber nicht

Seit Beginn meiner kleinen Seite wollte ich eine Kommentarfunktion haben. Aber nachdem ich nicht einfach Disqus und Konsorten einbinden wollte und mir ständig andere Sachen dazwischen kommen, habe ich es immer wieder aufgeschoben. Bis jetzt, denn letztens bin ich auf das Open Source Projekt Talkyard gestoßen.

Ich dachte mir es wird schon nicht so schwer sein, das auf einen LXC-Container zu installieren. Und ja, das geht sogar, die Software läuft. Das Problem war dann, dass Talkyard Nginx verwendet und ich aber Caddy für Zertifikate und als Reverse Proxy verwende. Daher wollte ich Nginx nur für die statischen Websiten-Elemente verwenden und stattdessen Caddy für den Rest. Aber das war leider nicht erfolgreich. Dieser Beitrag ist dennoch vielleicht für jemanden insteressant, wer weiß.

Installation

Hier das Github-Repo. Als Erstes erstellen wir einen Klon von unserem Docker-LXC, falls man kein Template hat, kann man auch einen neuen LXC-Container mit beispielsweise Ubuntu 24.04 oder Debian 12 erstellen (oder auch Alpine Linux, wenn man es kompakt haben möchte). Dann passt man die IP-Adresse an, am besten mit statischer Adresse oder fixer Vergabe vom DHCP-Server.

Jetzt können wir den Container starten und die folgenden Befehle ausführen (vgl. Anleitung auf Github):

apt update
apt upgrade
apt install git locales
apt install tree ncdu
locale-gen en_US.UTF-8
export LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8

Die Programme tree und ncdu werden nur dazu benutzt um eine schöne Baumansicht im Terminal zu bekommen (tree) und die Ordnergröße im gegeben Verzeichnis anzeigen zu lassen (ncdu). Die locales Installation ist unter Ubuntu 24.04 nicht notwendig, bei anderen Distros kann sie aber fehlen. Ich habe aus der Liste eigentlich nur den Editor vim ausgelassen, denn der sollte entweder eh schon installiert sein und wenn nicht, hat man auf die Schnelle auch gar nichts damit angefangen – auch wenn es durchaus erstrebenswert wäre endlich umzusteigen, bin ich nach wie vor bei nano.

Den nächsten Schritt kann man überspringen, wenn man ein entsprechendes Monitoring hat, oder nicht davon ausgeht die Platte vollzuschreiben (unter Proxmox alles nicht so ein großes Problem, da man jederzeit die virtual hard disk erweitern kann):

Es wirkt mir überhaupt wie ein etwas komischer Mechanismus, einfach ein paar “Platzhalter” Dateien zu erstellen, die dann wie bei einem Heißluftballon, wie die Gewichte, abgeworfen werden. Denn wenn Talkyard alles vollräumt, dann steht die Bude sowieso erst einmal und ob ich dann diese “Speicherplatz-Gewichtln” lösche oder [[0L Raspberry Pi SD-Karte voll So mistet man das System aus|zum Beispiel den apt-Cache]] ist dann auch schon wurst.

Als nächstes müssen wir das Github-Repo klonen. Sie empfehlen /opt/talkyard weil sonst “das Backup nicht funktioniert”. Naja, von mir aus:

cd /opt/
git clone https://github.com/debiki/talkyard-prod-one.git talkyard
cd talkyard

Interessant, dass die Installationsanleitung für eine produktive Umgebung im Grunde aus einem Haufen Skripte besteht, so wie hier im nächsten Schritt (für LXC habe ich ein angepasstes prepare-os.sh-Skript erstellt1):

./scripts/prepare-os.sh 2>&1 | tee -a talkyard-maint.log

Auch wenn mehrmals in Klammern darauf hingewiesen wird, die Skripte doch etwas zu beäugen:

Aber das hat nicht neugierig gemacht, was heißt hier “enable automatic security updates”? Naja, schauen wir uns einmal an, was das Skript so macht. Aber vorher erstelle ich noch einen Snapshot, damit wir schnell und einfach wieder zum Zustand davor zurückkehren können:

2025-04-07T15:13:37+00:00 prepare-os: Configuring this Operating System:
Generating locales (this might take a while)...
  en_US.UTF-8... done
Generation complete.
Setting LC_ALL to en_US.UTF-8...
2025-04-07T15:13:40+00:00 prepare-os: Installing jq and rng-tools, for json logs and hardware random numbers...
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'rng-tools-debian' instead of 'rng-tools'
The following additional packages will be installed:
  libjq1 libonig5
The following NEW packages will be installed:
  jq libjq1 libonig5 rng-tools-debian
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 421 kB of archives.
After this operation, 1,251 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 rng-tools-debian amd64 2.4 [42.7 kB]
Get:2 http://archive.ubuntu.com/ubuntu noble/main amd64 libonig5 amd64 6.9.9-1build1 [172 kB]
Get:3 http://archive.ubuntu.com/ubuntu noble/main amd64 libjq1 amd64 1.7.1-3build1 [141 kB]
Get:4 http://archive.ubuntu.com/ubuntu noble/main amd64 jq amd64 1.7.1-3build1 [65.5 kB]
Fetched 421 kB in 1s (503 kB/s)
Selecting previously unselected package rng-tools-debian.
(Reading database ... 20796 files and directories currently installed.)
Preparing to unpack .../rng-tools-debian_2.4_amd64.deb ...
Unpacking rng-tools-debian (2.4) ...
Selecting previously unselected package libonig5:amd64.
Preparing to unpack .../libonig5_6.9.9-1build1_amd64.deb ...
Unpacking libonig5:amd64 (6.9.9-1build1) ...
Selecting previously unselected package libjq1:amd64.
Preparing to unpack .../libjq1_1.7.1-3build1_amd64.deb ...
Unpacking libjq1:amd64 (1.7.1-3build1) ...
Selecting previously unselected package jq.
Preparing to unpack .../jq_1.7.1-3build1_amd64.deb ...
Unpacking jq (1.7.1-3build1) ...
Setting up rng-tools-debian (2.4) ...
Setting up libonig5:amd64 (6.9.9-1build1) ...
Setting up libjq1:amd64 (1.7.1-3build1) ...
Setting up jq (1.7.1-3build1) ...
Processing triggers for man-db (2.12.0-4build2) ...
Processing triggers for libc-bin (2.39-0ubuntu8.4) ...
2025-04-07T15:13:47+00:00 prepare-os: Installing add-apt-repository...
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  appstream dirmngr gir1.2-packagekitglib-1.0 gpg gpg-agent gpgconf libappstream5 libduktape207 libdw1t64 libglib2.0-bin libgstreamer1.0-0 libksba8
  libpackagekit-glib2-18 libpolkit-agent-1-0 libpolkit-gobject-1-0 libstemmer0d libxmlb2 packagekit packagekit-tools pinentry-curses polkitd python3-blinker
  python3-cryptography python3-distro python3-httplib2 python3-jwt python3-launchpadlib python3-lazr.restfulclient python3-lazr.uri python3-oauthlib
  python3-pyparsing python3-six python3-software-properties python3-wadllib sgml-base unattended-upgrades xml-core
Suggested packages:
  apt-config-icons gnupg pinentry-gnome3 tor keyboxd scdaemon gstreamer1.0-tools pinentry-doc polkitd-pkla python-blinker-doc python-cryptography-doc
  python3-cryptography-vectors python3-crypto python3-keyring python3-testresources python-pyparsing-doc sgml-base-doc bsd-mailx needrestart powermgmt-base
  debhelper
The following NEW packages will be installed:
  appstream dirmngr gir1.2-packagekitglib-1.0 gpg gpg-agent gpgconf libappstream5 libduktape207 libdw1t64 libglib2.0-bin libgstreamer1.0-0 libksba8
  libpackagekit-glib2-18 libpolkit-agent-1-0 libpolkit-gobject-1-0 libstemmer0d libxmlb2 packagekit packagekit-tools pinentry-curses polkitd python3-blinker
  python3-cryptography python3-distro python3-httplib2 python3-jwt python3-launchpadlib python3-lazr.restfulclient python3-lazr.uri python3-oauthlib
  python3-pyparsing python3-six python3-software-properties python3-wadllib sgml-base software-properties-common unattended-upgrades xml-core
0 upgraded, 38 newly installed, 0 to remove and 0 not upgraded.
Need to get 5,787 kB of archives.
After this operation, 21.7 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble/main amd64 sgml-base all 1.31 [11.4 kB]
{...}

Creating config file /etc/apt/apt.conf.d/20auto-upgrades with new version

Creating config file /etc/apt/apt.conf.d/50unattended-upgrades with new version
Created symlink /etc/systemd/system/multi-user.target.wants/unattended-upgrades.service → /usr/lib/systemd/system/unattended-upgrades.service.
Synchronizing state of unattended-upgrades.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable unattended-upgrades
Setting up python3-pyparsing (3.1.1-1) ...
Setting up python3-cryptography (41.0.7-4ubuntu0.1) ...
Setting up python3-wadllib (1.3.6-5) ...
Setting up libduktape207:amd64 (2.7.0+tests-0ubuntu3) ...
Setting up gpgconf (2.4.4-2ubuntu17.2) ...
Setting up python3-httplib2 (0.20.4-3) ...
Setting up sgml-base (1.31) ...
Setting up libstemmer0d:amd64 (2.2.0-4build1) ...
Setting up gpg (2.4.4-2ubuntu17.2) ...
Setting up libpolkit-gobject-1-0:amd64 (124-2ubuntu1.24.04.2) ...
Setting up libgstreamer1.0-0:amd64 (1.24.2-1ubuntu0.1) ...
Setcap worked! gst-ptp-helper is not suid!
Setting up python3-blinker (1.7.0-1) ...
Setting up gpg-agent (2.4.4-2ubuntu17.2) ...
Created symlink /etc/systemd/user/sockets.target.wants/gpg-agent.socket → /usr/lib/systemd/user/gpg-agent.socket.
Created symlink /etc/systemd/user/sockets.target.wants/gpg-agent-ssh.socket → /usr/lib/systemd/user/gpg-agent-ssh.socket.
Created symlink /etc/systemd/user/sockets.target.wants/gpg-agent-extra.socket → /usr/lib/systemd/user/gpg-agent-extra.socket.
Created symlink /etc/systemd/user/sockets.target.wants/gpg-agent-browser.socket → /usr/lib/systemd/user/gpg-agent-browser.socket.
Setting up libappstream5:amd64 (1.0.2-1build6) ...
Setting up dirmngr (2.4.4-2ubuntu17.2) ...
Created symlink /etc/systemd/user/sockets.target.wants/dirmngr.socket → /usr/lib/systemd/user/dirmngr.socket.
Setting up python3-oauthlib (3.2.2-1) ...
Setting up appstream (1.0.2-1build6) ...
✔ Metadata cache was updated successfully.
Setting up xml-core (0.19) ...
Setting up libpolkit-agent-1-0:amd64 (124-2ubuntu1.24.04.2) ...
Setting up python3-lazr.restfulclient (0.14.6-1) ...
Setting up python3-launchpadlib (1.11.0-6) ...
Created symlink /etc/systemd/user/timers.target.wants/launchpadlib-cache-clean.timer → /usr/lib/systemd/user/launchpadlib-cache-clean.timer.
Setting up python3-software-properties (0.99.49.1) ...
Processing triggers for libc-bin (2.39-0ubuntu8.4) ...
Processing triggers for man-db (2.12.0-4build2) ...
Processing triggers for dbus (1.14.10-4ubuntu4.1) ...
Processing triggers for sgml-base (1.31) ...
Setting up polkitd (124-2ubuntu1.24.04.2) ...
Creating group 'polkitd' with GID 989.
Creating user 'polkitd' (User for polkitd) with UID 989 and GID 989.
Setting up packagekit (1.2.8-2ubuntu1.2) ...
Created symlink /etc/systemd/user/sockets.target.wants/pk-debconf-helper.socket → /usr/lib/systemd/user/pk-debconf-helper.socket.
Setting up packagekit-tools (1.2.8-2ubuntu1.2) ...
Setting up software-properties-common (0.99.49.1) ...
Processing triggers for dbus (1.14.10-4ubuntu4.1) ...
2025-04-07T15:14:04+00:00 prepare-os: Amending the /etc/sysctl.conf config...
2025-04-07T15:14:04+00:00 prepare-os: Reloading the system config...
* Applying /usr/lib/sysctl.d/10-apparmor.conf ...
* Applying /etc/sysctl.d/10-bufferbloat.conf ...
* Applying /etc/sysctl.d/10-console-messages.conf ...
* Applying /etc/sysctl.d/10-ipv6-privacy.conf ...
* Applying /etc/sysctl.d/10-kernel-hardening.conf ...
* Applying /etc/sysctl.d/10-magic-sysrq.conf ...
* Applying /etc/sysctl.d/10-map-count.conf ...
* Applying /etc/sysctl.d/10-network-security.conf ...
* Applying /etc/sysctl.d/10-ptrace.conf ...
* Applying /etc/sysctl.d/10-zeropage.conf ...
* Applying /usr/lib/sysctl.d/50-pid-max.conf ...
* Applying /usr/lib/sysctl.d/99-protect-links.conf ...
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.conf ...
sysctl: setting key "kernel.apparmor_restrict_unprivileged_userns", ignoring: Read-only file system
kernel.apparmor_restrict_unprivileged_userns = 1
sysctl: setting key "kernel.printk", ignoring: Read-only file system
kernel.printk = 4 4 1 7
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
sysctl: setting key "kernel.kptr_restrict", ignoring: Read-only file system
kernel.kptr_restrict = 1
sysctl: setting key "kernel.sysrq", ignoring: Read-only file system
kernel.sysrq = 176
sysctl: setting key "vm.max_map_count", ignoring: Read-only file system
vm.max_map_count = 1048576
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.all.rp_filter = 2
sysctl: setting key "kernel.yama.ptrace_scope", ignoring: Read-only file system
kernel.yama.ptrace_scope = 1
sysctl: setting key "vm.mmap_min_addr", ignoring: Read-only file system
vm.mmap_min_addr = 65536
sysctl: setting key "kernel.pid_max", ignoring: Read-only file system
kernel.pid_max = 4194304
sysctl: setting key "fs.protected_fifos", ignoring: Read-only file system
fs.protected_fifos = 1
sysctl: setting key "fs.protected_hardlinks", ignoring: Read-only file system
fs.protected_hardlinks = 1
sysctl: setting key "fs.protected_regular", ignoring: Read-only file system
fs.protected_regular = 2
sysctl: setting key "fs.protected_symlinks", ignoring: Read-only file system
fs.protected_symlinks = 1
sysctl: setting key "vm.swappiness", ignoring: Read-only file system
vm.swappiness = 0
net.core.somaxconn = 8192
sysctl: setting key "vm.max_map_count", ignoring: Read-only file system
vm.max_map_count = 262144
sysctl: setting key "vm.swappiness", ignoring: Read-only file system
vm.swappiness = 0
net.core.somaxconn = 8192
sysctl: setting key "vm.max_map_count", ignoring: Read-only file system
vm.max_map_count = 262144
Transparent Huge Pages is [madvise] or [never], fine, Redis happy.
2025-04-07T15:14:04+00:00 prepare-os: Adding history settings to .bashrc...
2025-04-07T15:14:04+00:00 prepare-os: There's already an auto upgrades config file: /etc/apt/apt.conf.d/20auto-upgrades.
2025-04-07T15:14:04+00:00 prepare-os: I'll leave it as is — I won't (re)configure automatic upgrades.
2025-04-07T15:14:04+00:00 prepare-os: ---- It's contents: ------
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
2025-04-07T15:14:04+00:00 prepare-os: --------------------------
2025-04-07T15:14:04+00:00 prepare-os: Consider adding the below line,  if it's missing,
2025-04-07T15:14:04+00:00 prepare-os: so your server will reboot if needed, for upgrades to take effect:

Unattended-Upgrade::Automatic-Reboot "true";

2025-04-07T15:14:04+00:00 prepare-os: Done configuring the OS.

OK, alle Befehle, die eine komplette VM benötigen funktionieren in einem unprivilegierten Container nicht. Darunter Sicherheitseinstellungen:

sysctl: setting key "kernel.apparmor_restrict_unprivileged_userns", ignoring: Read-only file system

Und u.A. Swapeinstellungen:

sysctl: setting key "vm.swappiness", ignoring: Read-only file system
vm.swappiness = 0

Aber Swap habe ich sowieso nicht, sollte aber auch ohne ausreichen. Die Kernel-Apparmor Einstellungen muss ich eventuell noch über die Container Config einrichten.

Der chinesische Chatbot schlägt folgende Anpassungen für LXC mit dem Skript vor:

Machen wir einmal weiter, bis wir wo anstehen.

Die nächsten beiden Schritte können wir gleich überspringen, denn Docker Compose ist hier bereits installiert und Proxmox hat bereits eine Firewall, die wir verwenden werden.

Jetzt müssen wir die .env im Repo-Ordner und play-framework.conf im Unterordner conf anpassen:

Mit dem Befehl…

openssl rand -base64 32

… bekommt man ein 32-Zeichen langes zufällig generiertes Passwort für POSTGRES_PASSWORD=change_me in .env.

Für conf/play-framework.conf braucht man noch einmal ein Passwort, dieses Mal achtzig Zeichen lang (openssl rand -base64 80) und man muss auch Administrator-Email, URL und Angaben für den Emailversand vom Forum mittels SMTP eintragen.

Als nächstes wieder in das Hauptverzeichnis von der Repo wechseln und je nach RAM-Ausstattung den passenden Befehl ausführen. Hier für 1,7 GB freien RAM:

cp mem/1.7g.yml docker-compose.override.yml

Jetzt noch einmal einen Snapshot anlegen und dann…

 ./scripts/upgrade-if-needed.sh 2>&1 | tee -a talkyard-maint.log

… ausführen. Was leider misslingt:

root@talkyard:/opt/talkyard#  ./scripts/upgrade-if-needed.sh 2>&1 | tee -a talkyard-maint.log
upgrade-script: Using release branch: tyse-v0-regular.
upgrade-script: Apparently no version currently installed.
upgrade-script: Checking for latest version...
upgrade-script: Downloading version numbers submodule...
Submodule 'versions' (https://github.com/debiki/talkyard-versions.git) registered for path 'versions'
Cloning into '/opt/talkyard/versions'...
Submodule path 'versions': checked out 'ebf65a424af5f9fa6ac22bae5cd07958cd264f5f'
Previous HEAD position was ebf65a4 Add v0.5.0-WIP-4-6f60d0c.
Switched to a new branch 'tyse-v0-regular'
branch 'tyse-v0-regular' set up to track 'origin/tyse-v0-regular'.
upgrade-script: I will install version v0.2025.005-7a6728209.
upgrade-script: Downloading version v0.2025.005-7a6728209... (this might take long)
./scripts/upgrade-if-needed.sh: line 126: /usr/local/bin/docker-compose: No such file or directory

Das liegt wohl daran, dass die Anleitung noch die alte Variante mit docker-compose verwendet und nicht die als Plugin realisierte neue Variante als docker compose. Das Verzeichnis docker-compose existiert nicht, da alles in docker ist. Wo genau mit which docker findet man zB folgenden Pfad:

/usr/bin/docker

Um dieses Problem zu lösen muss man, laut Chatbot, zuerst den falschen Verweis… … durch den richtigen ersetzen:

Um das Skript anzupassen kann man diesen Befehl verwenden:

sed -i 's|/usr/local/bin/docker-compose|docker compose|g' scripts/upgrade-if-needed.sh

Jetzt lädt es herunter:

root@talkyard:/opt/talkyard# ./scripts/upgrade-if-needed.sh 2>&1 | tee -a talkyard-maint.log
upgrade-script: Using release branch: tyse-v0-regular.
upgrade-script: Apparently no version currently installed.
upgrade-script: Checking for latest version...
Reset branch 'tyse-v0-regular'
branch 'tyse-v0-regular' set up to track 'origin/tyse-v0-regular'.
Your branch is up to date with 'origin/tyse-v0-regular'.
upgrade-script: I will install version v0.2025.005-7a6728209.
upgrade-script: Downloading version v0.2025.005-7a6728209... (this might take long)
msg="/opt/talkyard/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion"
msg="/opt/talkyard/docker-compose.override.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion"
cache Pulling
rdb Pulling
search Pulling
app Pulling
web Pulling

Aber das Starten funktioniert nicht:

Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error setting rlimits for ready process: error setting rlimit type 8: operation not permitted: unknown

Deepseek meint es liegt an

So in etwa:

Und das Docker-Deployment hat funktioniert:

upgrade-script: Installing: Setting current version number to v0.2025.005-7a6728209...
upgrade-script: Done. Bye.

Talkyard aufrufen mehr Troubleshooting

Aber so wirklich funktioniert hat das nicht, als ich die Website via IP-Adresse aufrufen wollte (sowohl mit http als auch https):

Die talkyard-app scheint auch so ihre Probleme zu haben:

Die Anleitung ist auch nicht unbedingt hilfreich…

… und der nächste Schritt hat wieder drei Skripte, die aber nur für die maintenance wichtig sind:

Ich habe also nun das docker-compose.yml angepasst

Caddyfile:

forum.martinfellner.at {
  reverse_proxy http://xxx.xxx.xxx.xxx:80 {
    # Tell Talkyard the original request was HTTPS:
    header_up X-Forwarded-Proto https
    header_up X-Forwarded-Host {host}
    header_up X-Real-IP {remote}
  }
}

Aber wenn man nur diese Einstellung nimmt, dann bekommt man den folgenden Fehler, beim Aufrufen der Seite:

403 Forbidden
X-Forwarded-Proto is Some(http) but should be https. X-Forwarded-Host: Some(forum.martinfellner.at) [TyEFORWPROTO]

Daher muss man dann doch noch conf/sites-enabled-manual/talkyard-servers.conf anpassen, oder durch diese Version ersetzen (Server URL bei server_name eingeben nicht vergessen):

server {
  listen 80;
  server_name forum.website.com;
 
  # Serve static assets directly
  location /-/assets/ {
    alias /opt/talkyard/uploads/;
    expires 1y;
    add_header Cache-Control "public";
    access_log off;
  }
 
  location /-/fonts/ {
    alias /opt/talkyard/uploads/fonts/;
    expires 1y;
    add_header Cache-Control "public";
    access_log off;
  }
 
  location /-/media/ {
    alias /opt/talkyard/uploads/media/;
    expires 1y;
    add_header Cache-Control "public";
    access_log off;
  }
 
  # Proxy dynamic requests to Play Framework
  location / {
    proxy_pass http://app:9000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Das sind die Chatbot’schen Änderungen:

Jetzt muss man noch Nginx neustarten mit:

docker compose restart web

Und es funktioniert nicht. Ich schaffe es auch nach mehreren Versuchen nicht Talkyard aufzurufen. Ich glaube das wird’s nicht mehr.

Letztlich ist der Versuch gescheitert und ich bin dann auf NodeBB umgestiegen. Aber vielleicht ist es ja interessant zu sehen, dass man Talkyard prinzipiell auch in einem kleinen LXC Container installieren kann.

#!/bin/bash
 
# This script makes ElasticSearch work, simplifies troubleshooting,
# and configures automatic security updates, with reboots.
# ADAPTED FOR PROXMOX LXC + DOCKER
 
function log_message {
  echo "`date --iso-8601=seconds --utc` prepare-os: $1"
}
 
echo
echo
log_message 'Configuring this Operating System (Proxmox LXC):'
 
 
# ----------------------------------------------------------------------
# 1. Locale Settings
# ----------------------------------------------------------------------
# Avoid "warning: Setting locale failed" warnings from Perl
locale-gen 'en_US.UTF-8'
if ! grep -q 'LC_ALL=' /etc/default/locale; then
  echo 'Setting LC_ALL to en_US.UTF-8...'
  echo 'LC_ALL=en_US.UTF-8' >> /etc/default/locale
  export LC_ALL='en_US.UTF-8'
fi
if ! grep -q 'LANG=' /etc/default/locale; then
  echo 'Setting LANG to en_US.UTF-8...'
  echo 'LANG=en_US.UTF-8' >> /etc/default/locale
  export LANG='en_US.UTF-8'
fi
 
 
# ----------------------------------------------------------------------
# 2. Install Dependencies
# ----------------------------------------------------------------------
# Install 'jq' for JSON logs (skip rng-tools in LXC)
log_message 'Installing jq...'
apt-get -y install jq
 
log_message 'Installing add-apt-repository...'
apt-get -y install software-properties-common
 
 
# ----------------------------------------------------------------------
# 3. Sysctl Settings (LXC-Compatible Only)
# ----------------------------------------------------------------------
# Omit vm.max_map_count (must be set on Proxmox host instead)
if ! grep -q 'Talkyard' /etc/sysctl.conf; then
  log_message 'Amending /etc/sysctl.conf for LXC...'
  cat <<-EOF >> /etc/sysctl.conf
		
		###################################################################
		# Talkyard LXC settings
		vm.swappiness=0
		net.core.somaxconn=8192
		EOF
 
  log_message 'Reloading sysctl (LXC-safe settings)...'
  sysctl --system
fi
 
 
# ----------------------------------------------------------------------
# 4. Transparent Huge Pages (THP) for Redis (Conditional)
# ----------------------------------------------------------------------
if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then
  if ! grep -q '\[always\]' /sys/kernel/mm/transparent_hugepage/enabled ; then
    echo "Transparent Huge Pages: [madvise] or [never], Redis-compatible."
  else
    echo "Setting Transparent Huge Pages to [madvise] for Redis..."
    echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
    rc_local_f="/etc/rc.local"
    if [ ! -f $rc_local_f ]; then
      echo "exit 0" >> $rc_local_f
    fi
    if ! grep -q 'transparent_hugepage/enabled' $rc_local_f ; then
      sed -i -e '$i # For Talkyard and Redis:\necho madvise > /sys/kernel/mm/transparent_hugepage/enabled\n' $rc_local_f
    fi
  fi
else
  log_message "Skipping THP adjustment: /sys/kernel/mm/transparent_hugepage/enabled not accessible in LXC."
fi
 
 
# ----------------------------------------------------------------------
# 5. Bash History (Troubleshooting)
# ----------------------------------------------------------------------
if ! grep -q 'HISTTIMEFORMAT' ~/.bashrc; then
  log_message 'Adding history settings to .bashrc...'
  cat <<-EOF >> ~/.bashrc
		
		###################################################################
		export HISTCONTROL=ignoredups
		export HISTCONTROL=ignoreboth
		export HISTSIZE=10100
		export HISTFILESIZE=10100
		export HISTTIMEFORMAT='%F %T %z  '
		EOF
fi
 
 
# ----------------------------------------------------------------------
# 6. Automatic Security Updates (With Safeguards)
# ----------------------------------------------------------------------
auto_upgr_f="/etc/apt/apt.conf.d/20auto-upgrades"
if [ -f $auto_upgr_f ]; then
  log_message "Auto-upgrades config already exists. Leaving it intact."
else
  log_message 'Enabling automatic security updates (no reboots by default)...'
  DEBIAN_FRONTEND=noninteractive \
      apt-get install -y \
          -o Dpkg::Options::="--force-confdef" \
          -o Dpkg::Options::="--force-confold" \
          unattended-upgrades \
          update-notifier-common
 
  cat <<EOF > $auto_upgr_f
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutoremoveInterval "14";
APT::Periodic::AutocleanInterval "14";
APT::Periodic::MinAge "8";
Unattended-Upgrade::Automatic-Reboot "false";  # Safer for Docker in LXC
EOF
fi
 
 
# ----------------------------------------------------------------------
log_message 'Done configuring the OS for Proxmox LXC + Docker.'
echo

Footnotes

  1. Hier das für unprivilegierte Proxmox LXC angepasste Skript: