<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>criticalbasics</title>
      <link>https://criticalbasics.xyz</link>
      <description>Retro is now!</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://criticalbasics.xyz/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Thu, 10 Sep 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Fetch, Review, Accept: Syncing Dotfiles and pass over SSH</title>
          <pubDate>Thu, 10 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/dotfiles-pass-sync-git-ssh-peers/</link>
          <guid>https://criticalbasics.xyz/posts/dotfiles-pass-sync-git-ssh-peers/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/dotfiles-pass-sync-git-ssh-peers/">&lt;p&gt;A useful configuration change should not become a copying exercise every time you switch computers. But a handful of personal machines hardly needs a synchronization platform either.&lt;/p&gt;
&lt;p&gt;This guide uses one small routine: &lt;strong&gt;when you sit down at a computer, fetch changes from your other reachable computers, inspect them, and decide whether to accept them.&lt;/strong&gt; Git records the changes; SSH transports them. A short Bash script handles the repetition.&lt;/p&gt;
&lt;p&gt;The computers themselves are the peers. Here, “fleet” simply means the few computers you own and administer. Ordinary updates need only a fetch and confirmation. When histories diverge, the script prepares a temporary Git worktree for review; it can then send the accepted result back to the other device after a second confirmation.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Fetch from a known peer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Review changes / resolve conflicts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Accept the local result? [y/N]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Optionally send the result back? [y/N]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Peer checks its checkout before applying&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The trade-off is explicit: &lt;strong&gt;direct peers must be online at the same time.&lt;/strong&gt; Commit before leaving one machine, and keep it reachable until the next has fetched those commits. Nothing has to run continuously, but a sleeping laptop cannot serve its repository.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-10&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide to syncing dotfiles and a pass password store between SSH peers with interactive review, conflict resolution, and optional confirmed return updates.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-why-git-fits-this-job&quot;&gt;1. Why Git Fits This Job&lt;/h2&gt;
&lt;p&gt;Git can fetch from another ordinary checkout over SSH. The remote need not be a hosted service or a bare repository. Fetching downloads history without replacing the current checkout; the downloaded commit is already the intermediate state needed for review. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-fetch&quot;&gt;Git fetch documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A file synchronizer solves a different problem. Syncthing handles concurrent edits by retaining conflict copies; for configuration, this guide instead keeps the history and the decision to combine changes in Git. Keep live Git repositories outside folders managed by file synchronization software. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.syncthing.net/users/syncing.html&quot;&gt;Syncthing conflict handling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Use two repositories: one for dotfiles and another for the encrypted &lt;code&gt;pass&lt;/code&gt; store. Only committed changes travel between peers. This is configuration-file management, not a complete system rebuild: installing packages and configuring system services remain separate tasks.&lt;/p&gt;
&lt;h2 id=&quot;2-shared-configuration-host-differences-and-stow&quot;&gt;2. Shared Configuration, Host Differences, and Stow&lt;/h2&gt;
&lt;p&gt;Keep the shared files together and make the small host-specific parts explicit:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dotfiles/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── fleet.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── common/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── .config/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       └── example-app/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│           └── config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── hosts/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── desktop/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └── .config/example-app/host.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── laptop/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        └── .config/example-app/host.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;example-app&lt;/code&gt; is a placeholder: use your actual applications and their supported configuration syntax. Where an application supports includes, the shared file can include a local host fragment. Otherwise, keep its entire host-dependent configuration in the host package. Arrange packages so that they do not manage the same file.&lt;/p&gt;
&lt;p&gt;GNU Stow links files from these packages into your home directory. Preview before applying, and select exactly one host package:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/src/dotfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;stow&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --simulate --verbose --no-folding --target=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; common&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;stow&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --no-folding --target=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; common&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;stow&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --dir=hosts --simulate --verbose --no-folding --target=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; desktop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;stow&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --dir=hosts --no-folding --target=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; desktop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;code&gt;laptop&lt;/code&gt; on the laptop. Resolve existing-file conflicts deliberately before proceeding. &lt;code&gt;--no-folding&lt;/code&gt; keeps the directory structure explicit and creates individual file links. Run Stow again when adding newly managed paths. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gnu.org/software/stow/manual/stow.html&quot;&gt;GNU Stow manual&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For machines that already have working configurations, start with a file-by-file inventory. Put reviewed, identical files in &lt;code&gt;common&lt;/code&gt;; keep intentional differences in the respective host packages. A whole host-specific configuration file is a reasonable starting point when splitting it into includes would add unnecessary work. Track only explicitly selected files, not application caches, histories, session files, or entire configuration directories by default.&lt;/p&gt;
&lt;p&gt;Before replacing an existing file with a Stow link, copy its contents and permissions into the intended package and make a separate dated backup outside the repository. Confirm that the package copy matches the live original, then move the original out of the target path. Run Stow’s simulation and apply steps, and verify that the new link resolves to the intended file with the original contents. If installation fails, remove only the links created during that attempt and restore the saved originals. Avoid using &lt;code&gt;--adopt&lt;/code&gt; as a shortcut for merging different configurations: it moves existing target files into the package. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gnu.org/s/stow/manual/html_node/Invoking-Stow.html&quot;&gt;Stow conflict handling and adoption&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Treat theme definitions and hardware settings separately. Share colors, keybindings, and theme-switching scripts; preserve each machine’s DPI, monitor arrangement, and device names. For X resources, one practical arrangement is to assemble common defaults, the selected color palette, and the host’s overrides in that order, then load the result with &lt;code&gt;xrdb&lt;/code&gt;. Keep DPI and other hardware values out of the palettes so switching between light and dark does not replace them. Check both modes and a new login. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.x.org/releases/current/doc/man/man1/xrdb.1.xhtml&quot;&gt;X.Org xrdb manual&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Track the sources of generated configuration, rather than giving Stow and a theme switcher competing ownership of the same output. A switcher that replaces a file with &lt;code&gt;mv&lt;/code&gt; or recreates a symlink can replace the link Stow installed. In this layout, theme palettes and scripts belong in the repository; the active theme links and assembled resource file are generated locally. Keep the Git checkout outside Syncthing-managed folders even if Syncthing distributes your standalone scripts.&lt;/p&gt;
&lt;h3 id=&quot;first-time-setup-is-separate-from-everyday-sync&quot;&gt;First-Time Setup Is Separate from Everyday Sync&lt;/h3&gt;
&lt;p&gt;A new machine also needs the programs that read these files. Keep a small, explicit setup routine alongside the dotfiles: a reviewed package list, installation of supporting scripts and fonts, Stow application, and any required service setup. Run it deliberately when onboarding a machine or adding a dependency. The sync script does not install packages, create newly needed Stow links, or activate services. Keep the synchronizer executable itself as an installed copy, rather than a live link to its source in the repository it updates. Install a reviewed script update explicitly on each direct peer.&lt;/p&gt;
&lt;p&gt;System configuration needs its own installation step. For example, share the intended appearance of a login manager, but install its configuration under &lt;code&gt;/etc&lt;/code&gt; with explicit administrator privileges and a backup. Preserve host-specific session settings. An accepted Git commit must not automatically execute privileged setup or restart the active login session.&lt;/p&gt;
&lt;p&gt;Validate workflows, not just file equality: a clipboard shortcut needs its daemon, a status-bar button needs its launcher and application, and a media-control bridge needs a reachable player or server. Record these dependencies in the setup notes. This keeps the everyday sync routine small while making the initial setup repeatable.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            REVIEW BEFORE UPDATING THE CHECKOUT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Stow links point into the repository. Updating an existing linked file changes the configuration available to the application immediately; there is no separate deployment barrier. Shell startup files can execute commands in the next shell. Review before accepting the merge, then reload applications as appropriate.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Keep private keys, tokens, and plaintext passwords out of the dotfiles repository. An ignore file is a convenience, not a secret detector: inspect what you stage.&lt;/p&gt;
&lt;p&gt;For Vim swap files and editor backups, a small &lt;code&gt;.gitignore&lt;/code&gt; at the repository root is enough to start:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*.swp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*.swo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Commit this file with your configuration. Ignored, untracked files do not block the script’s clean-checkout check. Keep &lt;code&gt;.orig&lt;/code&gt; and &lt;code&gt;.rej&lt;/code&gt; files visible for inspection after conflict or patch work rather than ignoring them by default. Ignore rules do not stop tracking files already committed. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/gitignore&quot;&gt;Git ignore documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;3-set-up-ssh-and-the-first-repository&quot;&gt;3. Set Up SSH and the First Repository&lt;/h2&gt;
&lt;p&gt;The examples assume Linux, Bash, Git, OpenSSH, &lt;code&gt;flock&lt;/code&gt; from util-linux, GNU Stow, and &lt;code&gt;pass&lt;/code&gt; with GnuPG. Vim supplies the default &lt;code&gt;vimdiff&lt;/code&gt; merge editor; whole-file conflict choices do not require an editor. Install them through your distribution’s package manager. Enable the SSH server on machines that should serve repositories, following your distribution’s instructions.&lt;/p&gt;
&lt;p&gt;All account names, machine names, paths, and domains below are examples. Replace them with your own. The examples use an ordinary account named &lt;code&gt;user&lt;/code&gt; on machines named &lt;code&gt;desktop&lt;/code&gt; and &lt;code&gt;laptop&lt;/code&gt;, with repositories at the same relative location.&lt;/p&gt;
&lt;p&gt;Set your Git author name and email if you have not already done so. On the first machine, create the dotfiles repository, populate it with reviewed configuration files, and make the first commit:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/src/dotfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/src/dotfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add your configuration packages before continuing.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add common hosts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Add initial configuration&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use a separate SSH client key for each device. &lt;strong&gt;Verify the destination’s SSH host-key fingerprint through a trusted channel before accepting it.&lt;/strong&gt; For example, compare the fingerprint displayed during the first connection with the server’s fingerprint viewed locally on that machine:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Run locally on the destination; this reads its public host key.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh-keygen&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -lf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/ssh/ssh_host_ed25519_key.pub&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use the matching host-key type if the connection presents another type. Then install your client public key using &lt;code&gt;ssh-copy-id user@desktop.local&lt;/code&gt;, and test noninteractive authentication:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; BatchMode=yes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; StrictHostKeyChecking=yes user@desktop.local&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The host key authenticates the destination; your client key authenticates your account access. This workflow trusts those known machines to serve the intended repositories. Manual review checks content; it does not establish the cryptographic authorship of each commit. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://man.openbsd.org/ssh_config&quot;&gt;OpenSSH client settings&lt;/a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://man.openbsd.org/ssh-keygen&quot;&gt;ssh-keygen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Clone onto the second machine after SSH works:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone user@desktop.local:/home/user/.local/src/dotfiles ~/.local/src/dotfiles&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repeat the SSH setup in each direction you intend to fetch. A normal account is the simplest starting point; restrict access further if your threat model requires it. Do not expose SSH publicly just for this workflow.&lt;/p&gt;
&lt;p&gt;Names ending in &lt;code&gt;.local&lt;/code&gt; require working mDNS on the machines and network; they are not automatic merely because SSH is installed. mDNS is local-link discovery, so these names normally will not work from a café or across routed networks. Existing local DNS names or stable LAN addresses work too. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.rfc-editor.org/rfc/rfc6762&quot;&gt;Multicast DNS specification&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;4-one-peer-list-one-interactive-script&quot;&gt;4. One Peer List, One Interactive Script&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;fleet.conf&lt;/code&gt; at the root of the dotfiles repository. Each line contains the peer’s short hostname and its SSH repository URL, separated by whitespace:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Short hostname    SSH repository URL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;desktop    user@desktop.local:/home/user/.local/src/dotfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;laptop     user@laptop.local:/home/user/.local/src/dotfiles&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Commit this file so all clones receive the same list. Labels must match the hostname from &lt;code&gt;uname -n&lt;/code&gt; up to the first dot on the corresponding machines, allowing the script to skip itself. Use unique short hostnames. URLs must contain no whitespace. Blank lines and full-line comments are allowed, as are trailing comments introduced by whitespace followed by &lt;code&gt;#&lt;/code&gt;. A &lt;code&gt;#&lt;/code&gt; within a URL remains part of the URL. The file is read as data, never executed as shell code; malformed entries stop the script with an error.&lt;/p&gt;
&lt;p&gt;No &lt;code&gt;git remote add&lt;/code&gt; is needed for these peers: Git accepts the URL directly. Adding a machine means adding a line &lt;strong&gt;after&lt;/strong&gt; preparing its SSH access and initial clone. Each repository has its own list because its remote paths differ.&lt;/p&gt;
&lt;p&gt;The complete implementation is one standalone Bash script: &lt;strong&gt;&lt;a href=&quot;/scripts/fleet-sync&quot;&gt;download fleet-sync&lt;/a&gt;&lt;/strong&gt;. Read it before installing it on each direct peer:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 755&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /path/to/downloaded/fleet-sync ~/.local/bin/fleet-sync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure &lt;code&gt;~/.local/bin&lt;/code&gt; is on your interactive shell’s &lt;code&gt;PATH&lt;/code&gt;. Run &lt;code&gt;fleet-sync&lt;/code&gt; in a terminal; it defaults to &lt;code&gt;~/.local/src/dotfiles&lt;/code&gt;. The repository must already have commits on &lt;code&gt;main&lt;/code&gt; and no pending local changes. The script does not automatically create commits for ordinary edits or stash unfinished work.&lt;/p&gt;
&lt;p&gt;Before switching devices, commit the changes you want to carry over. For the placeholder layout above:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/src/dotfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --short&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; diff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; common/.config/example-app/config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; diff&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --cached&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Adjust example-app settings&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the example path with the specific files you reviewed. Once the checkout is clean, run &lt;code&gt;fleet-sync&lt;/code&gt; here to offer the commit to other peers, or fetch it when you arrive at the next device. Equal commits produce no acceptance prompt. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-add&quot;&gt;Git staging&lt;/a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-commit&quot;&gt;Git commits&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The normal decisions are:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Situation&lt;/th&gt;&lt;th&gt;What the script offers&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Both tips are equal&lt;/td&gt;&lt;td&gt;Nothing to do.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;The peer is ahead&lt;/td&gt;&lt;td&gt;Show the incoming diff and ask before updating this device.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;This device is ahead&lt;/td&gt;&lt;td&gt;Show the outgoing diff and ask whether to update the peer now.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Both made independent commits&lt;/td&gt;&lt;td&gt;Offer an interactive merge, then review the combined result and optionally send it back.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A failed fetch leaves its error visible and moves on. &lt;code&gt;BatchMode=yes&lt;/code&gt; prevents interactive SSH authentication prompts; &lt;code&gt;StrictHostKeyChecking=yes&lt;/code&gt; requires an already trusted host key. &lt;code&gt;ConnectTimeout=3&lt;/code&gt; limits connection establishment and the initial handshake, not the entire transfer or every name-resolution delay. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://man.openbsd.org/ssh_config&quot;&gt;OpenSSH settings&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The peer list is loaded and validated before any peer is processed. The fetched commit ID is fixed for each review; another fetch cannot silently replace the proposal. Nonignored untracked files block updates too. Ignored files may remain, but a merge must not overwrite one that collides with an incoming tracked path.&lt;/p&gt;
&lt;h3 id=&quot;updating-the-other-device-immediately&quot;&gt;Updating the Other Device Immediately&lt;/h3&gt;
&lt;p&gt;SSH access makes a return update possible. After reviewing an outgoing diff, answer the separate prompt:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Proposed update: desktop -&amp;gt; laptop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Send and apply this reviewed result on laptop now? [y/N]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;This approval authorizes changing the other device’s checkout, including its existing Stow-linked configuration.&lt;/strong&gt; No second terminal prompt appears there. Applications may read the updated files immediately; the script does not reload them or install new Stow links.&lt;/p&gt;
&lt;p&gt;The same script must be installed at &lt;code&gt;~/.local/bin/fleet-sync&lt;/code&gt; on that peer. Git invokes its receiver mode over the existing SSH connection. It transfers the reviewed commit through a temporary Git ref, then the receiver checks that it is still on the expected clean &lt;code&gt;main&lt;/code&gt; and applies only a fast-forward. If the target changed, contains unfinished work, is busy, or has a colliding ignored file, the update is refused. A failed return update leaves the accepted local result available for a later retry. The temporary ref is removed on normal completion or handled failure. Git’s custom receive command support provides the transport. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-push&quot;&gt;Git push documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Answer &lt;code&gt;n&lt;/code&gt; to leave the other device alone and let it fetch later. A forge with a restricted Git-only SSH service generally cannot run this helper; keep it fetch-only in this script and use an ordinary explicit &lt;code&gt;git push&lt;/code&gt; when desired.&lt;/p&gt;
&lt;h3 id=&quot;more-than-two-devices&quot;&gt;More Than Two Devices&lt;/h3&gt;
&lt;p&gt;Peers are processed sequentially. Each accepted result becomes the starting point for the next comparison; previous approvals are not rolled back if a later peer fails. A peer visited early may need another pass to receive changes discovered later in the list.&lt;/p&gt;
&lt;p&gt;A nonblocking &lt;code&gt;flock&lt;/code&gt; lock prevents two Fleetsync operations from editing the same repository simultaneously, including the receiver. A busy destination refuses the transfer instead of waiting indefinitely. This coordinates Fleetsync instances, not unrelated editor or Git processes: avoid concurrent manual Git operations in the same checkout. Checks immediately before applying catch common changes during review. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://man7.org/linux/man-pages/man1/flock.1.html&quot;&gt;flock documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-use-the-same-routine-for-pass&quot;&gt;5. Use the Same Routine for pass&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pass&lt;/code&gt; keeps entries encrypted with GnuPG. Start on one machine with the intended recipients’ public keys already imported and a recovery plan for the corresponding private keys. Substitute real public-key fingerprints below:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; init RECIPIENT_A_FINGERPRINT RECIPIENT_B_FINGERPRINT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git init&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git branch&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -M&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;pass git init&lt;/code&gt; records existing contents and configures Git integration; do not add a redundant initialization commit. Clone the resulting store onto another machine only if its destination does not already contain a password store:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone user@desktop.local:/home/user/.password-store ~/.password-store&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Provision that machine’s decryption key securely and separately, then verify that it can read an entry. Do not put private keys in either repository. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.passwordstore.org/&quot;&gt;pass documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If both machines already contain password stores without a shared Git history, stop before cloning or initializing them independently. Back up both stores and compare the encrypted files and recipient configuration first. An entry present on only one device may be a new addition or an intentional deletion on the other; do not automatically take the union. Agree on the intended initial contents, resolve any differing entries deliberately, and create one initial history from that result. Keep the original stores until the replacement and decryption checks succeed.&lt;/p&gt;
&lt;p&gt;Add and commit a &lt;code&gt;fleet.conf&lt;/code&gt; inside this repository too:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;desktop    user@desktop.local:/home/user/.password-store&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;laptop     user@laptop.local:/home/user/.password-store&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git add fleet.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Add peer list&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fleet-sync&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.password-store&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Keep the confirmation here as well.&lt;/strong&gt; The script shows additions, modifications, and deletions by filename, plus the text diff for files other than &lt;code&gt;.gpg&lt;/code&gt; entries. Inspect recipient changes in &lt;code&gt;.gpg-id&lt;/code&gt; carefully: they influence future encryption. Changes to the peer list also deserve review.&lt;/p&gt;
&lt;p&gt;A plaintext password comparison is possible: &lt;code&gt;pass git init&lt;/code&gt; configures a GPG text-conversion diff driver locally. That Git configuration does not travel with a clone. The script explicitly disables text conversion and excludes encrypted entries from its content diff, so an ordinary sync does not automatically print passwords. Decrypt individual versions deliberately if you need to resolve a password conflict. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git.zx2c4.com/password-store/tree/src/password-store.sh&quot;&gt;pass implementation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For a recipient change, first bring the participating machines to a common commit. Run &lt;code&gt;pass init&lt;/code&gt; with the complete new recipient list on one machine, inspect its generated commits, and let the others fetch that history. Re-encryption alone does not imply divergent history; independent commits do. Removing a recipient cannot retract old ciphertext or secrets that device already obtained. Rotate affected credentials if access must actually be revoked.&lt;/p&gt;
&lt;p&gt;Encryption leaves filenames and Git metadata visible. Choose nonsensitive entry names and protect backups and key recovery material.&lt;/p&gt;
&lt;h2 id=&quot;6-resolve-conflicts-without-changing-live-files-first&quot;&gt;6. Resolve Conflicts Without Changing Live Files First&lt;/h2&gt;
&lt;p&gt;Divergence means both sides contain commits absent from the other. It does not necessarily mean they edited the same lines. The script first shows both histories and asks whether to prepare a merge.&lt;/p&gt;
&lt;p&gt;Git performs that merge in a &lt;strong&gt;temporary detached worktree&lt;/strong&gt;, sharing the existing object database. The active checkout and its Stow targets remain unchanged while you review. This is needed for preparing a combined result; ordinary fetch-and-review updates still need no second checkout. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-worktree&quot;&gt;Git worktree documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Git combines nonconflicting changes. For each remaining conflict, the script identifies the file and offers:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Local = desktop; peer = laptop.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;l = whole LOCAL file; p = whole PEER file; e = merge editor; a = abort.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Choose [l/p/e/a]:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;l&lt;/code&gt; or &lt;code&gt;p&lt;/code&gt; selects that side’s &lt;strong&gt;entire file&lt;/strong&gt;, including deletion if it does not exist on that side. To combine individual changes within a text file, choose &lt;code&gt;e&lt;/code&gt;. The default is Git’s &lt;code&gt;vimdiff&lt;/code&gt; mergetool: &lt;code&gt;LOCAL&lt;/code&gt; is this device’s version, &lt;code&gt;REMOTE&lt;/code&gt; is the peer’s version, and &lt;code&gt;MERGED&lt;/code&gt; is the result to save. You may choose another installed Git mergetool with &lt;code&gt;FLEET_MERGETOOL&lt;/code&gt;, for example &lt;code&gt;FLEET_MERGETOOL=meld fleet-sync&lt;/code&gt;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-mergetool&quot;&gt;Git mergetool documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Encrypted &lt;code&gt;.gpg&lt;/code&gt; files are never opened in this text editor or decrypted for the displayed diff. Select a complete encrypted version only if you know it is the intended one; otherwise abort and reconcile that entry separately.&lt;/p&gt;
&lt;p&gt;After conflict resolution, the script shows the complete proposed change to the local checkout and asks:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Accept and commit this combined result locally? [y/N]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only &lt;code&gt;y&lt;/code&gt; creates the merge commit and fast-forwards the active checkout to it. A conflict-free merge of divergent histories still needs this approval. Aborting or rejecting the result discards the temporary worktree for that peer. After local acceptance, you may separately approve sending the result back. Both original histories remain ancestors of the merge commit, so other peers can receive the convergence through a fast-forward. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-merge&quot;&gt;Git merge documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;7-optional-remote-and-backups&quot;&gt;7. Optional Remote and Backups&lt;/h2&gt;
&lt;p&gt;A private Forgejo repository can provide an extra copy reachable when the direct peers are asleep. If you already use one, push your converged branch to it explicitly:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; remote add forgejo git@forgejo.example.org:example/dotfiles.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push forgejo main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add its SSH URL to &lt;code&gt;fleet.conf&lt;/code&gt; under a label such as &lt;code&gt;forgejo&lt;/code&gt; if the script should also fetch it. Decline the script’s direct-checkout return update for this remote and use the ordinary push command above instead. Prepare its host key and authentication first. Do the equivalent separately for the password store. This service is optional; it only has commits someone has pushed to it.&lt;/p&gt;
&lt;p&gt;Keep independent backups. For a portable Git-history copy, create a bundle &lt;strong&gt;outside&lt;/strong&gt; the checkout, for example on mounted encrypted backup media:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;backup_dir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/path/to/mounted/encrypted-backup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bundle&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$backup_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dotfiles-$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F-%H%M%S).bundle&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/src/dotfiles bundle create &amp;quot;&lt;/span&gt;&lt;span&gt;$bundle&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/src/dotfiles bundle verify &amp;quot;&lt;/span&gt;&lt;span&gt;$bundle&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use an existing destination and avoid overwriting an earlier backup. Repeat for the password store. A bundle can seed a clone, but it does not contain uncommitted files, local Git configuration, or private GPG keys; back up recovery material separately. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-bundle&quot;&gt;Git bundle documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The everyday habit stays small: &lt;strong&gt;commit your work; fetch, review, and accept; optionally send the reviewed result back.&lt;/strong&gt; Add signatures, a fetch-only timer, or VPN reachability later only if a concrete need appears. None is required for a few trusted computers exchanging reviewed changes on the same LAN.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-add&quot;&gt;Git: staging reviewed changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-commit&quot;&gt;Git: recording commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.x.org/releases/current/doc/man/man1/xrdb.1.xhtml&quot;&gt;X.Org xrdb manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-fetch&quot;&gt;Git: fetch and SSH repository URLs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-merge&quot;&gt;Git: fast-forwards, merges, and conflict recovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-worktree&quot;&gt;Git: temporary worktrees&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-mergetool&quot;&gt;Git: conflict editors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-push&quot;&gt;Git: push and custom receive commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://man7.org/linux/man-pages/man1/flock.1.html&quot;&gt;flock: coordinating script instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/git-bundle&quot;&gt;Git: bundle backup and transfer format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/docs/gitignore&quot;&gt;Git: ignore patterns and tracked files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gnu.org/software/stow/manual/stow.html&quot;&gt;GNU Stow manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://man.openbsd.org/ssh_config&quot;&gt;OpenSSH: client configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://man.openbsd.org/ssh-keygen&quot;&gt;OpenSSH: key fingerprints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.rfc-editor.org/rfc/rfc6762&quot;&gt;RFC 6762: Multicast DNS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.passwordstore.org/&quot;&gt;pass: documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git.zx2c4.com/password-store/tree/src/password-store.sh&quot;&gt;pass: Git integration and recipient handling implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.syncthing.net/users/syncing.html&quot;&gt;Syncthing: synchronization and conflicts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Duke Nukem II: 5 Handy DOS-Era Tricks for Rigelatin</title>
          <pubDate>Wed, 09 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/duke-nukem-ii-retro-guide/</link>
          <guid>https://criticalbasics.xyz/posts/duke-nukem-ii-retro-guide/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/duke-nukem-ii-retro-guide/">&lt;p&gt;Released for PC in December 1993, &lt;em&gt;Duke Nukem II&lt;/em&gt; is Apogee’s colourful 256-colour sequel: four episodes with eight stages apiece, while episode one was the original shareware sampler. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamespot.com/games/duke-nukem-ii/&quot;&gt;GameSpot’s release record&lt;/a&gt; and the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://ftp.gamefilearchive.com/ftp.3drealms.com/stuff/Downloads.html&quot;&gt;3D Realms archive&lt;/a&gt; are useful period references.&lt;/p&gt;
&lt;h2 id=&quot;five-tricks-worth-remembering&quot;&gt;Five tricks worth remembering&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the full aiming range.&lt;/strong&gt; Arrow keys move and aim; &lt;code&gt;Ctrl&lt;/code&gt; jumps, &lt;code&gt;Alt&lt;/code&gt; fires, and &lt;code&gt;PgUp&lt;/code&gt; / &lt;code&gt;PgDn&lt;/code&gt; make Duke look up or down. Looking down before a blind drop and aiming up under a ledge makes several enemy placements much less unfair. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://strategywiki.org/wiki/Duke_Nukem_II/Gameplay&quot;&gt;control reference&lt;/a&gt; documents the keyboard layout.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Restart beacons are your real safety net.&lt;/strong&gt; Activate one before probing suspicious floors, ceilings, and walls. It moves the retry point forward, so secret hunting costs far less time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Play the level twice when a secret is tempting.&lt;/strong&gt; First clear it normally and learn the enemy rhythm; then revisit side passages and odd-looking walls. The first episode contains the famous opening prison sequence and is the best place to learn the game’s visual language.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep the registered-version cheats separate from the shareware demo.&lt;/strong&gt; During play, &lt;code&gt;EAT&lt;/code&gt; restores health. &lt;code&gt;NUK&lt;/code&gt; (or &lt;code&gt;DUKM&lt;/code&gt;) supplies a weapon plus the inventory needed for the current level. These are documented for the PC full game; the shareware episode deliberately rejects cheat input. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://strategywiki.org/wiki/Duke_Nukem_II/Cheats&quot;&gt;StrategyWiki’s cheat reference&lt;/a&gt; records both the restriction and the effects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Treat the shareware episode as a proper test run.&lt;/strong&gt; It is not freeware and not the complete game: it is one episode intended to demonstrate the full release. That distinction matters when collecting old DOS titles.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;play-it-legally&quot;&gt;Play it legally&lt;/h2&gt;
&lt;p&gt;The archived &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://ftp.gamefilearchive.com/ftp.3drealms.com/stuff/Downloads.html&quot;&gt;3D Realms master download page&lt;/a&gt; lists &lt;code&gt;4duke.zip&lt;/code&gt; as the official v1.0 Duke Nukem II shareware episode. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://dnr.duke4.net/shareware.php.html&quot;&gt;Duke Nukem Repository’s Shareware page&lt;/a&gt; also identifies it as the 1.06 MB shareware release. For a complete version, use a current licensed retailer or an official collection rather than treating the shareware episode as the full game.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://ftp.gamefilearchive.com/ftp.3drealms.com/stuff/Downloads.html&quot;&gt;3D Realms master download archive&lt;/a&gt; — original shareware listing.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://dnr.duke4.net/shareware.php.html&quot;&gt;Duke Nukem Repository: Shareware&lt;/a&gt; — archive details and download classification.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://strategywiki.org/wiki/Duke_Nukem_II/Cheats&quot;&gt;StrategyWiki: Duke Nukem II cheats&lt;/a&gt; — cheat behaviour and shareware limitation.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamespot.com/games/duke-nukem-ii/&quot;&gt;GameSpot: Duke Nukem II&lt;/a&gt; — release date, platform, developer and genre record.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-legal-notice&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-heading&quot;&gt;⚖ RIGHTS &amp;amp; FAN GUIDE NOTICE&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-body&quot;&gt;&lt;strong&gt;Duke Nukem II.&lt;/strong&gt; Duke Nukem is a historic Apogee/3D Realms game series; &lt;a href=&quot;https://3drealms.com/about/&quot;&gt;3D Realms identifies it among its legacy catalogue&lt;/a&gt;. This independent, non-commercial guide and its original illustration are not affiliated with or endorsed by any rights holder. The title, characters, game software and original artwork remain with their respective rights holders.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Micro Machines: Tiny Cars, Giant Kitchen-Table Chaos</title>
          <pubDate>Wed, 09 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/micro-machines-dos-guide/</link>
          <guid>https://criticalbasics.xyz/posts/micro-machines-dos-guide/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/micro-machines-dos-guide/">&lt;p&gt;&lt;em&gt;Micro Machines&lt;/em&gt; turns ordinary surfaces into impossibly fast racetracks: breakfast tables, desks, bathtubs and garden furniture become worlds for toy-sized vehicles. The series began on NES in 1991; the MS-DOS port arrived in 1994 and was developed by Big Red Software. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/Micro_Machines_(video_game)&quot;&gt;The release overview&lt;/a&gt; lists the DOS version alongside the other ports, while the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;original manual&lt;/a&gt; makes its toy licence unusually explicit: the Micro Machines mark belonged to Lewis Galoob Toys and Codemasters used it under licence.&lt;/p&gt;
&lt;p&gt;The central idea is wonderfully mean: this is a top-down racer, but the tight single-screen duel rewards gaining a whole screen length over the other driver, rather than merely counting down a lap timer. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/Micro_Machines_(video_game)&quot;&gt;gameplay history&lt;/a&gt; explains the resulting colour-light score system and why it was used instead of split-screen.&lt;/p&gt;
&lt;h2 id=&quot;the-useful-stuff-the-game-barely-tells-you&quot;&gt;The useful stuff the game barely tells you&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Steer for the car’s direction, not the screen.&lt;/strong&gt; The manual says left and right rotate the vehicle anti-clockwise and clockwise regardless of whether it currently points up or down. That sounds obvious, but it is the source of many first-lap crashes: resist “screen-left” instincts and steer as though holding a tiny physical car. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Original control notes&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the qualifier as a handling laboratory.&lt;/strong&gt; The opening Micro Machines Challenge race takes place in a bathtub and is explicitly described as a place to practise. Test the turn-in point with no ambition to win, then repeat with a shorter acceleration burst before the next corner. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Original manual: qualifier race&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Brake early; reverse is a recovery tool.&lt;/strong&gt; Holding the fire control accelerates until full speed. Moving down while already travelling forward slows the vehicle; once stopped, it becomes reverse. That makes a tiny correction after a missed corner much cheaper than a wide high-speed loop around the table. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Original control notes&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Second place is success in Challenge.&lt;/strong&gt; A first- or second-place finish advances you to another track and vehicle. Third or fourth costs a chance and repeats the course; the run starts with three chances. Treat a safe second as a genuine tactical result, especially on an unfamiliar vehicle class. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Original Challenge rules&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The route is the real opponent.&lt;/strong&gt; Every course has a defined path; lingering off it sends a car back onto the circuit. So a dramatic-looking shortcut over crumbs, paper or carpet is usually slower unless it reconnects immediately. The top-down route rule is explained in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/Micro_Machines_(video_game)&quot;&gt;gameplay reference&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Head-to-head is a score-light tug-of-war.&lt;/strong&gt; Both sides begin with four coloured lights. Pull a screen ahead and one light changes to your colour; take all eight, or lead after three laps, to win. A tie goes to sudden death. It means that a clean escape from one corner can matter more than defending every pixel of the lap. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Original head-to-head rules&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose opponents with the campaign in mind.&lt;/strong&gt; After qualifying, the manual lets you select three opponents, then replace drivers as they drop out. It even advises reserving weaker characters for later rounds. That is a rare bit of tournament planning hiding inside an arcade racer. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Original opponent-selection notes&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Do not copy random console cheats into DOS.&lt;/strong&gt; Cheats documented online are often explicitly tied to CD-i, Master System, Game Gear or NES releases—for example, the hard-mode sequences and the secret-credits trick. They are interesting port trivia, but not verified DOS codes. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://gamefaqs.gamespot.com/cdi/581287-micro-machines/cheats&quot;&gt;Version-labelled cheat list&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A famous bug belongs to the NES original, too.&lt;/strong&gt; The first race could crash if the player reversed; the fix was a small add-on in affected cartridges. It is a great piece of launch-era lore, but it is not a reason to expect the DOS port to reproduce it. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/Micro_Machines_(video_game)&quot;&gt;Development history&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;play-it-legally&quot;&gt;Play it legally&lt;/h2&gt;
&lt;p&gt;The surviving DOS manual is useful documentation, but it is not a licence to redistribute the game. I have not found a current authorised DOS download from the rights holders, so the sensible route is original media or a verified authorised re-release if one becomes available. The period manual itself identifies the Galoob trademark licence and Codemasters copyright notice. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Manual copyright and trademark page&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.gamesdatabase.org/Media/SYSTEM/Microsoft_DOS/manual/Formated/Micro_Machines.pdf&quot;&gt;Micro Machines DOS manual&lt;/a&gt; — controls, Challenge rules, head-to-head scoring, settings and original rights notice.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/Micro_Machines_(video_game)&quot;&gt;Micro Machines release and development overview&lt;/a&gt; — DOS release year, platforms, top-down route mechanic and development trivia.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://gamefaqs.gamespot.com/cdi/581287-micro-machines/cheats&quot;&gt;GameFAQs version-labelled codes&lt;/a&gt; — comparison point for cheats that belong to other ports rather than DOS.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-legal-notice&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-heading&quot;&gt;⚖ RIGHTS &amp;amp; FAN GUIDE NOTICE&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-body&quot;&gt;&lt;strong&gt;Micro Machines.&lt;/strong&gt; The original DOS manual identifies Micro Machines as a registered trademark of Lewis Galoob Toys, Inc. and credits Codemasters Software Company Ltd. for the game. This independent, non-commercial guide and its original illustration are not affiliated with or endorsed by the trademark or copyright owners. Game software, names, characters and original art remain with their respective rights holders.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Stunts: The DOS Racer That Lets You Build the Impossible</title>
          <pubDate>Wed, 09 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/stunts-retro-guide/</link>
          <guid>https://criticalbasics.xyz/posts/stunts-retro-guide/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/stunts-retro-guide/">&lt;p&gt;&lt;em&gt;Stunts&lt;/em&gt; (also sold as &lt;em&gt;4D Sports Driving&lt;/em&gt;) is a 1990 DOS racing game by Distinctive Software. Its enduring trick is simple: race against an opponent, then build a more ridiculous course and save the replay. It has 11 cars, automatic or manual transmission, multiple camera angles and a grid-based track editor. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://de.wikipedia.org/wiki/Stunts&quot;&gt;Wikipedia’s overview&lt;/a&gt; and the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://wiki.stunts.hu/wiki/Download&quot;&gt;Stunts Wiki version notes&lt;/a&gt; give the useful release context.&lt;/p&gt;
&lt;h2 id=&quot;five-tricks-for-better-laps-and-better-tracks&quot;&gt;Five tricks for better laps and better tracks&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Drive from the keyboard first.&lt;/strong&gt; &lt;code&gt;Ctrl+K&lt;/code&gt; switches to keyboard control; &lt;code&gt;Ctrl+J&lt;/code&gt; calibrates and switches to joystick control. The old analogue-joystick default can feel imprecise on modern setups, so keyboard steering is an excellent baseline. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://kalpen.de/luke/4dinfo.html&quot;&gt;Luke’s key reference&lt;/a&gt; documents both modes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the replay as a diagnostic tool.&lt;/strong&gt; During a replay, &lt;code&gt;R&lt;/code&gt; toggles the VCR panel. &lt;code&gt;F1&lt;/code&gt;–&lt;code&gt;F4&lt;/code&gt;, &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;D&lt;/code&gt;, &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;P&lt;/code&gt; retain their driving-view functions, so watch the same jump from more than one camera before blaming the car. The original manual’s reference card lists &lt;code&gt;R&lt;/code&gt; as the replay-panel toggle. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.retrogames.cz/manualy/DOS/4D_Sports_Driving_-_DOS_-_Manual.pdf&quot;&gt;Manual scan&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make the approach to a stunt boring.&lt;/strong&gt; Give a loop, ramp or corkscrew a straight approach and a straight exit. A difficult stunt after a blind bend mostly tests luck; a clean approach lets you learn speed and steering.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build with the editor’s limits in mind.&lt;/strong&gt; The original editor is tile-based, which is why tracks can create wonderfully abrupt transitions. Use it deliberately: first make a reliable closed lap, then add one stunt section at a time. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://wiki.stunts.hu/wiki/Download&quot;&gt;Stunts Wiki&lt;/a&gt; notes that v1.1 from February 1991 is the usual version for current competitions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Race your own ghost.&lt;/strong&gt; Save a clean replay before experimenting. It gives you a personal benchmark and preserves the satisfying evidence when a wild shortcut finally works.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;play-it-legally&quot;&gt;Play it legally&lt;/h2&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://wiki.stunts.hu/wiki/Download&quot;&gt;Stunts Wiki download page&lt;/a&gt; distinguishes the historical v1.0 and v1.1 releases, provides manual scans and explains the modern DOSBox requirement. It also points to the preserved v1.1 disk copy. Treat this as preservation information: verify the licensing position in your jurisdiction before downloading a game package, and prefer an authorised re-release where one is available.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://wiki.stunts.hu/wiki/Download&quot;&gt;Stunts Wiki: Download&lt;/a&gt; — version history, manuals and modern-running notes.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://kalpen.de/luke/4dinfo.html&quot;&gt;Luke’s 4D Sports Driving page&lt;/a&gt; — driving, replay and editor key reference.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.retrogames.cz/manualy/DOS/4D_Sports_Driving_-_DOS_-_Manual.pdf&quot;&gt;4D Sports Driving manual&lt;/a&gt; — original control reference.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://de.wikipedia.org/wiki/Stunts&quot;&gt;German Wikipedia overview&lt;/a&gt; — game and editor overview.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-legal-notice&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-heading&quot;&gt;⚖ RIGHTS &amp;amp; FAN GUIDE NOTICE&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-body&quot;&gt;&lt;strong&gt;Stunts / 4D Sports Driving.&lt;/strong&gt; The game was developed by Distinctive Software and historically published by Broderbund and Mindscape, as documented by &lt;a href=&quot;https://www.dosdays.co.uk/topics/Games/game_4ddriving.php&quot;&gt;DOS Days&lt;/a&gt;. Rights in the game, its names and its original artwork remain with their respective holders. This independent, non-commercial guide and its original illustration are not affiliated with or endorsed by them.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Total Recall (1990): Details Worth a Second Memory</title>
          <pubDate>Wed, 09 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/total-recall-retro-guide/</link>
          <guid>https://criticalbasics.xyz/posts/total-recall-retro-guide/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/total-recall-retro-guide/">&lt;p&gt;Paul Verhoeven’s &lt;em&gt;Total Recall&lt;/em&gt; (1990), starring Arnold Schwarzenegger as Douglas Quaid, turns a Mars holiday into a question about memory, identity and whether an adventure can be too perfectly tailored. It is a loose adaptation of Philip K. Dick’s 1966 story &lt;em&gt;We Can Remember It for You Wholesale&lt;/em&gt;, whose original premise already pairs an ordinary man, an unaffordable Mars trip and purchased memories. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://philipdick.com/pkd-and-me/Total-Recall&quot;&gt;Philip K. Dick’s archive&lt;/a&gt; gives the useful literary starting point.&lt;/p&gt;
&lt;h2 id=&quot;details-worth-watching-for&quot;&gt;Details worth watching for&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Watch the Rekall sales pitch as a checklist.&lt;/strong&gt; It promises a very specific fantasy: Mars, espionage, romance and a mission. The film later keeps returning to those ingredients. That does not prove one reading of the ending, but it makes the “implant gone wrong” interpretation deliberately tempting.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The film preserves two possible realities.&lt;/strong&gt; Edgemar’s warning sounds tailored to Quaid’s experience, and IMDb’s production trivia notes that several of his predictions are echoed visually later. The white fade-out is therefore less a solution than a prompt to revisit the film with the opposite interpretation in mind. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.imdb.com/title/tt0100802/trivia/&quot;&gt;IMDb trivia&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mexico City provides much of its future concrete.&lt;/strong&gt; The production began there because the Metro’s angular, brutalist architecture looked futuristic and Estudios Churubusco could hold the huge indoor sets. Mars feels like a constructed world because, in large part, it literally was one. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.imdb.com/title/tt0100802/trivia/&quot;&gt;IMDb production trivia&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The special effects were formally exceptional.&lt;/strong&gt; The Academy gave &lt;em&gt;Total Recall&lt;/em&gt; a Special Achievement Award for Visual Effects at the 63rd Academy Awards. It is a useful reminder to look for physical transformations, miniature-scale machinery and makeup effects rather than assuming the spectacle was computer-generated. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://awardsdatabase.oscars.org/Search/GetResults?query=%7B%22AwardCategory%22%3A%5B%2224%22%5D%2C%22Sort%22%3A%223-Award+Category-Chron%22%2C%22Search%22%3A%22Basic%22%7D&quot;&gt;Academy Awards database&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compare the story’s name before and after the adaptation.&lt;/strong&gt; Dick’s protagonist is Douglas &lt;strong&gt;Quail&lt;/strong&gt;, not Quaid, and he dreams of Mars before he can afford to go there. The film expands that compact identity puzzle into a muscular conspiracy thriller; reading the short story afterwards highlights exactly what changed. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://philipdick.com/mirror/websites/pkdweb/short_stories/We%20Can%20Remember%20It%20For%20You%20Wholesale.htm&quot;&gt;Story background&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://philipdick.com/pkd-and-me/Total-Recall&quot;&gt;Philip K. Dick: story background&lt;/a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://philipdick.com/mirror/websites/pkdweb/short_stories/We%20Can%20Remember%20It%20For%20You%20Wholesale.htm&quot;&gt;story text/archive&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.imdb.com/title/tt0100802/trivia/&quot;&gt;IMDb: Total Recall trivia&lt;/a&gt; — production and narrative-detail reference.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://awardsdatabase.oscars.org/Search/GetResults?query=%7B%22AwardCategory%22%3A%5B%2224%22%5D%2C%22Sort%22%3A%223-Award+Category-Chron%22%2C%22Search%22%3A%22Basic%22%7D&quot;&gt;Academy Awards database&lt;/a&gt; — 1990 Special Achievement Award for Visual Effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-legal-notice&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-heading&quot;&gt;⚖ RIGHTS &amp;amp; FAN GUIDE NOTICE&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td class=&quot;retro-legal-body&quot;&gt;&lt;strong&gt;Total Recall (1990).&lt;/strong&gt; The 1990 film is presented by &lt;a href=&quot;https://www.paramountpictures.com/movies/total-recall&quot;&gt;Paramount Pictures&lt;/a&gt;. The title, characters, screenplay, original imagery and film footage remain with their respective rights holders. This independent, non-commercial guide and its original pixel-art illustration are not affiliated with or endorsed by Paramount or any other rights holder.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Deploying the Nextcloud Talk AIO Recording Backend as a Standalone Container</title>
          <pubDate>Sun, 06 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/nextcloud-talk-aio-recording-standalone/</link>
          <guid>https://criticalbasics.xyz/posts/nextcloud-talk-aio-recording-standalone/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/nextcloud-talk-aio-recording-standalone/">&lt;p&gt;This guide deploys the official Nextcloud AIO Talk Recording image as a standalone container. It complements an existing Nextcloud Talk High-Performance Backend and does not require a full Nextcloud AIO installation.&lt;/p&gt;
&lt;p&gt;The recording backend joins Talk calls as a participant, captures the selected media, and uploads the result back to Nextcloud. It needs its own resources, storage for temporary recordings, and a secure internal connection to the matching signaling backend.&lt;/p&gt;
&lt;p&gt;The deployment uses the pre-built image from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nextcloud/all-in-one&quot;&gt;Nextcloud AIO project&lt;/a&gt; and follows the upstream &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nextcloud/nextcloud-talk-recording/blob/main/docs/installation.md&quot;&gt;Recording Backend installation documentation&lt;/a&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            RECORDING IS A SEPARATE COMPONENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The standalone AIO Talk container provides signaling, Janus, NATS, and TURN. It does &lt;strong&gt;not&lt;/strong&gt; include recording. Deploy the Recording Backend separately and configure it in Nextcloud Talk afterwards.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-06&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Added the standalone AIO Talk Recording Backend guide.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working Nextcloud Talk installation.&lt;/li&gt;
&lt;li&gt;A working Talk High-Performance Backend (HPB).&lt;/li&gt;
&lt;li&gt;Docker Engine and Docker Compose v2.&lt;/li&gt;
&lt;li&gt;A Traefik v3 reverse proxy on an external Docker network named &lt;code&gt;proxy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A DNS name and TLS certificate for the recording endpoint, or a dedicated path below the existing signaling hostname.&lt;/li&gt;
&lt;li&gt;At least 2 GB of shared memory available to the recording container.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide is designed to follow &lt;strong&gt;&lt;a href=&quot;../nextcloud-talk-aio-standalone-hpb/&quot;&gt;Running the Nextcloud Talk AIO Container as a Standalone High-Performance Backend&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The following internal tutorials provide the surrounding infrastructure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../debian-server-initial-setup/&quot;&gt;Debian Server Initial Setup&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For Compose syntax, reverse-proxy behavior, and trusted-proxy settings, see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose documentation&lt;/a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://doc.traefik.io/traefik/&quot;&gt;Traefik documentation&lt;/a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html&quot;&gt;Nextcloud reverse-proxy documentation&lt;/a&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            PLAN CAPACITY FOR RECORDINGS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Recording uses a browser, video capture, and transcoding. CPU, memory, and temporary storage requirements rise with the number, duration, and resolution of concurrent recordings. Start with one recorder per HPB and monitor it before increasing capacity.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;2-create-the-project-directory-and-secrets&quot;&gt;2. Create the project directory and secrets&lt;/h2&gt;
&lt;p&gt;Create an isolated project directory:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk-recording&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk-recording&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generate a new recording secret:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;INTERNAL_SECRET&lt;/code&gt; is not a new value: it must be the same value used by the corresponding AIO Talk container. The recording backend uses it to authenticate to that signaling server.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt; and replace every placeholder:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# The existing Nextcloud hostname, without https://&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;NC_DOMAIN=cloud.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# The public hostname of the matching AIO Talk backend&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;HPB_DOMAIN=talk.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Leave empty for a dedicated hostname, or use a matching Traefik path prefix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;HPB_PATH=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Generate this specifically for the recording backend.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;RECORDING_SECRET=REPLACE_WITH_A_RANDOM_64_HEX_CHARACTER_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Copy this value from the matching AIO Talk container only.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;INTERNAL_SECRET=REPLACE_WITH_THE_MATCHING_TALK_INTERNAL_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            KEEP THE TWO SECRETS DISTINCT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;&lt;code&gt;RECORDING_SECRET&lt;/code&gt; is shared with Nextcloud’s Recording Backend setting. &lt;code&gt;INTERNAL_SECRET&lt;/code&gt; is shared only with the matching Talk HPB. Do not reuse either value between unrelated Nextcloud instances.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;3-create-the-docker-compose-file&quot;&gt;3. Create the Docker Compose file&lt;/h2&gt;
&lt;p&gt;The example below exposes the recorder through a dedicated hostname. It stores temporary recordings in a named Docker volume and gives the browser enough shared memory.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  recording:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/nextcloud-releases/aio-talk-recording:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: nextcloud-aio-talk-recording&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    user: &amp;quot;122&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    init: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    read_only: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    shm_size: 2gb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    tmpfs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - /conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    env_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      ALLOW_ALL: &amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      SKIP_VERIFY: &amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      NC_PROTOCOL: https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      HPB_PROTOCOL: https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      AIO_LOG_LEVEL: warn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      TZ: Europe/Vienna&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - recording-tmp:/tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk-recording.rule=Host(`recording.example.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk-recording.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk-recording.tls=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk-recording.middlewares=nextcloud-aio-talk-recording-headers@docker,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.nextcloud-aio-talk-recording-headers.headers.customRequestHeaders.X-Forwarded-Proto=https&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.nextcloud-aio-talk-recording.loadbalancer.server.port=1234&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  recording-tmp:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            USING A PATH PREFIX
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If the recorder is published at a path such as &lt;code&gt;https://talk.example.com/recording-one&lt;/code&gt;, change the Traefik router rule to include &lt;code&gt;PathPrefix&lt;/code&gt;, add a &lt;code&gt;StripPrefix&lt;/code&gt; middleware, and use the same full URL in the Nextcloud Recording Backend setting. &lt;code&gt;HPB_PATH&lt;/code&gt; is independent: it points from the recorder to its matching Talk signaling endpoint.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;4-start-and-verify-the-recorder&quot;&gt;4. Start and verify the recorder&lt;/h2&gt;
&lt;p&gt;Pull and start the image:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk-recording&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait until Docker reports a healthy container:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker inspect nextcloud-aio-talk-recording&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;/&amp;quot;Health&amp;quot;: {/,/},/p&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inspect logs when the health check does not become healthy:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail 100&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-aio-talk-recording&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The recorder must be able to resolve and reach both &lt;code&gt;NC_DOMAIN&lt;/code&gt; and the signaling URL constructed from &lt;code&gt;HPB_DOMAIN&lt;/code&gt; and &lt;code&gt;HPB_PATH&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;5-configure-the-recording-backend-in-nextcloud-talk&quot;&gt;5. Configure the Recording Backend in Nextcloud Talk&lt;/h2&gt;
&lt;p&gt;In Nextcloud, open &lt;strong&gt;Administration settings → Talk&lt;/strong&gt; and enter:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Setting&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Recording backend URL&lt;/td&gt;&lt;td&gt;&lt;code&gt;https://recording.example.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Shared secret&lt;/td&gt;&lt;td&gt;The value of &lt;code&gt;RECORDING_SECRET&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Verify SSL certificate&lt;/td&gt;&lt;td&gt;Enabled&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Save the settings and confirm that the Talk setup check reports a successful Recording Backend.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            MIGRATE BEFORE REMOVING THE OLD RECORDER
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;When replacing an existing recording service, start and health-check the new recorder first. Change the Nextcloud setting, verify the Talk setup check, and make a real recording before stopping the old service.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;6-make-a-real-recording-test&quot;&gt;6. Make a real recording test&lt;/h2&gt;
&lt;p&gt;The health check proves that the container starts, but it cannot verify browser capture, TURN fallback, or upload permissions. Create a test room and:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start an audio/video recording as a room moderator.&lt;/li&gt;
&lt;li&gt;Let the call run briefly and stop the recording.&lt;/li&gt;
&lt;li&gt;Confirm that the recording appears in the configured Nextcloud location and can be played.&lt;/li&gt;
&lt;li&gt;Check the recorder logs while the recording is being processed.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-aio-talk-recording&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;7-multiple-independent-nextcloud-instances&quot;&gt;7. Multiple independent Nextcloud instances&lt;/h2&gt;
&lt;p&gt;Use a separate recorder for every isolated AIO Talk container.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Item&lt;/th&gt;&lt;th&gt;First instance&lt;/th&gt;&lt;th&gt;Second instance&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Recording project&lt;/td&gt;&lt;td&gt;&lt;code&gt;nextcloud-aio-talk-recording-one&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;nextcloud-aio-talk-recording-two&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Recording endpoint&lt;/td&gt;&lt;td&gt;&lt;code&gt;recording-one.example.com&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;recording-two.example.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NC_DOMAIN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;cloud-one.example.com&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;cloud-two.example.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;HPB endpoint&lt;/td&gt;&lt;td&gt;&lt;code&gt;talk-one.example.com&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;talk-two.example.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;INTERNAL_SECRET&lt;/code&gt;&lt;/td&gt;&lt;td&gt;From Talk container one&lt;/td&gt;&lt;td&gt;From Talk container two&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;RECORDING_SECRET&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Unique to instance one&lt;/td&gt;&lt;td&gt;Unique to instance two&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Do not point one recorder at two isolated AIO Talk containers. The internal signaling secret must match the one HPB that the recorder joins.&lt;/p&gt;
&lt;h2 id=&quot;8-maintenance-and-troubleshooting&quot;&gt;8. Maintenance and troubleshooting&lt;/h2&gt;
&lt;p&gt;Update the image during a maintenance window:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk-recording&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before updating, back up &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;docker-compose.yml&lt;/code&gt;. The temporary recording volume is cleared by the container at startup; failed or in-progress recordings should therefore be investigated before restarting it.&lt;/p&gt;
&lt;p&gt;If recordings fail:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Confirm that both the recorder and the matching Talk HPB are healthy.&lt;/li&gt;
&lt;li&gt;Confirm that &lt;code&gt;INTERNAL_SECRET&lt;/code&gt; matches the matching AIO Talk container exactly.&lt;/li&gt;
&lt;li&gt;Confirm that &lt;code&gt;RECORDING_SECRET&lt;/code&gt; matches the Talk administration setting exactly.&lt;/li&gt;
&lt;li&gt;Check available RAM, &lt;code&gt;/dev/shm&lt;/code&gt;, disk capacity, and container logs.&lt;/li&gt;
&lt;li&gt;Verify that the recorder can reach Nextcloud and the Talk endpoint using valid TLS certificates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For upstream configuration details, consult the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nextcloud/nextcloud-talk-recording/blob/main/docs/installation.md&quot;&gt;official Nextcloud Talk Recording installation documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;related-tutorials&quot;&gt;Related tutorials&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../nextcloud-talk-aio-standalone-hpb/&quot;&gt;Running the Nextcloud Talk AIO Container as a Standalone High-Performance Backend&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../nextcloud-talk-high-performance-backend/&quot;&gt;Deploying the classic Nextcloud Talk High-Performance Backend with Docker&lt;/a&gt;&lt;/strong&gt; — retained as an archive and migration reference.&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Running the Nextcloud Talk AIO Container as a Standalone High-Performance Backend</title>
          <pubDate>Sun, 06 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/nextcloud-talk-aio-standalone-hpb/</link>
          <guid>https://criticalbasics.xyz/posts/nextcloud-talk-aio-standalone-hpb/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/nextcloud-talk-aio-standalone-hpb/">&lt;p&gt;This guide deploys the official pre-built Nextcloud Talk container as a &lt;strong&gt;standalone High-Performance Backend (HPB)&lt;/strong&gt;. It is intended for an existing, non-AIO Nextcloud installation and does &lt;strong&gt;not&lt;/strong&gt; migrate Nextcloud, its database, files, or reverse proxy to Nextcloud All-in-One.&lt;/p&gt;
&lt;p&gt;The container bundles the components needed for a modern Talk backend: the signaling server, Janus media gateway, NATS, and an integrated TURN service. Compared with maintaining the classic multi-container signaling stack yourself, it removes the custom builds and most component-level configuration.&lt;/p&gt;
&lt;p&gt;It follows the upstream &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://nextcloud-talk.readthedocs.io/en/latest/quick-install/&quot;&gt;Nextcloud Talk quick-install documentation&lt;/a&gt; and uses the pre-built image maintained in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nextcloud/all-in-one&quot;&gt;Nextcloud AIO project&lt;/a&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHAT THIS GUIDE INSTALLS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This is the &lt;strong&gt;AIO Talk container only&lt;/strong&gt;, not the complete Nextcloud AIO appliance. Your existing Nextcloud Docker Compose stack stays in place and is configured to use this backend afterwards.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-06&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Added the standalone AIO Talk container tutorial.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide assumes that you already have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working Nextcloud instance with the &lt;strong&gt;Talk&lt;/strong&gt; app enabled.&lt;/li&gt;
&lt;li&gt;Docker Engine and Docker Compose v2.&lt;/li&gt;
&lt;li&gt;A Traefik v3 reverse proxy with a shared external Docker network named &lt;code&gt;proxy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A dedicated DNS name for the signaling and TURN service, such as &lt;code&gt;talk.example.com&lt;/code&gt;, pointing to the Docker host.&lt;/li&gt;
&lt;li&gt;A valid TLS certificate for that DNS name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access on the Docker host.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reverse-proxy setup from the following guide is a suitable foundation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../debian-server-initial-setup/&quot;&gt;Debian Server Initial Setup&lt;/a&gt;&lt;/strong&gt; for a baseline host and firewall configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For Docker Compose fundamentals and reverse-proxy behavior, refer to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose documentation&lt;/a&gt; and the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://doc.traefik.io/traefik/&quot;&gt;Traefik documentation&lt;/a&gt;. If your Nextcloud instance is already behind a proxy, also verify the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html&quot;&gt;Nextcloud reverse-proxy settings&lt;/a&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            ONE CONTAINER, ONE NEXTCLOUD BACKEND
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The standalone AIO Talk container creates one configured signaling backend from &lt;code&gt;NC_DOMAIN&lt;/code&gt;. Do not add multiple unrelated Nextcloud URLs to one container. For two independent Nextcloud instances, deploy two containers with separate endpoints, secrets, and TURN ports as shown in section 8.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;1-1-firewall-configuration&quot;&gt;1.1. Firewall configuration&lt;/h3&gt;
&lt;p&gt;The reverse proxy handles HTTPS on ports &lt;code&gt;80&lt;/code&gt; and &lt;code&gt;443&lt;/code&gt;. The integrated TURN server must be reachable directly on the Talk port over both TCP and UDP. The examples use &lt;code&gt;3478&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 3478/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 3478/udp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your firewall is managed by a cloud provider or hardware router, open and forward the same two ports there as well.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            TURN IS NOT HTTP TRAFFIC
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The TURN port bypasses Traefik and its HTTP middleware. Keep the Talk container updated, use a long random TURN secret, and restrict host access with your firewall policy where appropriate.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;2-create-the-project-directory-and-secrets&quot;&gt;2. Create the project directory and secrets&lt;/h2&gt;
&lt;p&gt;Create a dedicated directory for the backend. Keeping the &lt;code&gt;.env&lt;/code&gt; file separate prevents secrets from being committed or copied into a public Compose example.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generate three independent secrets:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt; and replace every placeholder. &lt;code&gt;NC_DOMAIN&lt;/code&gt; and &lt;code&gt;TALK_HOST&lt;/code&gt; are host names only, without &lt;code&gt;https://&lt;/code&gt; or a path.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Existing Nextcloud instance that will use this container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;NC_DOMAIN=cloud.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Public DNS name for signaling and TURN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;TALK_HOST=talk.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Keep all three values private and use different random values.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;TURN_SECRET=REPLACE_WITH_A_RANDOM_64_HEX_CHARACTER_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;SIGNALING_SECRET=REPLACE_WITH_A_RANDOM_64_HEX_CHARACTER_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;INTERNAL_SECRET=REPLACE_WITH_A_RANDOM_64_HEX_CHARACTER_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The secrets have different roles:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Secret&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;th&gt;Used in Nextcloud?&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SIGNALING_SECRET&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Authenticates the Nextcloud server to the signaling backend.&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;TURN_SECRET&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Creates short-lived TURN credentials for Talk clients.&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;INTERNAL_SECRET&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Protects internal communication within the backend.&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DO NOT REUSE PLACEHOLDER VALUES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Never use the placeholder strings from this article. Generate unique random secrets for every Talk container and store the &lt;code&gt;.env&lt;/code&gt; file in your password manager or encrypted backup.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;3-create-the-docker-compose-file&quot;&gt;3. Create the Docker Compose file&lt;/h2&gt;
&lt;p&gt;The following Compose file uses Traefik for TLS and WebSocket forwarding. The TURN service is published directly on port &lt;code&gt;3478&lt;/code&gt;, while signaling remains internal and is exposed only through Traefik on port &lt;code&gt;8081&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  talk:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/nextcloud-releases/aio-talk:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    init: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    env_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Required by the standalone AIO Talk image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      TALK_PORT: &amp;quot;3478&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      TURN_DOMAIN: ${TALK_HOST}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      AIO_LOG_LEVEL: warn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      SKIP_CERT_VERIFY: &amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ports:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;3478:3478/tcp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;3478:3478/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk.rule=Host(`${TALK_HOST}`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk.tls=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nextcloud-aio-talk.middlewares=nextcloud-aio-talk-headers@docker,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.nextcloud-aio-talk-headers.headers.customRequestHeaders.X-Forwarded-Proto=https&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.nextcloud-aio-talk.loadbalancer.server.port=8081&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            PATH PREFIXES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The preferred layout is one dedicated signaling hostname per container. If a path prefix is unavoidable, add a Traefik &lt;code&gt;StripPrefix&lt;/code&gt; middleware and use the same prefix in the High-Performance Backend URL in Nextcloud. A dedicated hostname is simpler to operate and troubleshoot.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;4-start-and-verify-the-backend&quot;&gt;4. Start and verify the backend&lt;/h2&gt;
&lt;p&gt;Pull the image and start the container:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify the public signaling endpoint. The response contains a version string and a welcome message:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://talk.example.com/api/v1/welcome&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check the container logs if the endpoint does not respond:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail 100&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Common causes of an unsuccessful start are a DNS record that does not point to the Docker host, a missing TLS certificate, port &lt;code&gt;3478&lt;/code&gt; already being occupied, or an unreachable &lt;code&gt;NC_DOMAIN&lt;/code&gt; from inside the container.&lt;/p&gt;
&lt;h2 id=&quot;5-configure-nextcloud-talk&quot;&gt;5. Configure Nextcloud Talk&lt;/h2&gt;
&lt;p&gt;Open &lt;strong&gt;Administration settings → Talk&lt;/strong&gt; in Nextcloud and configure:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Setting&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;High-performance backend URL&lt;/td&gt;&lt;td&gt;&lt;code&gt;https://talk.example.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Shared secret&lt;/td&gt;&lt;td&gt;The value of &lt;code&gt;SIGNALING_SECRET&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TURN mode&lt;/td&gt;&lt;td&gt;&lt;code&gt;turn: only&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TURN server&lt;/td&gt;&lt;td&gt;&lt;code&gt;talk.example.com:3478&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TURN secret&lt;/td&gt;&lt;td&gt;The value of &lt;code&gt;TURN_SECRET&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Protocols&lt;/td&gt;&lt;td&gt;UDP and TCP&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Save the settings and wait for the connection check to finish successfully.&lt;/p&gt;
&lt;h3 id=&quot;5-1-configure-it-using-occ-optional&quot;&gt;5.1. Configure it using &lt;code&gt;occ&lt;/code&gt; (optional)&lt;/h3&gt;
&lt;p&gt;The same configuration can be added from the Nextcloud container. Replace the placeholders before running the commands.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add the signaling endpoint and validate its TLS certificate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; occ talk:signaling:add&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --verify \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  https://talk.example.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  REPLACE_WITH_YOUR_SIGNALING_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add the integrated TURN service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; occ talk:turn:add&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  turn&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  talk.example.com:3478&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  udp,tcp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --secret=REPLACE_WITH_YOUR_TURN_SECRET&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;List configured endpoints with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; occ talk:signaling:list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; occ talk:turn:list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            MIGRATION FROM ANOTHER HPB
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Run the new backend alongside the old one first. Verify the new URL, configure it in Nextcloud, make a real test call from two different networks, and only then remove the old signaling entry and containers. Keep the old Compose directory until the migration has been verified.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;6-test-a-real-call&quot;&gt;6. Test a real call&lt;/h2&gt;
&lt;p&gt;The welcome endpoint proves that Traefik can reach the signaling service, but it does not prove that media relay works. Create a Talk room and test a video call:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Join from two separate devices or networks.&lt;/li&gt;
&lt;li&gt;Test microphone, camera, screen sharing, and reconnecting after a network change.&lt;/li&gt;
&lt;li&gt;Repeat the test from a mobile connection or a restrictive network to confirm TURN fallback.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;During a test call, monitor the container:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;7-maintenance-and-updates&quot;&gt;7. Maintenance and updates&lt;/h2&gt;
&lt;p&gt;The image is intentionally pre-built, so normal updates do not require rebuilding Signaling, Janus, or NATS from source.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker image prune&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before updating, back up the project directory, especially &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -czf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-aio-talk-backup-&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.tar.gz&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  nextcloud-aio-talk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Review release notes after updates and repeat the signaling endpoint and real-call checks. Do not use a blind &lt;code&gt;docker image prune -a&lt;/code&gt; on a production host, as it may remove images used for rollback.&lt;/p&gt;
&lt;h2 id=&quot;8-running-multiple-independent-nextcloud-instances&quot;&gt;8. Running multiple independent Nextcloud instances&lt;/h2&gt;
&lt;p&gt;Each standalone AIO Talk container has exactly one &lt;code&gt;NC_DOMAIN&lt;/code&gt; and one &lt;code&gt;SIGNALING_SECRET&lt;/code&gt;. For two separate Nextcloud instances, use two isolated deployments.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Item&lt;/th&gt;&lt;th&gt;First instance&lt;/th&gt;&lt;th&gt;Second instance&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Project directory&lt;/td&gt;&lt;td&gt;&lt;code&gt;/opt/containers/nextcloud-aio-talk-one&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;/opt/containers/nextcloud-aio-talk-two&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Signaling hostname&lt;/td&gt;&lt;td&gt;&lt;code&gt;talk-one.example.com&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;talk-two.example.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Talk / TURN port&lt;/td&gt;&lt;td&gt;&lt;code&gt;3478&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;3479&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Container name&lt;/td&gt;&lt;td&gt;&lt;code&gt;nextcloud-aio-talk-one&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;nextcloud-aio-talk-two&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NC_DOMAIN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;cloud-one.example.com&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;cloud-two.example.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Secrets&lt;/td&gt;&lt;td&gt;Three unique secrets&lt;/td&gt;&lt;td&gt;Three different unique secrets&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;For the second deployment, copy the project directory, change every identifier shown above, and publish its configured &lt;code&gt;TALK_PORT&lt;/code&gt; over TCP and UDP. Each Nextcloud instance then receives only its own signaling URL and its own Signaling and TURN secrets.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            NO SHARED SECRETS ACROSS TENANTS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Do not share &lt;code&gt;SIGNALING_SECRET&lt;/code&gt;, &lt;code&gt;TURN_SECRET&lt;/code&gt;, or &lt;code&gt;INTERNAL_SECRET&lt;/code&gt; between independent Nextcloud instances. Separation makes future rotations, troubleshooting, and decommissioning safer.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;9-recording-backend-scope&quot;&gt;9. Recording backend scope&lt;/h2&gt;
&lt;p&gt;The AIO Talk image provides signaling, media handling, and TURN. It does &lt;strong&gt;not&lt;/strong&gt; include the Talk Recording Backend. Recording is deployed as a separate service and should be planned, secured, and backed up independently.&lt;/p&gt;
&lt;p&gt;Continue with &lt;strong&gt;&lt;a href=&quot;../nextcloud-talk-aio-recording-standalone/&quot;&gt;Deploying the Nextcloud Talk AIO Recording Backend as a Standalone Container&lt;/a&gt;&lt;/strong&gt; when you need recordings.&lt;/p&gt;
&lt;h2 id=&quot;10-troubleshooting&quot;&gt;10. Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;the-high-performance-backend-check-fails&quot;&gt;The High-Performance Backend check fails&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Verify DNS and TLS with &lt;code&gt;curl https://talk.example.com/api/v1/welcome&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm that &lt;code&gt;SIGNALING_SECRET&lt;/code&gt; matches exactly in &lt;code&gt;.env&lt;/code&gt; and in Nextcloud Talk settings.&lt;/li&gt;
&lt;li&gt;Confirm that &lt;code&gt;NC_DOMAIN&lt;/code&gt; is the existing Nextcloud hostname without a scheme or path.&lt;/li&gt;
&lt;li&gt;Inspect &lt;code&gt;sudo docker logs nextcloud-aio-talk&lt;/code&gt; for certificate or connectivity errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;calls-connect-but-media-does-not-work&quot;&gt;Calls connect but media does not work&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Confirm that &lt;code&gt;3478/tcp&lt;/code&gt; and &lt;code&gt;3478/udp&lt;/code&gt; are reachable from the internet.&lt;/li&gt;
&lt;li&gt;Confirm the TURN hostname, port, secret, and UDP/TCP protocols in Talk settings.&lt;/li&gt;
&lt;li&gt;Test from an external mobile network, not only from the same LAN.&lt;/li&gt;
&lt;li&gt;Check provider firewalls and router port forwarding in addition to UFW.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-container-cannot-contact-nextcloud&quot;&gt;The container cannot contact Nextcloud&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ensure the Docker host can resolve and reach &lt;code&gt;https://cloud.example.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use a publicly trusted certificate or mount an additional trusted CA certificate when using a private PKI.&lt;/li&gt;
&lt;li&gt;Do not set &lt;code&gt;SKIP_CERT_VERIFY=true&lt;/code&gt; as a permanent workaround.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The standalone AIO Talk image is a practical way to use the maintained, pre-built Talk backend without replacing an existing Nextcloud deployment with full Nextcloud AIO. Keep each Nextcloud instance isolated, protect the secrets, verify TURN with real calls, and retain a tested rollback path during migration.&lt;/p&gt;
&lt;p&gt;For the upstream quick-install procedure and current image details, see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://nextcloud-talk.readthedocs.io/en/latest/quick-install/&quot;&gt;official Nextcloud Talk documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;related-tutorials&quot;&gt;Related tutorials&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../nextcloud-talk-high-performance-backend/&quot;&gt;Deploying the classic Nextcloud Talk High-Performance Backend with Docker&lt;/a&gt;&lt;/strong&gt; — retained as an archive and migration reference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../nextcloud-talk-aio-recording-standalone/&quot;&gt;Deploying the Nextcloud Talk AIO Recording Backend as a Standalone Container&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Running Hermes Agent Across Multiple Devices with Forgejo and Matrix</title>
          <pubDate>Sat, 05 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/hermes-agent-multi-device-architecture/</link>
          <guid>https://criticalbasics.xyz/posts/hermes-agent-multi-device-architecture/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/hermes-agent-multi-device-architecture/">&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://hermes-agent.nousresearch.com/&quot;&gt;Hermes Agent&lt;/a&gt;&lt;/strong&gt; by Nous Research is a self-hosted AI agent that runs shell, file, and development tools on the machine where its profile is active. That makes a multi-device installation a fleet of independent runtimes, not one database replicated between several computers.&lt;/p&gt;
&lt;p&gt;The reference setup in this guide installs the same logical role profiles on a desktop, one or more laptops, and optionally an always-on private VM. A private Forgejo repository distributes reviewed role definitions, skills, prompts, knowledge, and handoffs. Every endpoint keeps its own sessions, memories, credentials, Matrix encryption store, service state, and search index.&lt;/p&gt;
&lt;p&gt;The examples use Hermes Agent 0.21.0. Before deploying the design, check the release notes, pin the version you have tested, and use that same revision on every endpoint.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-05&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Authentication Update:&lt;/strong&gt; Documented independent and centrally managed provider-login models without placing credentials in Forgejo.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-09-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Hermes 0.21 Update:&lt;/strong&gt; Added the fleet-relevant Hermes 0.21 features, clarified the boundary between Forgejo synchronization and runtime deployment, generalized the examples, and added bounded deterministic snapshots for faster scheduled briefings.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-08-31&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Fleet Update:&lt;/strong&gt; Replaced the workstation/server model with role-based profiles, documented guarded automatic synchronization, gateway ownership, and one provider login per host.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-18&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Always-on Update:&lt;/strong&gt; Added private-home deployment, sizing considerations, controlled host migration, and local mail/PIM mirror guidance.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Security Update:&lt;/strong&gt; Corrected backup scope and clarified full-trust operation, approvals, Matrix recovery, and off-host protection.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-16&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Fleet Update:&lt;/strong&gt; Added profile-scoped gateways, machine-aware Matrix identities, session boundaries, and the profile-versus-sandbox distinction.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-16&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Added the multi-instance Hermes design with Forgejo, profile distributions, QMD knowledge, handoffs, Matrix hardening, and backups.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-reference-architecture&quot;&gt;1. Reference Architecture&lt;/h2&gt;
&lt;p&gt;The fleet standardizes &lt;strong&gt;roles and reviewed capabilities&lt;/strong&gt; across endpoints. It does not replicate a live Hermes home.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                Private Forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    ┌─────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    │ hermes-shared                   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    │ distributions/{roles}/         │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    │ skills/{profiles,shared}/       │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    │ knowledge/  handoffs/  scripts/ │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    └───────────────┬─────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                    │ guarded Git sync&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  ┌─────────────────┼─────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  │                 │                 │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             Desktop          Laptop(s)        Private VM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          active/standby   active/standby      always-on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  │                 │                 │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          main · personal · business · specialist · ops&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          same roles and policy; independent local runtime state&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following five roles are one useful example. Rename, remove, or add roles to match your own trust boundaries:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Profile&lt;/th&gt;&lt;th&gt;Surface&lt;/th&gt;&lt;th&gt;Responsibility&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;main&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Interactive&lt;/td&gt;&lt;td&gt;Global Chief of Staff. Correlates reviewed cross-domain signals, prepares briefings, and delegates mutations to the owning role.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;personal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Interactive&lt;/td&gt;&lt;td&gt;Private mail, calendars, contacts, tasks, notes, and personal files.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;business&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Interactive&lt;/td&gt;&lt;td&gt;Single conversational entry point for business work and customers; delegates specialist tasks where needed.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;specialist&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Internal worker&lt;/td&gt;&lt;td&gt;Isolated customer or domain-specific files, connectors, and memory.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ops&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Internal worker&lt;/td&gt;&lt;td&gt;Infrastructure diagnosis and execution without standing mail, cloud-file, Paperless, or customer-data authority.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;An always-on private VM can host the primary gateways and scheduled work. Desktop and laptop nodes may run additional identities or remain disabled as prepared fallbacks. Give each Matrix identity exactly one active owner; never start a copied identity or encryption store concurrently on two hosts. Internal workers such as &lt;code&gt;specialist&lt;/code&gt; and &lt;code&gt;ops&lt;/code&gt; do not need a chat gateway unless they have a genuine user-facing delivery path.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccccff&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            📝 
            A PUBLIC SERVICE HOST IS NOT AUTOMATICALLY A FLEET NODE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;A public mail or web server can run unrelated automation without joining the fleet. Install role profiles there only when they genuinely need to act on that host. Keeping an old, stopped Hermes installation on such a server does not make it an active fleet endpoint.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Matrix gateways establish outbound connections to the homeserver. A Matrix-only endpoint therefore needs no public inbound port. A private LAN VM administered over VPN is a good default for personal mail, calendars, contacts, and documents. A public VPS remains useful when the agent must directly administer services on that VPS or remain available during a home outage.&lt;/p&gt;
&lt;h2 id=&quot;2-shared-and-local-boundaries&quot;&gt;2. Shared and Local Boundaries&lt;/h2&gt;
&lt;p&gt;Share through Forgejo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reviewed profile distributions and role-specific &lt;code&gt;SOUL.md&lt;/code&gt; files,&lt;/li&gt;
&lt;li&gt;reviewed shared and profile-specific skills,&lt;/li&gt;
&lt;li&gt;device-independent Markdown knowledge,&lt;/li&gt;
&lt;li&gt;compact project handoffs,&lt;/li&gt;
&lt;li&gt;reviewed cron prompts, policy files, deployment scripts, and version metadata.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keep endpoint-local:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;state.db&lt;/code&gt;, WAL files, sessions, and memories,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;auth.json&lt;/code&gt;, API keys, OAuth tokens, and password-store data,&lt;/li&gt;
&lt;li&gt;Matrix access tokens, device IDs, recovery material, and E2EE stores,&lt;/li&gt;
&lt;li&gt;Maildir, CalDAV/CardDAV mirrors, and synchronization journals,&lt;/li&gt;
&lt;li&gt;logs, caches, QMD indexes, gateway state, and backups.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            NEVER REPLICATE LIVE RUNTIME STATE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;SQLite WAL mode supports concurrent access on one machine; it is not a conflict-free multi-master database. Do not synchronize Hermes databases, Matrix crypto stores, Maildir state, or cloud-sync journals through Git, Syncthing, or Nextcloud. Each active instance owns its local state exclusively.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;3-prerequisites-and-version-discipline&quot;&gt;3. Prerequisites and Version Discipline&lt;/h2&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a private &lt;strong&gt;&lt;a href=&quot;../forgejo/&quot;&gt;Forgejo&lt;/a&gt;&lt;/strong&gt; repository reachable from every endpoint,&lt;/li&gt;
&lt;li&gt;Hermes Agent installed at the same reviewed version on every fleet node,&lt;/li&gt;
&lt;li&gt;Git, &lt;code&gt;flock&lt;/code&gt; (usually provided by &lt;code&gt;util-linux&lt;/code&gt;), and user-level systemd services on Linux endpoints,&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;&lt;a href=&quot;../matrix-synapse-server/&quot;&gt;Matrix Synapse&lt;/a&gt;&lt;/strong&gt; homeserver for remote chat,&lt;/li&gt;
&lt;li&gt;Node.js &lt;code&gt;&amp;gt;= 22&lt;/code&gt; and QMD when local hybrid knowledge search is enabled.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide was tested with:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;Version&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Hermes Agent&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/NousResearch/hermes-agent/releases/tag/v2026.8.31&quot;&gt;&lt;code&gt;0.21.0&lt;/code&gt; (&lt;code&gt;v2026.8.31&lt;/code&gt;)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Example profile distributions&lt;/td&gt;&lt;td&gt;&lt;code&gt;1.0.0&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;QMD&lt;/td&gt;&lt;td&gt;&lt;code&gt;2.5.3&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Node.js for QMD&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;gt;= 22&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Use these as known-good reference versions, not as an instruction to ignore newer releases. Pin the Hermes release you have tested, record it in &lt;code&gt;VERSIONS.md&lt;/code&gt;, and deploy the same revision to every endpoint. If you carry local patches, record their revision separately from the upstream version.&lt;/p&gt;
&lt;h3 id=&quot;hermes-0-21-features-relevant-to-a-fleet&quot;&gt;Hermes 0.21 Features Relevant to a Fleet&lt;/h3&gt;
&lt;p&gt;Hermes 0.21 introduced several facilities worth considering in a multi-device design:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;built-in Bot Mode for persistent autonomous operation,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hermes peer&lt;/code&gt; for direct agent-to-agent collaboration,&lt;/li&gt;
&lt;li&gt;cron continuity through memory and prior-run context,&lt;/li&gt;
&lt;li&gt;live steering of running subagents,&lt;/li&gt;
&lt;li&gt;an MCP command center and a gateway control socket,&lt;/li&gt;
&lt;li&gt;selective multiplex-profile serving,&lt;/li&gt;
&lt;li&gt;write approval for protected agent-instruction files,&lt;/li&gt;
&lt;li&gt;additional model providers and security hardening.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are optional building blocks, not a reason to blur endpoint boundaries. Enable Bot Mode, peer links, or multiplexing only after defining their identity, trust, lifecycle, and failure behavior.&lt;/p&gt;
&lt;h2 id=&quot;4-build-the-shared-repository&quot;&gt;4. Build the Shared Repository&lt;/h2&gt;
&lt;p&gt;The active part of &lt;code&gt;hermes-shared&lt;/code&gt; has this shape:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hermes-shared/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── VERSIONS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── SOUL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── USER.shared.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cron/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── prompts/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── distributions/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── main/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── personal/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── business/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── specialist/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── ops/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── skills/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── profiles/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── main/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── personal/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── business/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── specialist/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   └── ops/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── shared/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── knowledge/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── projects/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── handoffs/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── scripts/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── systemd/user/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The repository &lt;code&gt;.gitignore&lt;/code&gt; and server-side protection must exclude at least:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;auth.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*.key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*.pem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;state.db*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;memories/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sessions/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;logs/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cache/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pending/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;platforms/matrix/store/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;matrix/store/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*.tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*.swp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clone the repository on each endpoint:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone git@git.example.com:user/hermes-shared.git ~/hermes-shared&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;5-profile-distributions-and-capability-policy&quot;&gt;5. Profile Distributions and Capability Policy&lt;/h2&gt;
&lt;p&gt;Hermes &lt;strong&gt;profile distributions&lt;/strong&gt; package reviewed agent-owned files behind a &lt;code&gt;distribution.yaml&lt;/code&gt; manifest. They deliberately exclude credentials, memories, sessions, and live state.&lt;/p&gt;
&lt;p&gt;Each active distribution contains only the stable role payload:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;distributions/main/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── distribution.yaml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── SOUL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── config.yaml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── mcp.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The role-specific skills live outside the distribution root under &lt;code&gt;skills/profiles/&amp;lt;profile&amp;gt;/&lt;/code&gt; and are loaded through &lt;code&gt;skills.external_dirs&lt;/code&gt;. Runtime cron state is also endpoint-owned. This prevents a distribution update from deleting or replacing local skill and scheduler state.&lt;/p&gt;
&lt;p&gt;A manifest starts with the role name and version:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;version&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1.0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Global cross-domain coordinator and Chief of Staff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;hermes_requires&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;gt;=0.21.0&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Profiles separate Hermes configuration and state, but they are &lt;strong&gt;not&lt;/strong&gt; an operating-system sandbox. With &lt;code&gt;terminal.backend: local&lt;/code&gt; and &lt;code&gt;terminal.home_mode: real&lt;/code&gt;, commands run with the permissions and home directory of the service user. Use this mode only when that level of host access is intentional.&lt;/p&gt;
&lt;p&gt;The declarative fleet capability policy is therefore important:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;all profiles use &lt;code&gt;approvals.mode: smart&lt;/code&gt; and &lt;code&gt;approvals.cron_mode: deny&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt; and &lt;code&gt;business&lt;/code&gt; receive orchestration capabilities,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;personal&lt;/code&gt; and &lt;code&gt;specialist&lt;/code&gt; receive only their required domain integrations,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ops&lt;/code&gt; uses an explicit infrastructure-tool allowlist and no standing customer, mail, search, or creative-suite connector,&lt;/li&gt;
&lt;li&gt;each role loads only its reviewed external skill directories.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hard isolation still requires separate Unix users, filesystem ACLs, restricted SSH credentials, or a correctly configured sandbox/container.&lt;/p&gt;
&lt;h2 id=&quot;6-install-and-update-the-role-profiles&quot;&gt;6. Install and Update the Role Profiles&lt;/h2&gt;
&lt;p&gt;Because the distributions are subdirectories of one repository, install them from their local paths on the first endpoint:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/hermes-shared&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pull&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --ff-only --prune&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; profile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main personal business specialist ops&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; profile install &amp;quot;&lt;/span&gt;&lt;span&gt;$PWD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/distributions/&lt;/span&gt;&lt;span&gt;$profile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --alias --yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On later updates, pull the reviewed repository and update each installed profile by name:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/hermes-shared&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pull&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --ff-only --prune&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; profile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main personal business specialist ops&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; profile update &amp;quot;&lt;/span&gt;&lt;span&gt;$profile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;hermes profile update&lt;/code&gt; reloads distribution-owned files from the source recorded during installation. It preserves memories, sessions, authentication, &lt;code&gt;.env&lt;/code&gt;, and the existing &lt;code&gt;config.yaml&lt;/code&gt; unless you explicitly pass &lt;code&gt;--force-config&lt;/code&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            CONFIG.YAML IS LOCAL ON EXISTING PROFILES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;&lt;code&gt;hermes profile update &amp;lt;name&amp;gt;&lt;/code&gt; preserves an existing local &lt;code&gt;config.yaml&lt;/code&gt; by default. Use &lt;code&gt;--force-config&lt;/code&gt; only when you intentionally want the distribution’s config to replace endpoint-specific settings. If you use a fleet helper, have it apply only the policy you have explicitly declared and reviewed.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;USER.shared.md&lt;/code&gt; is curated source material, not an automatically loaded Hermes memory file. Stable cross-device rules belong in &lt;code&gt;SOUL.md&lt;/code&gt;. If a role needs a local user-memory seed, copy it deliberately into that profile once; do not symlink it into a writable Hermes memory path.&lt;/p&gt;
&lt;h2 id=&quot;7-provider-authentication-ownership&quot;&gt;7. Provider Authentication Ownership&lt;/h2&gt;
&lt;p&gt;Hermes 0.21 lets a named profile fall back to the global provider store at &lt;code&gt;~/.hermes/auth.json&lt;/code&gt; when that profile has no credential for the provider. Several profiles on one host therefore do &lt;strong&gt;not&lt;/strong&gt; need separate provider logins.&lt;/p&gt;
&lt;p&gt;Authenticate once without &lt;code&gt;--profile&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; auth add openai-codex&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --type&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; oauth&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --no-browser&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then verify resolution from the roles:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; profile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main personal business specialist ops&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  hermes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$profile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; auth status openai-codex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The per-host invariant is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one authoritative &lt;code&gt;openai-codex&lt;/code&gt; entry in the host-global auth store,&lt;/li&gt;
&lt;li&gt;no duplicate &lt;code&gt;openai-codex&lt;/code&gt; entry in profile-local &lt;code&gt;auth.json&lt;/code&gt; files,&lt;/li&gt;
&lt;li&gt;profile-local credentials only where a role truly requires a different identity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A profile-local provider entry takes precedence over the global fallback. Keep it absent unless a role deliberately uses a different provider identity.&lt;/p&gt;
&lt;h3 id=&quot;choose-the-cross-host-model-deliberately&quot;&gt;Choose the Cross-Host Model Deliberately&lt;/h3&gt;
&lt;p&gt;There are two valid operational models. In an &lt;strong&gt;independent-host&lt;/strong&gt; fleet, every active host completes its own provider login. In a &lt;strong&gt;centrally managed&lt;/strong&gt; fleet, one selected source host owns the interactive provider login and a reviewed local synchronizer distributes that chosen account to enrolled private hosts.&lt;/p&gt;
&lt;p&gt;The central model removes repeated browser logins, but it is credential distribution and must be designed as such. Keep the following boundary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Forgejo carries the reviewed synchronizer, policy, and status format—never &lt;code&gt;auth.json&lt;/code&gt;, tokens, or backups.&lt;/li&gt;
&lt;li&gt;Transfer the credential only over a dedicated encrypted host-to-host channel with a key restricted to the exact read operation it needs.&lt;/li&gt;
&lt;li&gt;Store an atomic local backup before replacing a host credential, record only a short one-way account fingerprint in the status file, and restart affected gateways in a controlled way.&lt;/li&gt;
&lt;li&gt;Stop the adoption when the source is unavailable or the received data is malformed; it must never fall back to a token in Git, a log, or a chat message.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The provider’s account terms, workforce policy, and token-rotation behavior determine whether this model is appropriate. Test the chosen model with a small inference and a gateway restart before enabling it for scheduled work.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            NEVER PUT PROVIDER CREDENTIALS IN FORGEJO
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Whether the fleet uses independent or centrally managed logins, Git remains a transport for reviewed code and knowledge only. Do not commit or publish &lt;code&gt;auth.json&lt;/code&gt;, OAuth records, API keys, refresh-token backups, or account identifiers.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;8-guarded-forgejo-synchronization&quot;&gt;8. Guarded Forgejo Synchronization&lt;/h2&gt;
&lt;p&gt;A guarded fleet should not run a blind &lt;code&gt;git pull --rebase&lt;/code&gt; loop. The following pull-only synchronizer refuses dirty worktrees and divergent history, fast-forwards clean clones, and never executes files it has downloaded.&lt;/p&gt;
&lt;h3 id=&quot;8-1-create-the-synchronizer&quot;&gt;8.1. Create the Synchronizer&lt;/h3&gt;
&lt;p&gt;Create the local runtime directory:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d -m 0700&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/libexec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;~/.local/libexec/hermes-fleet-sync&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/libexec/hermes-fleet-sync&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;set -euo pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;repo=&amp;quot;${HERMES_FLEET_REPO:-$HOME/hermes-shared}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;lock_root=&amp;quot;${XDG_RUNTIME_DIR:-/tmp}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;exec 9&amp;gt;&amp;quot;$lock_root/hermes-fleet-sync-${UID}.lock&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;flock -n 9 || exit 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;if [[ ! -d &amp;quot;$repo/.git&amp;quot; ]]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  echo &amp;quot;Not a Git repository: $repo&amp;quot; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;if [[ -n &amp;quot;$(git -C &amp;quot;$repo&amp;quot; status --porcelain)&amp;quot; ]]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  echo &amp;quot;Refusing to sync a dirty worktree: $repo&amp;quot; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;export GIT_TERMINAL_PROMPT=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;git -C &amp;quot;$repo&amp;quot; fetch --prune origin main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;local_rev=&amp;quot;$(git -C &amp;quot;$repo&amp;quot; rev-parse HEAD)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;remote_rev=&amp;quot;$(git -C &amp;quot;$repo&amp;quot; rev-parse origin/main)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;base_rev=&amp;quot;$(git -C &amp;quot;$repo&amp;quot; merge-base HEAD origin/main)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;if [[ &amp;quot;$local_rev&amp;quot; == &amp;quot;$remote_rev&amp;quot; ]]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  echo &amp;quot;Already current: $local_rev&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;elif [[ &amp;quot;$local_rev&amp;quot; == &amp;quot;$base_rev&amp;quot; ]]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  git -C &amp;quot;$repo&amp;quot; merge --ff-only origin/main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  if command -v qmd &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;amp;&amp;amp; qmd collection list 2&amp;gt;/dev/null | grep -q &amp;#39;^hermes-shared &amp;#39;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    qmd update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    qmd embed -c hermes-shared --max-docs-per-batch 32 --max-batch-mb 16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;elif [[ &amp;quot;$remote_rev&amp;quot; == &amp;quot;$base_rev&amp;quot; ]]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  echo &amp;quot;Local commits exist; refusing to push automatically.&amp;quot; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  echo &amp;quot;Local and remote history diverged; manual review required.&amp;quot; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0700&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/libexec/hermes-fleet-sync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script deliberately does not push. Publication is a separate, explicit workflow, so a forgotten local commit cannot silently propagate to every device.&lt;/p&gt;
&lt;h3 id=&quot;8-2-create-the-systemd-user-units&quot;&gt;8.2. Create the systemd User Units&lt;/h3&gt;
&lt;p&gt;Create the user-unit directory:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d -m 0700&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/systemd/user&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;~/.config/systemd/user/hermes-fleet-sync.service&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Unit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Description&lt;/span&gt;&lt;span&gt;=Fast-forward the reviewed Hermes fleet repository&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;After&lt;/span&gt;&lt;span&gt;=network-online.target&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Wants&lt;/span&gt;&lt;span&gt;=network-online.target&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Service]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Type&lt;/span&gt;&lt;span&gt;=oneshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Environment&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;HERMES_FLEET_REPO&lt;/span&gt;&lt;span&gt;=%h/hermes-shared&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ExecStart&lt;/span&gt;&lt;span&gt;=%h/.local/libexec/hermes-fleet-sync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;~/.config/systemd/user/hermes-fleet-sync.timer&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Unit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Description&lt;/span&gt;&lt;span&gt;=Synchronize the Hermes fleet repository periodically&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Timer]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;OnBootSec&lt;/span&gt;&lt;span&gt;=2min&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;OnUnitActiveSec&lt;/span&gt;&lt;span&gt;=10min&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RandomizedDelaySec&lt;/span&gt;&lt;span&gt;=2min&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Persistent&lt;/span&gt;&lt;span&gt;=true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Install]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;WantedBy&lt;/span&gt;&lt;span&gt;=timers.target&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enable the timer and run the first synchronization:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; enable&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --now&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hermes-fleet-sync.timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; start hermes-fleet-sync.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The synchronizer now:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;takes a per-host &lt;code&gt;flock&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;refuses to operate on a dirty worktree,&lt;/li&gt;
&lt;li&gt;fetches without interactive credential prompts,&lt;/li&gt;
&lt;li&gt;fast-forwards only when the host is behind,&lt;/li&gt;
&lt;li&gt;stops when local commits or divergent history require review,&lt;/li&gt;
&lt;li&gt;refreshes QMD after a successful fast-forward.&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            SYNCHRONIZATION IS NOT RUNTIME DEPLOYMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The timer fast-forwards the reviewed repository but does &lt;strong&gt;not&lt;/strong&gt; run newly downloaded installers, profile updates, or scripts. This prevents a pushed Forgejo commit from becoming immediate code execution on every fleet host. Apply Hermes and profile upgrades explicitly, or design and audit a separately installed, version-pinned updater before granting that authority.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Inspect it with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status hermes-fleet-sync.timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hermes-fleet-sync.service&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n 100&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;8-3-publish-reviewed-changes-explicitly&quot;&gt;8.3. Publish Reviewed Changes Explicitly&lt;/h3&gt;
&lt;p&gt;Inspect and commit only the intended file. Do not use a blanket &lt;code&gt;git add .&lt;/code&gt; in a repository that may contain generated or sensitive data:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/hermes-shared&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pull&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --ff-only --prune&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --short&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; diff&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; handoffs/current/example.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; handoffs/current/example.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; diff&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --cached --check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Update project handoff&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add a secret scanner and protected branches on Forgejo when several people or agents can publish. If the remote advances before the push, stop and review the histories instead of rebasing an unattended automation branch.&lt;/p&gt;
&lt;h2 id=&quot;9-knowledge-search-and-handoffs&quot;&gt;9. Knowledge Search and Handoffs&lt;/h2&gt;
&lt;p&gt;Hermes memories are small, profile-local working context. Durable knowledge belongs in Markdown under &lt;code&gt;knowledge/&lt;/code&gt;, &lt;code&gt;projects/&lt;/code&gt;, and &lt;code&gt;handoffs/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;QMD provides local keyword, vector, and reranked search:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; @tobilu/qmd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;qmd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; collection add ~/hermes-shared&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hermes-shared&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;qmd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;qmd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; embed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hermes-shared&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --max-docs-per-batch 32 --max-batch-mb 16&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated index stays under &lt;code&gt;~/.cache/qmd/&lt;/code&gt;; it is reproducible and never synchronized. The sync timer can update and embed it after the Git revision changes.&lt;/p&gt;
&lt;p&gt;To continue work on another device, maintain a compact topic handoff such as:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;handoffs/current/hermes-architecture.md&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Record the goal, verified current state, decisions, changed files, open risks, and the next concrete action. On the new endpoint, read the handoff and re-read live external state before any mutation. A handoff transfers intent and evidence; it does not pretend to resume the other endpoint’s live process.&lt;/p&gt;
&lt;p&gt;Hermes can also export sessions for deliberate archival or review, but exports must be redacted and inspected before publication. They are not a substitute for a concise handoff.&lt;/p&gt;
&lt;h2 id=&quot;10-matrix-gateways-and-e2ee&quot;&gt;10. Matrix Gateways and E2EE&lt;/h2&gt;
&lt;p&gt;Each profile has independent messaging configuration, session namespace, and Matrix crypto state. Separate profile gateways are a straightforward default because their failures and restarts are easy to reason about.&lt;/p&gt;
&lt;p&gt;Install and manage a gateway with the profile explicitly selected:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main gateway install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main gateway start&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main gateway status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gateway list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use a host- and profile-specific Matrix device ID, for example:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;dotenv&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;MATRIX_ALLOWED_USERS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;@you:matrix.example.org&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;MATRIX_ALLOWED_ROOMS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;!roomid:matrix.example.org&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;MATRIX_DEVICE_ID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;NODE1_MAIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;MATRIX_E2EE_MODE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;required&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;MATRIX_APPROVAL_REQUIRE_SENDER&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Never reuse one Matrix device/E2EE store on two hosts. A controlled gateway migration is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;stop and disable the old profile gateway,&lt;/li&gt;
&lt;li&gt;verify that no old process is running,&lt;/li&gt;
&lt;li&gt;copy the profile’s Matrix credentials and crypto store through an encrypted channel,&lt;/li&gt;
&lt;li&gt;start the new gateway and test encrypted send/receive,&lt;/li&gt;
&lt;li&gt;leave the old copy disabled as a rollback snapshot.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Provider auth and Matrix identity are separate concerns. A model credential may use the host-global fallback described above; every Matrix adapter still needs its own correctly scoped account/token and exclusive crypto store.&lt;/p&gt;
&lt;p&gt;Hermes also supports an opt-in multiplexing gateway through &lt;code&gt;gateway.multiplex_profiles&lt;/code&gt;. It can be useful for many low-traffic profiles, but it changes lifecycle, listener, route, and failure behavior. Prefer independent gateway processes until you have a specific reason and test plan for multiplexing.&lt;/p&gt;
&lt;p&gt;CLI and Matrix sessions share the selected profile’s home and database, but not a live response channel. Matrix-started work replies to Matrix; a CLI background task does not automatically report there. Use an explicit handoff or delivery workflow when the result must appear in Matrix.&lt;/p&gt;
&lt;h2 id=&quot;11-mail-calendar-and-file-mirrors&quot;&gt;11. Mail, Calendar, and File Mirrors&lt;/h2&gt;
&lt;p&gt;Hermes can read existing local mirrors without receiving the remote account password itself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NeoMutt reads Maildir,&lt;/li&gt;
&lt;li&gt;Notmuch indexes mail,&lt;/li&gt;
&lt;li&gt;Khal, Khard, and Todoman read local vdirs,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mbsync&lt;/code&gt; and &lt;code&gt;vdirsyncer&lt;/code&gt; own remote synchronization credentials.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For unattended mail collection, prefer a pull-oriented command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mbsync&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --pull --create-near --expunge-near&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; account@example.org&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;notmuch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; new&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keep actual sending behind a task-specific approval. A read/triage workflow does not require SMTP. Mirror only the cloud subtrees and collections that a role needs, and keep each endpoint’s synchronization journal local.&lt;/p&gt;
&lt;h3 id=&quot;11-1-use-bounded-domain-snapshots-for-scheduled-briefings&quot;&gt;11.1. Use Bounded Domain Snapshots for Scheduled Briefings&lt;/h3&gt;
&lt;p&gt;A scheduled agent that repeatedly discovers commands, searches every source,
reads large tool results, and decides what to fetch next spends time and tokens
on data collection before it starts the actual analysis. A better pattern for
stable recurring work is:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mail ───────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;calendar ───┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tasks ──────┤  deterministic, read-only collectors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;projects ───┤              │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;documents ──┤              ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;weather ────┘      one bounded JSON snapshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                            │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                            ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  one cross-domain analysis&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run independent read-only collectors concurrently, but keep the reasoning in
one model call when relationships between domains matter. Splitting mail,
calendar, and project analysis among isolated agents can hide a conflict that
only becomes visible when the evidence is combined.&lt;/p&gt;
&lt;p&gt;Every source envelope should include at least:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;generation time and source freshness,&lt;/li&gt;
&lt;li&gt;collector duration and success or error state,&lt;/li&gt;
&lt;li&gt;total records found, included, and omitted,&lt;/li&gt;
&lt;li&gt;the limit or reason responsible for an omission,&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;complete&lt;/code&gt; flag and a targeted read-only retrieval hint,&lt;/li&gt;
&lt;li&gt;an explicit warning that source fields are untrusted data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enforce a hard serialized-output budget, not merely a record count. A practical
starting point is a compact 25–40 KB snapshot, adjusted after measuring real
coverage. If the budget removes an item, record that removal in the envelope;
the model must never turn “omitted” into “does not exist.” Keep high-value
evidence first—for example, recent overdue and upcoming tasks before an old
backlog—and trim low-priority tails deterministically.&lt;/p&gt;
&lt;p&gt;The snapshot collector should not silently take ownership of synchronization.
Let dedicated timers update Maildir, Notmuch, and CalDAV/CardDAV mirrors. The
briefing collector reads their current state without changing seen state,
flags, folders, drafts, attachments, or remote objects. This keeps the fast
path reproducible and makes failures source-specific rather than losing the
whole report.&lt;/p&gt;
&lt;p&gt;An illustrative deployment reduced the collection phase to roughly five or six
seconds while producing a 30–39 KB combined snapshot. Its older end-to-end
briefings took several minutes, but those runs also included model inference,
graphics, speech synthesis, cloud verification, and message delivery, so the
numbers are not a like-for-like model benchmark. Record collection time,
inference usage, rendering time, and delivery time separately.&lt;/p&gt;
&lt;h2 id=&quot;12-security-model&quot;&gt;12. Security Model&lt;/h2&gt;
&lt;p&gt;Choose and document the trust model for each endpoint:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Restricted automation identity:&lt;/strong&gt; separate Unix user or sandbox, narrowly scoped paths and SSH identities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full-trust personal assistant:&lt;/strong&gt; the agent intentionally has the same files and administration capabilities as its owner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A Hermes profile alone implements neither boundary at OS level. &lt;code&gt;SOUL.md&lt;/code&gt;, model instructions, and &lt;code&gt;approvals.mode: smart&lt;/code&gt; reduce mistakes but are not containment against prompt injection.&lt;/p&gt;
&lt;p&gt;Treat mail, websites, documents, issues, repositories, and tool output as untrusted data. Require concrete authorization for the destination, payload, and purpose before sending mail, uploading files, pushing Git commits, publishing, buying, inviting users, changing cloud resources, or mutating another host.&lt;/p&gt;
&lt;p&gt;Audit the effective service identity:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n -l&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;stat -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;%A %U:%G %n&amp;#39; /var/run/docker.sock&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Passwordless sudo and access to a rootful Docker socket are both root-equivalent. If that authority is intentional, protect Matrix identities, model/tool supply chains, outbound-action policy, and recoverable backups accordingly.&lt;/p&gt;
&lt;h2 id=&quot;13-backups-and-recovery&quot;&gt;13. Backups and Recovery&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;hermes backup&lt;/code&gt; creates a machine-level archive of the Hermes root, including named profiles. Run it once per endpoint, not once per profile:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; backup&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --output&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /secure/staging/hermes-backup.zip&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The archive contains secrets and is not encrypted by Hermes. Encrypt it before it leaves the machine and store it off-host with deletion-resistant retention.&lt;/p&gt;
&lt;p&gt;A profile export has a different purpose:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; profile export main&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --output&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./main-profile.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It strips &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;auth.json&lt;/code&gt;, making it useful for a controlled profile transfer, but it is not complete disaster recovery. Quick snapshots are local rollback aids, not off-host backups.&lt;/p&gt;
&lt;p&gt;Back up separately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the Forgejo repository and server configuration,&lt;/li&gt;
&lt;li&gt;encrypted Matrix crypto stores, device IDs, and matching recovery material,&lt;/li&gt;
&lt;li&gt;external project and synchronization configuration,&lt;/li&gt;
&lt;li&gt;credentials stored outside the Hermes root.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Test an actual restore with the original runtime stopped. Never start the same restored database or E2EE store on two hosts.&lt;/p&gt;
&lt;h2 id=&quot;14-verification-checklist&quot;&gt;14. Verification Checklist&lt;/h2&gt;
&lt;p&gt;Before relying on the fleet, verify:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Every endpoint has the intended role profiles at the approved distribution versions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Obsolete or experimental distributions are not active.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
All active endpoints run the same reviewed Hermes upstream and patch revisions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Each profile has its own sessions, memories, SQLite state, Matrix state, and endpoint credentials.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
No runtime database, secret, OAuth record, E2EE store, Maildir, or sync journal is in Forgejo.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
One global model login serves the profiles on a host; duplicate profile-local entries do not shadow it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
The selected cross-host authentication model is documented, tested after gateway restart, and keeps credentials out of Forgejo.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
The intended gateway owners are documented; fallback units remain disabled until deliberately started, and no Matrix identity has two active owners.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Matrix allowlists, requester-bound approvals, stable device IDs, and &lt;code&gt;MATRIX_E2EE_MODE=required&lt;/code&gt; are set.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
The guarded sync timer is active and stops on a dirty tree or divergent history.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
QMD returns current results after a synchronized commit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
The coordinator only coordinates cross-domain writes; the owning Personal, Business, Specialist, or Ops role performs them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;approvals.mode: smart&lt;/code&gt; and &lt;code&gt;approvals.cron_mode: deny&lt;/code&gt; are explicit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Root-equivalent permissions and outbound-action paths were reviewed consciously.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
One encrypted off-host backup exists per endpoint and a restore was tested.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Useful read-only checks:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; profile list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hermes&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gateway list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/hermes-shared status&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --short --branch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status hermes-fleet-sync.timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hermes-fleet-sync.service&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;qmd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;15-updates-and-maintenance&quot;&gt;15. Updates and Maintenance&lt;/h2&gt;
&lt;p&gt;Roll out changes in this order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;update and test one endpoint,&lt;/li&gt;
&lt;li&gt;record the exact upstream, patch, distribution, QMD, and Node versions,&lt;/li&gt;
&lt;li&gt;fast-forward the clean repository clone on the other endpoints,&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;hermes profile update &amp;lt;name&amp;gt; --yes&lt;/code&gt; for each installed role,&lt;/li&gt;
&lt;li&gt;review and reinstall the local synchronizer if its implementation changed,&lt;/li&gt;
&lt;li&gt;compare &lt;code&gt;hermes --version&lt;/code&gt;, &lt;code&gt;hermes profile list&lt;/code&gt;, and the Git revision across endpoints,&lt;/li&gt;
&lt;li&gt;test provider auth, Matrix E2EE, role routing, and a QMD query,&lt;/li&gt;
&lt;li&gt;only then restore normal always-on gateway and cron operation.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do not treat a successful &lt;code&gt;git pull&lt;/code&gt; as deployment: downloaded scripts and distributions take effect only after the reviewed apply/install step.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The durable design is a consistent set of logical roles on every endpoint, with an optional always-on home, explicitly selected active gateways, and independent on-demand fallbacks. Forgejo synchronizes only reviewed, device-independent material; guarded automation refuses dirty or divergent histories; runtime state and credentials stay local.&lt;/p&gt;
&lt;p&gt;The key distinctions are simple: share roles, knowledge, and handoffs; do not share live databases, Matrix crypto state, or credentials through Git. A provider login can be independent per host or centrally managed through a separately reviewed private channel. Consolidate user-facing coordination while preserving role ownership and endpoint-level recovery.&lt;/p&gt;
&lt;a href=&quot;https://hermes-agent.nousresearch.com/docs/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;HERMES DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://hermes-agent.nousresearch.com/docs/user-guide/profiles&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🤖&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;PROFILES &amp; GATEWAYS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://hermes-agent.nousresearch.com/docs/user-guide/multi-profile-gateways&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🛰️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;MULTI-PROFILE GATEWAYS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://hermes-agent.nousresearch.com/docs/user-guide/profile-distributions&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;PROFILE DISTRIBUTIONS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://hermes-agent.nousresearch.com/docs/user-guide/sessions&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;💾&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;SESSIONS &amp; EXPORT&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://hermes-agent.nousresearch.com/docs/user-guide/messaging/matrix&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;💬&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;MATRIX INTEGRATION&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying GoToSocial with Traefik and Phanpy</title>
          <pubDate>Fri, 04 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/gotosocial/</link>
          <guid>https://criticalbasics.xyz/posts/gotosocial/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/gotosocial/">&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://gotosocial.org/&quot;&gt;GoToSocial&lt;/a&gt;&lt;/strong&gt; is a lightweight ActivityPub server for small Fediverse instances. It is especially attractive for single-user or small-group deployments where a full Mastodon stack would be unnecessarily heavy.&lt;/p&gt;
&lt;p&gt;This guide focuses on a fresh GoToSocial installation in an existing &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec Docker ecosystem&lt;/a&gt;&lt;/strong&gt;. GoToSocial runs as a normal Docker Compose stack on the shared &lt;code&gt;proxy&lt;/code&gt; network, Traefik handles public HTTPS, and &lt;strong&gt;Phanpy&lt;/strong&gt; is deployed as a separate static web client.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            FRESH INSTALL FIRST
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The main path below is a clean installation. If you are replacing an existing Mastodon account, use the optional migration section near the end after GoToSocial itself is already working.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-04&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Maintenance Update:&lt;/strong&gt; Updated the pinned GoToSocial image to 0.22.1 and added a safer SQLite-first update procedure with explicit version and HTTP checks.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Fresh GoToSocial install with SQLite, Traefik, Phanpy, and optional Mastodon account-move notes.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec stack&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A subdomain for GoToSocial, e.g. &lt;code&gt;gotosocial.your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A subdomain for Phanpy, e.g. &lt;code&gt;phanpy.your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;DNS &lt;code&gt;A&lt;/code&gt;/&lt;code&gt;AAAA&lt;/code&gt; records pointing both subdomains at your server.&lt;/li&gt;
&lt;li&gt;Docker and Docker Compose.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide assumes the Traefik external Docker network is named &lt;code&gt;proxy&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;2-gotosocial-directory&quot;&gt;2. GoToSocial Directory&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/gotosocial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/gotosocial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; data cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1000:1000 data cache&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example below runs the container as UID/GID &lt;code&gt;1000:1000&lt;/code&gt;. If your deployment uses another unprivileged user, adjust ownership and &lt;code&gt;user:&lt;/code&gt; accordingly.&lt;/p&gt;
&lt;h2 id=&quot;3-gotosocial-docker-compose&quot;&gt;3. GoToSocial Docker Compose&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/gotosocial/docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  gotosocial&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker.io/superseriousbusiness/gotosocial:0.22.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    container_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gotosocial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    user&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1000:1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_HOST&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gotosocial.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_DB_TYPE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sqlite&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_DB_ADDRESS&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /gotosocial/storage/sqlite.db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_LETSENCRYPT_ENABLED&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_TRUSTED_PROXIES&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 172.18.0.0/16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_WAZERO_COMPILATION_CACHE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /gotosocial/.cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_MEDIA_REMOTE_CACHE_DURATION&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;14 days&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GTS_STATUSES_CLEANUP_REMOTE_OLDER_THAN&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;30 days&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      GIN_MODE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      TZ&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Europe/Berlin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./data:/gotosocial/storage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./cache:/gotosocial/.cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.gotosocial.rule=Host(`gotosocial.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.gotosocial.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.gotosocial.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.gotosocial.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.gotosocial.loadbalancer.server.port=8080&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  proxy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Configuration notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GTS_LETSENCRYPT_ENABLED=false&lt;/code&gt;: Traefik handles public TLS.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GTS_TRUSTED_PROXIES&lt;/code&gt;: restrict this to your Docker proxy subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GTS_MEDIA_REMOTE_CACHE_DURATION&lt;/code&gt;: limits cached remote media growth.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GTS_STATUSES_CLEANUP_REMOTE_OLDER_THAN&lt;/code&gt;: cleans old remote statuses.&lt;/li&gt;
&lt;li&gt;SQLite is appropriate for a small personal instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Start the service:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gotosocial&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;4-create-the-first-account&quot;&gt;4. Create the First Account&lt;/h2&gt;
&lt;p&gt;Create the account from inside the container:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -it&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gotosocial&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  /gotosocial/gotosocial admin account create&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --username&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; yourusername&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --email&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; you@your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --password&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;REPLACE_WITH_A_STRONG_TEMPORARY_PASSWORD&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Promote it to admin:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -it&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gotosocial&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  /gotosocial/gotosocial admin account promote&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --username&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; yourusername&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Log in at:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://gotosocial.your-domain.com/settings&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Change the temporary password immediately.&lt;/p&gt;
&lt;h2 id=&quot;5-phanpy-web-client&quot;&gt;5. Phanpy Web Client&lt;/h2&gt;
&lt;p&gt;GoToSocial provides settings pages and API endpoints, but you usually want a full client for daily use. Phanpy works well as a static web client.&lt;/p&gt;
&lt;p&gt;Create the directory:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/phanpy/html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/phanpy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Download and verify the Phanpy release asset you want to run, then extract it into &lt;code&gt;html/&lt;/code&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            VERIFY RELEASE ASSETS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;When using prebuilt static client assets, verify the checksum from the release page before serving them publicly.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/phanpy/nginx.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;worker_processes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;user&lt;/span&gt;&lt;span&gt; www-data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;events&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    use&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; epoll&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    worker_connections&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 128&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;http&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    include&lt;/span&gt;&lt;span&gt; /etc/nginx/mime.types;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    default_type&lt;/span&gt;&lt;span&gt; application/octet-stream;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    sendfile&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; on&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    tcp_nopush&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; on&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    tcp_nodelay&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; on&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    keepalive_timeout&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 65&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    gzip&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; on&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    gzip_vary&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; on&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    gzip_proxied&lt;/span&gt;&lt;span&gt; any;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    gzip_comp_level&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 6&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    gzip_types&lt;/span&gt;&lt;span&gt; text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    server&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        listen&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 80&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        server_name&lt;/span&gt;&lt;span&gt; _;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        root&lt;/span&gt;&lt;span&gt; /usr/share/nginx/html;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        index&lt;/span&gt;&lt;span&gt; index.html;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        location ~*&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt; \.(?:css|js|mjs|png|jpg|jpeg|gif|svg|webp|avif|ico|woff2?)$ &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            try_files&lt;/span&gt;&lt;span&gt; $uri&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; =404&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            access_log&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; off&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            expires&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 30d&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            add_header&lt;/span&gt;&lt;span&gt; Cache-Control &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;public, immutable&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        location&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; / &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            try_files&lt;/span&gt;&lt;span&gt; $uri $uri/ /index.html;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            add_header&lt;/span&gt;&lt;span&gt; Cache-Control &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;no-cache&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/phanpy/docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  phanpy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nginx:1.27.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    container_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; phanpy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./html:/usr/share/nginx/html:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./nginx.conf:/etc/nginx/nginx.conf:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.phanpy.rule=Host(`phanpy.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.phanpy.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.phanpy.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.phanpy.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.phanpy.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  proxy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start it:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://phanpy.your-domain.com/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Choose your GoToSocial instance as the server when logging in.&lt;/p&gt;
&lt;h2 id=&quot;6-verification&quot;&gt;6. Verification&lt;/h2&gt;
&lt;p&gt;Check the public profile:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://gotosocial.your-domain.com/@yourusername&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check WebFinger:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;https://gotosocial.your-domain.com/.well-known/webfinger?resource=acct:yourusername@gotosocial.your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check logs:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/gotosocial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gotosocial&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify the Phanpy route:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://phanpy.your-domain.com/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, the fresh GoToSocial installation is ready. You can use Phanpy or any compatible Mastodon/ActivityPub client to log in.&lt;/p&gt;
&lt;h2 id=&quot;7-search-discovery-and-trending&quot;&gt;7. Search, Discovery, and Trending&lt;/h2&gt;
&lt;p&gt;A fresh GoToSocial instance only knows local accounts and remote objects it has already discovered. Global search is not a search engine over the entire Fediverse.&lt;/p&gt;
&lt;p&gt;To discover more content:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Follow accounts from known instances.&lt;/li&gt;
&lt;li&gt;Open remote profile URLs directly in your client.&lt;/li&gt;
&lt;li&gt;Follow hashtags.&lt;/li&gt;
&lt;li&gt;Interact with posts so your instance learns about those actors and threads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is normal for trending posts or broad search results to look empty at first.&lt;/p&gt;
&lt;h2 id=&quot;8-backups-and-updates&quot;&gt;8. Backups and Updates&lt;/h2&gt;
&lt;p&gt;Back up:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/gotosocial/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/gotosocial/docker-compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/phanpy/html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/phanpy/docker-compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/phanpy/nginx.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read the release notes before every update. For SQLite deployments, stop the service before copying the database so the backup is a consistent single file. Then change the pinned image tag, validate the Compose file, and recreate the service:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/gotosocial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Download the target image before starting the maintenance window.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker pull docker.io/superseriousbusiness/gotosocial:0.22.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose stop gotosocial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; data/sqlite.db &amp;quot;data/sqlite-pre-update-$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F).db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker-compose.yml &amp;quot;docker-compose.yml.pre-update-$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Edit docker-compose.yml and pin the reviewed release, for example 0.22.1.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --remove-orphans&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Confirm startup, the exact running version, and the public routes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail=100&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gotosocial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://gotosocial.your-domain.com/api/v1/instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://gotosocial.your-domain.com/settings&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not interrupt startup while GoToSocial reports database migrations. The update from 0.22.0 to 0.22.1 has no new database migration, but this is release-specific and must not be assumed for later versions.&lt;/p&gt;
&lt;p&gt;For Phanpy, replace the static release files in &lt;code&gt;html/&lt;/code&gt; with a verified newer release and recreate the Nginx container if needed.&lt;/p&gt;
&lt;h2 id=&quot;9-optional-migrating-from-mastodon&quot;&gt;9. Optional: Migrating from Mastodon&lt;/h2&gt;
&lt;p&gt;GoToSocial is not a drop-in Mastodon database replacement. If you are replacing an existing Mastodon account, treat it as an ActivityPub identity move after the new GoToSocial instance has been installed and tested.&lt;/p&gt;
&lt;p&gt;The migration flow is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep the old Mastodon account reachable.&lt;/li&gt;
&lt;li&gt;Create the new GoToSocial account.&lt;/li&gt;
&lt;li&gt;Add an alias in GoToSocial pointing to the old Mastodon account.&lt;/li&gt;
&lt;li&gt;Trigger the account move from the old Mastodon account to the new GoToSocial account.&lt;/li&gt;
&lt;li&gt;Import or recreate follows.&lt;/li&gt;
&lt;li&gt;Recreate hashtag follows separately if needed.&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            KEEP THE OLD ACCOUNT REACHABLE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;ActivityPub account moves depend on the old account being reachable long enough for other servers to observe the move. Do not shut down the old Mastodon hostname immediately after changing DNS.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;9-1-add-the-gotosocial-alias&quot;&gt;9.1. Add the GoToSocial Alias&lt;/h3&gt;
&lt;p&gt;In GoToSocial settings:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://gotosocial.your-domain.com/settings/user/migration&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the old Mastodon account as an alias, for example:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://mastodon.your-domain.com/@yourusername&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://mastodon.your-domain.com/users/yourusername&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9-2-trigger-the-move-in-mastodon&quot;&gt;9.2. Trigger the Move in Mastodon&lt;/h3&gt;
&lt;p&gt;Log in to the old Mastodon account and move it to:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@yourusername@gotosocial.your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mastodon will mark the old profile as moved and notify followers’ servers. Propagation is not instant.&lt;/p&gt;
&lt;h3 id=&quot;9-3-following-and-hashtags&quot;&gt;9.3. Following and Hashtags&lt;/h3&gt;
&lt;p&gt;Follower migration is handled by the ActivityPub move. Following relationships are different: export your Mastodon following list and import it into GoToSocial if the UI supports it, or recreate the follows through a client/API workflow.&lt;/p&gt;
&lt;p&gt;Hashtag follows are not guaranteed to migrate with account moves or account CSV imports. Export and recreate them separately.&lt;/p&gt;
&lt;p&gt;After the account move, search for the old Mastodon account from another Fediverse instance and verify that it points to the new GoToSocial account.&lt;/p&gt;
&lt;h2 id=&quot;10-optional-legacy-mastodon-proxy&quot;&gt;10. Optional: Legacy Mastodon Proxy&lt;/h2&gt;
&lt;p&gt;During a migration, it can be useful to keep &lt;code&gt;mastodon.your-domain.com&lt;/code&gt; reachable even after the new server handles DNS. A temporary Traefik file-provider route can proxy the old Mastodon host back to the old server.&lt;/p&gt;
&lt;p&gt;Remove this after the fallback window has ended. Keeping a legacy proxy forever makes the migration harder to reason about.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;GoToSocial fits neatly into a Traefik-based Docker setup: one small application container, SQLite storage for small instances, no public host port, and a separate static web client through the same reverse proxy. If you later replace Mastodon, handle that as an ActivityPub account move, not as a database transplant.&lt;/p&gt;
&lt;a href=&quot;https://docs.gotosocial.org/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;GOTOSOCIAL DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://codeberg.org/superseriousbusiness/gotosocial&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;GOTOSOCIAL CODEBERG&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://phanpy.social/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🌐&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;PHANPY&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying Lemmy with Docker, Traefik, and Nginx</title>
          <pubDate>Fri, 04 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/lemmy/</link>
          <guid>https://criticalbasics.xyz/posts/lemmy/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/lemmy/">&lt;p&gt;This guide provides a comprehensive walkthrough for deploying a secure and scalable Lemmy instance. We will use the official deployment pattern, which includes an Nginx container as an internal reverse proxy to manage application-specific routing. This entire stack is placed behind our modern Traefik v3 reverse proxy, which handles TLS, security, and public-facing routing.&lt;/p&gt;
&lt;p&gt;This “proxy-behind-a-proxy” architecture is highly recommended as it simplifies Traefik’s configuration and makes your Lemmy instance more robust and easier to update, closely following the official deployment standards.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-04&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Maintenance Update:&lt;/strong&gt; Updated Lemmy and Lemmy UI to 0.19.20 and pict-rs to 0.5.24, reduced production log verbosity, added post-update proxy/API/federation checks, and documented recovery of missing legacy ActivityPub uniqueness constraints.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Migration Update:&lt;/strong&gt; Updated image versions and added database-first migration and pict-rs storage guidance.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-10-30&lt;/td&gt;&lt;td&gt;Fixed mixed-content issues by enabling HTTPS settings and proper proxy headers in Lemmy behind Traefik.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-09-26&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide created using the official Nginx internal proxy method for maximum compatibility and update safety, integrated with the Traefik v3 stack.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide builds upon a secure Docker environment. Before you begin, you must have a fully functional Traefik v3 and CrowdSec stack.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            HARD REQUIREMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The following steps will not work correctly without the Traefik stack running as described in the prerequisite guide.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik_v3_crowdsec_tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;: This is the foundation for our public-facing reverse proxy and security.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;You will also need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A dedicated subdomain for your Lemmy instance (e.g., &lt;code&gt;lemmy.your-domain.com&lt;/code&gt;) pointed to your server’s IP address.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;openssl&lt;/code&gt; utility for generating secrets (&lt;code&gt;sudo apt install openssl&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-directory-structure&quot;&gt;2. Directory Structure&lt;/h2&gt;
&lt;p&gt;First, create a dedicated directory for your Lemmy configuration and data. This structure will hold all necessary config files.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create the main directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create directories for persistent data and configs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; volumes/pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; volumes/postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 991:991 volumes/pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-configuration&quot;&gt;3. Configuration&lt;/h2&gt;
&lt;p&gt;We will now create all the necessary configuration files for Nginx, PostgreSQL, Lemmy, and Docker Compose.&lt;/p&gt;
&lt;h3 id=&quot;3-1-generate-secrets&quot;&gt;3.1. Generate Secrets&lt;/h3&gt;
&lt;p&gt;Let’s generate strong, unique secrets for the database, image service, and admin account.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Generate a strong password for the Postgres database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Your Postgres password is: &lt;/span&gt;&lt;span&gt;$POSTGRES_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Generate a strong API key for Pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PICTRS_API_KEY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Your Pictrs API key is: &lt;/span&gt;&lt;span&gt;$PICTRS_API_KEY&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Generate a strong password for the Lemmy admin user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LEMMY_ADMIN_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Your Lemmy Admin password is: &lt;/span&gt;&lt;span&gt;$LEMMY_ADMIN_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            SAVE THESE SECRETS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Copy these generated values into a temporary text file. You will need to paste them into the configuration files in the upcoming steps.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-2-nginx-configuration-config-nginx-conf&quot;&gt;3.2. Nginx Configuration (&lt;code&gt;config/nginx.conf&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file contains the internal routing logic that directs traffic to either the Lemmy UI, the backend, or the image store based on the request path and headers.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee config/nginx.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;worker_processes 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;events {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    worker_connections 1024;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;http {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    upstream lemmy { server &amp;quot;lemmy:8536&amp;quot;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    upstream lemmy-ui { server &amp;quot;lemmy-ui:1234&amp;quot;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    server {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        listen 1236;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        listen 8536;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        server_name lemmy.criticalbasics.xyz;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        server_tokens off;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        gzip on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        gzip_types text/css application/javascript image/svg+xml;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        gzip_vary on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        client_max_body_size 20M;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        add_header X-Frame-Options SAMEORIGIN;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        add_header X-Content-Type-Options nosniff;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        add_header X-XSS-Protection &amp;quot;1; mode=block&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        location / {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            set $proxpass &amp;quot;http://lemmy-ui&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if ($http_accept = &amp;quot;application/activity+json&amp;quot;) { set $proxpass &amp;quot;http://lemmy&amp;quot;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if ($http_accept = &amp;quot;application/ld+json; profile=\&amp;quot;https://www.w3.org/ns/activitystreams\&amp;quot;&amp;quot;) { set $proxpass &amp;quot;http://lemmy&amp;quot;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if ($request_method = POST) { set $proxpass &amp;quot;http://lemmy&amp;quot;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_pass $proxpass;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            rewrite ^(.+)/+$ $1 permanent;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Real-IP $remote_addr;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header Host $host;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Forwarded-Ssl on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        location ~ ^/(api|pictrs|feeds|inbox|outbox|nodeinfo|version|socket\.io|federation|\.well-known) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_pass &amp;quot;http://lemmy&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_http_version 1.1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header Upgrade $http_upgrade;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header Connection &amp;quot;upgrade&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Real-IP $remote_addr;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header Host $host;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_set_header X-Forwarded-Ssl on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            proxy_redirect off;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-3-postgresql-configuration&quot;&gt;3.3. PostgreSQL Configuration&lt;/h3&gt;
&lt;p&gt;For better performance, we’ll provide a custom configuration file for PostgreSQL.&lt;/p&gt;
&lt;h4 id=&quot;config-custom-conf-performance-tuning&quot;&gt;&lt;code&gt;config/custom.conf&lt;/code&gt; (Performance Tuning)&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee config/custom.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Generated by https://pgtune.leopard.in.ua&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# DB Version: 16, OS: linux, RAM: 12 GB, CPUs: 16, Storage: ssd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;max_connections = 200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;shared_buffers = 3GB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;effective_cache_size = 9GB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;maintenance_work_mem = 768MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;checkpoint_completion_target = 0.9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;wal_buffers = 16MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;default_statistics_target = 100&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;random_page_cost = 1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;effective_io_concurrency = 200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;work_mem = 3932kB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;min_wal_size = 1GB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;max_wal_size = 8GB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;max_worker_processes = 16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;max_parallel_workers_per_gather = 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;max_parallel_workers = 16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;max_parallel_maintenance_workers = 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;config-pg-hba-conf-authentication-rules&quot;&gt;&lt;code&gt;config/pg_hba.conf&lt;/code&gt; (Authentication Rules)&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee config/pg_hba.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# TYPE  DATABASE        USER            ADDRESS                 METHOD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;local   all             all                                     trust&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;host    all             all             0.0.0.0/0               md5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;host    all             all             ::/0                    md5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-4-lemmy-configuration-config-lemmy-hjson&quot;&gt;3.4. Lemmy Configuration (&lt;code&gt;config/lemmy.hjson&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file controls the Lemmy application itself.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee config/lemmy.hjson&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  database: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    user: &amp;quot;lemmy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    password: &amp;quot;PASTE-YOUR-POSTGRES-PASSWORD-HERE&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    host: &amp;quot;postgres&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    port: 5432&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    database: &amp;quot;lemmy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  pictrs: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    url: &amp;quot;http://pictrs:8080/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    api_key: &amp;quot;PASTE-YOUR-PICTRS-API-KEY-HERE&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image_mode: &amp;quot;None&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  cache_external_link_previews: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  email: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    smtp_server: &amp;quot;your-mail-server.com:587&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    smtp_login: &amp;quot;lemmy@your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    smtp_password: &amp;quot;PASTE-YOUR-EMAIL-PASSWORD-HERE&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    smtp_from_address: &amp;quot;Lemmy &amp;lt;lemmy@your-domain.com&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    tls_type: &amp;quot;starttls&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  setup: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    admin_username: &amp;quot;admin&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    admin_password: &amp;quot;PASTE-YOUR-LEMMY-ADMIN-PASSWORD-HERE&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    site_name: &amp;quot;My Lemmy Instance&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    admin_email: &amp;quot;your-admin@example.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  hostname: &amp;quot;lemmy.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  bind: &amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  port: 8536&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  tls_enabled: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            KEEP MEDIA GROWTH UNDER CONTROL
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;For small personal instances, &lt;code&gt;image_mode: &quot;None&quot;&lt;/code&gt; and &lt;code&gt;cache_external_link_previews: false&lt;/code&gt; keep Lemmy from aggressively storing external link-preview images. This does not replace backups or monitoring, but it reduces avoidable media growth.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-5-docker-compose-docker-compose-yml&quot;&gt;3.5. Docker Compose (&lt;code&gt;docker-compose.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file ties all the services together. Notice that only the &lt;code&gt;lemmy-proxy&lt;/code&gt; service has Traefik labels and is exposed to the external &lt;code&gt;proxy&lt;/code&gt; network.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  lemmy-proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: nginx:stable-alpine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: lemmy-proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./config/nginx.conf:/etc/nginx/nginx.conf:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy-ui&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.lemmy.rule=Host(`lemmy.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.lemmy.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.lemmy.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.lemmy.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.lemmy.loadbalancer.server.port=8536&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  lemmy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: dessalines/lemmy:0.19.20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    hostname: lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - RUST_LOG=warn,lemmy_server=info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./config/lemmy.hjson:/config/config.hjson:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  lemmy-ui:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: dessalines/lemmy-ui:0.19.20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: lemmy-ui&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    hostname: lemmy-ui&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - LEMMY_UI_LEMMY_EXTERNAL_HOST=lemmy.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - LEMMY_UI_HTTPS=true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  pictrs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: asonix/pictrs:0.5.24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    hostname: pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - PICTRS__API_KEY=PASTE-YOUR-PICTRS-API-KEY-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - RUST_LOG=info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    user: 991:991&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./volumes/pictrs:/mnt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  postgres:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: postgres:16-alpine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    hostname: postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - POSTGRES_USER=lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - POSTGRES_PASSWORD=PASTE-YOUR-POSTGRES-PASSWORD-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - POSTGRES_DB=lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./volumes/postgres:/var/lib/postgresql/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./config/custom.conf:/etc/postgresql/postgresql.conf:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./config/pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - lemmy-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  lemmy-net:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    driver: bridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-6-update-configuration-with-your-values&quot;&gt;3.6. Update Configuration with Your Values&lt;/h3&gt;
&lt;p&gt;Carefully replace all placeholders in the files you just created.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Domain Name:&lt;/strong&gt; In &lt;code&gt;config/nginx.conf&lt;/code&gt;, &lt;code&gt;config/lemmy.hjson&lt;/code&gt;, and &lt;code&gt;docker-compose.yml&lt;/code&gt;, replace all instances of &lt;code&gt;lemmy.your-domain.com&lt;/code&gt; with your actual domain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secrets:&lt;/strong&gt; In &lt;code&gt;config/lemmy.hjson&lt;/code&gt; and &lt;code&gt;docker-compose.yml&lt;/code&gt;, paste the secrets you generated in step 3.1. Ensure the Postgres password and Pictrs API key are identical where required.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email Settings:&lt;/strong&gt; In &lt;code&gt;config/lemmy.hjson&lt;/code&gt;, update the &lt;code&gt;email&lt;/code&gt; section with your SMTP server details.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;4-launch-the-stack&quot;&gt;4. Launch the Stack&lt;/h2&gt;
&lt;p&gt;With all configuration files in place, you can start your Lemmy instance.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# From within the /opt/containers/lemmy directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first launch will take a few minutes as Docker downloads all the necessary images. You can monitor the progress with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Press &lt;code&gt;CTRL+C&lt;/code&gt; to exit the logs view once the services are stable.&lt;/p&gt;
&lt;h2 id=&quot;5-verify-the-installation&quot;&gt;5. Verify the Installation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check Running Containers:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ps&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --format&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{{.Names}}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see &lt;code&gt;lemmy-proxy&lt;/code&gt;, &lt;code&gt;lemmy&lt;/code&gt;, &lt;code&gt;lemmy-ui&lt;/code&gt;, &lt;code&gt;pictrs&lt;/code&gt;, and &lt;code&gt;postgres&lt;/code&gt; running.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access Your Site:&lt;/strong&gt;
Open a web browser and navigate to &lt;code&gt;https://lemmy.your-domain.com&lt;/code&gt;. You should see the Lemmy welcome page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Log In as Admin:&lt;/strong&gt;
Log in using the admin username (&lt;code&gt;admin&lt;/code&gt;) and the strong password you generated for it. You can now begin administering your instance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;6-maintenance&quot;&gt;6. Maintenance&lt;/h2&gt;
&lt;h3 id=&quot;updating-lemmy&quot;&gt;Updating Lemmy&lt;/h3&gt;
&lt;p&gt;Updating is now safer. You typically only need to update the image tags in &lt;code&gt;docker-compose.yml&lt;/code&gt; for &lt;code&gt;lemmy&lt;/code&gt;, &lt;code&gt;lemmy-ui&lt;/code&gt;, and &lt;code&gt;pictrs&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/lemmy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Back up the database before applying migrations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  pg_dump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -Fc -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lemmy&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lemmy&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lemmy-pre-update.dump&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Pull only the application images being updated. This avoids an&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# unintended PostgreSQL major/minor image change during the same operation.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull lemmy lemmy-ui pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Restart the stack with the new images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --remove-orphans&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Nginx resolves Docker service names when it starts. Restart the internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# proxy so it does not retain the old Lemmy container IP after a recreation.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose restart lemmy-proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Verify container state and the public API version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose ps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://lemmy.your-domain.com/api/v3/site&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;{version: .version, federation_enabled: .site_view.local_site.federation_enabled}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            CHECK RELEASE NOTES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Always consult the official Lemmy release notes before updating for any special instructions or potential changes to configuration files like &lt;code&gt;nginx.conf&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            A 502 AFTER UPDATING USUALLY MEANS STALE PROXY DNS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If Lemmy responds inside its container but the public route returns &lt;code&gt;502 Bad Gateway&lt;/code&gt;, restart &lt;code&gt;lemmy-proxy&lt;/code&gt;. The long-running Nginx process may still be using the IP address of the container that was replaced during the update.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;federation-verification&quot;&gt;Federation Verification&lt;/h3&gt;
&lt;p&gt;Do not treat a working home page as proof that federation is healthy. Check the public API, WebFinger, and an ActivityPub actor as well:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Federation must be enabled and the reported version must match the image tag.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://lemmy.your-domain.com/api/v3/site&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;{version: .version, federation_enabled: .site_view.local_site.federation_enabled}&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Replace admin with an existing local user.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;https://lemmy.your-domain.com/.well-known/webfinger?resource=acct:admin@lemmy.your-domain.com&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -H&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Accept: application/activity+json&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  https://lemmy.your-domain.com/u/admin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;{type, id, preferredUsername, inbox, outbox}&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Review recent delivery and queue failures after an update.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --since=30m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lemmy&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -Ei&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;federation queue|could not send|inbox.*error|outbox.*error|panic|fatal&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Confirm that current remote posts are actually being stored and surfaced.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;https://lemmy.your-domain.com/api/v3/post/list?type_=All&amp;amp;sort=New&amp;amp;limit=10&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;.posts[] | {published: .post.published, post: .post.ap_id, community: .community.actor_id}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            A WORKING UI CAN HIDE A BROKEN FEDERATION SCHEMA
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;On a database with a long upgrade history, federation can stop while the UI and public API still return HTTP 200. Repeated PostgreSQL errors such as &lt;code&gt;there is no unique or exclusion constraint matching the ON CONFLICT specification&lt;/code&gt; indicate a schema/data problem, not a network problem. Check that the official unique constraints for &lt;code&gt;community.actor_id&lt;/code&gt;, &lt;code&gt;person.actor_id&lt;/code&gt;, &lt;code&gt;post.ap_id&lt;/code&gt;, and &lt;code&gt;comment.ap_id&lt;/code&gt; exist. If duplicates have accumulated, do not simply delete them or add the constraints blindly: dependent posts, comments, likes, follows, reports, and aggregate rows must be merged transactionally. Take a full database backup and test the repair against a restored database first.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;migration-notes&quot;&gt;Migration Notes&lt;/h3&gt;
&lt;p&gt;For a server migration, treat Lemmy as a database-first service. The PostgreSQL database contains the instance identity, local users, subscriptions, site settings, instance keys, and federation state. If you want the same instance to continue federating as itself, migrate the database and core config/secrets.&lt;/p&gt;
&lt;p&gt;pict-rs media is a separate decision:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If historical images matter, back up and restore &lt;code&gt;volumes/pictrs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If old media is not important, you can intentionally skip the old pict-rs store and keep only the database and active config.&lt;/li&gt;
&lt;li&gt;Remote/federated content can often be fetched again, but local uploads and avatars may be lost if you skip media.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DO NOT PRUNE PICT-RS BY FILE AGE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Do not run ad-hoc commands like &lt;code&gt;find volumes/pictrs -mtime +21 -delete&lt;/code&gt;. pict-rs keeps metadata and aliases in addition to files. Deleting files directly can leave broken references. Use application-level deletion, pict-rs tooling, or a planned media-retention strategy instead.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;After a migration, watch the federation workers. If &lt;code&gt;federation_queue_state&lt;/code&gt; points to activity IDs that no longer exist in &lt;code&gt;sent_activity&lt;/code&gt;, Lemmy can repeatedly log queue errors. Treat this as a database repair task and take a database backup before touching federation queue tables.&lt;/p&gt;
&lt;h3 id=&quot;backing-up&quot;&gt;Backing Up&lt;/h3&gt;
&lt;p&gt;A complete backup consists of the database and the uploaded images.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# From your /opt/containers/lemmy directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. Stop services to ensure data consistency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose stop lemmy lemmy-ui lemmy-proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Back up the database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres pg_dump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lemmy&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lemmy&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gzip&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lemmy_db_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.sql.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. Back up the images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -czvf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pictrs_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.tar.gz volumes/pictrs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 4. Restart services&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You have now deployed a production-ready Lemmy instance using a robust and maintainable architecture. By combining the power of Traefik for edge routing and security with the official Nginx proxy for internal application logic, your instance is scalable, secure, and easy to manage for years to come.&lt;/p&gt;
&lt;a href=&quot;https://join-lemmy.org/docs/en/administration/from_scratch.html&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL LEMMY DOCS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/LemmyNet/lemmy-docker&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL DOCKER REPO&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying Mox Mail Server with systemd and Traefik: A Lightweight Mailcow Alternative</title>
          <pubDate>Wed, 02 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/mox-e-mail-server/</link>
          <guid>https://criticalbasics.xyz/posts/mox-e-mail-server/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/mox-e-mail-server/">&lt;p&gt;This guide deploys &lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.xmox.nl/&quot;&gt;Mox&lt;/a&gt;&lt;/strong&gt; as a native mail server managed by &lt;code&gt;systemd&lt;/code&gt;, while keeping &lt;strong&gt;Traefik v3&lt;/strong&gt; responsible for the public HTTPS routes. This is the cleanest pattern when Traefik already terminates TLS for your web stack, but you still need a real mail server that owns the mail protocols directly.&lt;/p&gt;
&lt;p&gt;Mox is a good lightweight alternative to a larger stack such as &lt;strong&gt;&lt;a href=&quot;../mailcow-mailserver/&quot;&gt;Mailcow&lt;/a&gt;&lt;/strong&gt;. It includes SMTP, submission, IMAP, webmail, admin pages, account pages, MTA-STS, autoconfig, DNS checks, and spam filtering in one service.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            TRAEFIK DOES NOT PROXY MAIL PROTOCOLS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Traefik is only used for HTTPS routes such as webmail, admin, autoconfig, autodiscover, and MTA-STS. SMTP and IMAP must be reachable directly on the host. Reverse-proxying the web UI alone is not a complete mail server setup.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-02&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Junk Filtering and Updates:&lt;/strong&gt; Added Introbox, safe Junk/Trash training, retraining, and a backup-first verified upgrade procedure.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-08-31&lt;/td&gt;&lt;td&gt;&lt;strong&gt;TLS Renewal:&lt;/strong&gt; Added validated automatic Traefik-to-Mox certificate synchronization with a systemd path trigger and timer fallback.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;DNS Notes:&lt;/strong&gt; Added SPF, DKIM, DMARC, TLSRPT, MTA-STS, and SRV record pitfalls from a production setup.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Major Rework:&lt;/strong&gt; Switched from Docker-only Mox to a native systemd deployment with direct mail ports, Traefik web routes, DNS, and migration notes.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-12&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide created for integrating Mox with the Traefik v3 stack.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-architecture&quot;&gt;1. Architecture&lt;/h2&gt;
&lt;p&gt;The target architecture looks like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Internet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | 25, 465, 587, 993&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Mox on the host via systemd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Internet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | 443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Traefik -&amp;gt; Mox internal HTTP listeners&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mox runs as a host service under &lt;code&gt;/home/mox&lt;/code&gt;. It binds the mail ports directly, then drops privileges to the &lt;code&gt;mox&lt;/code&gt; user. Traefik reaches Mox over an internal Docker bridge address for the HTTPS-facing helper endpoints.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Function&lt;/th&gt;&lt;th&gt;Public hostname&lt;/th&gt;&lt;th style=&quot;text-align: right&quot;&gt;Public port&lt;/th&gt;&lt;th&gt;Handler&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;SMTP delivery&lt;/td&gt;&lt;td&gt;&lt;code&gt;mail.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;25/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Mox directly&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Submission&lt;/td&gt;&lt;td&gt;&lt;code&gt;mail.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;587/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Mox directly&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SMTPS&lt;/td&gt;&lt;td&gt;&lt;code&gt;mail.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;465/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Mox directly&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;IMAPS&lt;/td&gt;&lt;td&gt;&lt;code&gt;mail.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;993/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Mox directly&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Account/admin/webmail&lt;/td&gt;&lt;td&gt;&lt;code&gt;mail.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;443/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Traefik -&amp;gt; Mox HTTP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Autoconfig&lt;/td&gt;&lt;td&gt;&lt;code&gt;autoconfig.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;443/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Traefik -&amp;gt; Mox HTTP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Autodiscover&lt;/td&gt;&lt;td&gt;&lt;code&gt;autodiscover.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;443/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Traefik -&amp;gt; Mox HTTP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MTA-STS&lt;/td&gt;&lt;td&gt;&lt;code&gt;mta-sts.your-domain.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;code&gt;443/tcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Traefik -&amp;gt; Mox HTTP&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            PROVIDER SMTP BLOCKS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Many VPS providers block outbound SMTP by default. Hetzner Cloud, for example, blocks outgoing ports &lt;code&gt;25&lt;/code&gt; and &lt;code&gt;465&lt;/code&gt; until the account is eligible and the limit is lifted. Request this before relying on direct delivery, or configure a relayhost.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;2-prerequisites&quot;&gt;2. Prerequisites&lt;/h2&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec stack&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A public IPv4 address. IPv6 is strongly recommended.&lt;/li&gt;
&lt;li&gt;Control over DNS records for the mail domain.&lt;/li&gt;
&lt;li&gt;Open firewall ports &lt;code&gt;25/tcp&lt;/code&gt;, &lt;code&gt;465/tcp&lt;/code&gt;, &lt;code&gt;587/tcp&lt;/code&gt;, and &lt;code&gt;993/tcp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git&lt;/code&gt;, &lt;code&gt;golang&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt;, and &lt;code&gt;openssl&lt;/code&gt; installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git golang jq openssl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-create-the-mox-user-and-build-the-binary&quot;&gt;3. Create the Mox User and Build the Binary&lt;/h2&gt;
&lt;p&gt;Create a dedicated system user and build Mox from an explicit release tag.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; useradd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --system --home-dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --create-home --shell&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /usr/sbin/nologin mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox /home/mox/src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox git clone https://github.com/mjl-/mox.git /home/mox/src/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/src/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Replace this with the release tag you want to run.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox git checkout&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --detach&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; vX.Y.Z&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox git show&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --no-patch --format=fuller&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox env CGO_ENABLED=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; go build&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -trimpath -ldflags=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;-s -w&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox.new .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0750&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox.new /home/mox/mox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            USE RELEASE NOTES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Mox moves quickly. Check the upstream release notes before choosing or changing a release tag, especially on production mail systems. Compare the full commit shown by &lt;code&gt;git show&lt;/code&gt; with the commit linked from the release page. The Mox command is built from the repository root (&lt;code&gt;.&lt;/code&gt;), not from &lt;code&gt;./cmd/mox&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;4-initial-mox-configuration&quot;&gt;4. Initial Mox Configuration&lt;/h2&gt;
&lt;p&gt;Run the quickstart in existing-webserver mode. Use &lt;code&gt;-skipdial&lt;/code&gt; if DNS still points at an old server during a migration.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/mox quickstart&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -hostname&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -adminemail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postmaster@your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -existing-webserver \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -skipdial&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates Mox configuration and data under &lt;code&gt;/home/mox/config&lt;/code&gt; and &lt;code&gt;/home/mox/data&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now edit the generated config:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudoedit&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/config/mox.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the internal listener, enable the HTTP services that Traefik will route to. In this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Account, admin, webmail, and web API use internal port &lt;code&gt;1080&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Autoconfig, autodiscover, and MTA-STS use internal port &lt;code&gt;81&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Forwarded: true&lt;/code&gt; tells Mox to respect the reverse proxy headers for rate limiting and secure cookies.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NonTLS: true&lt;/code&gt; is used for the internal listener because Traefik handles public HTTPS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Conceptually, the internal listener should expose:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AccountHTTP    -&amp;gt; port 1080, Forwarded: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AdminHTTP      -&amp;gt; port 1080, Forwarded: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WebmailHTTP    -&amp;gt; port 1080, Forwarded: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WebAPIHTTP     -&amp;gt; port 1080, Forwarded: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AutoconfigHTTPS -&amp;gt; port 81, NonTLS: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MTASTSHTTPS     -&amp;gt; port 81, NonTLS: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WebserverHTTP   -&amp;gt; port 81&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The public listener should bind your server’s real public IP addresses and enable SMTP, submission, SMTPS, and IMAPS.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            EXPLICIT PUBLIC IPS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Prefer explicit public IPs in the Mox public listener. This makes outgoing mail source addresses predictable and helps Mox validate that your DNS and reverse DNS are consistent.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;For MTA-STS, keep the generated short &lt;code&gt;MaxAge&lt;/code&gt; while testing. Once the domain is reachable, certificates work, and the DNS records are stable, raise it to a production value such as:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MTASTS:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	PolicyID: 20260701T110042&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Mode: enforce&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MaxAge: 720h0m0s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MX:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		- mail.your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Change &lt;code&gt;PolicyID&lt;/code&gt; whenever you materially change the MTA-STS policy. The matching DNS record under &lt;code&gt;_mta-sts.your-domain.com&lt;/code&gt; must use the same new ID so remote mail servers fetch the updated policy.&lt;/p&gt;
&lt;h2 id=&quot;5-systemd-service&quot;&gt;5. systemd Service&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/etc/systemd/system/mox.service&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Unit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Description&lt;/span&gt;&lt;span&gt;=mox mail server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;After&lt;/span&gt;&lt;span&gt;=network-online.target&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Wants&lt;/span&gt;&lt;span&gt;=network-online.target&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Service]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;UMask&lt;/span&gt;&lt;span&gt;=007&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;LimitNOFILE&lt;/span&gt;&lt;span&gt;=65535&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Type&lt;/span&gt;&lt;span&gt;=simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;WorkingDirectory&lt;/span&gt;&lt;span&gt;=/home/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ExecStart&lt;/span&gt;&lt;span&gt;=/home/mox/mox serve&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ExecStop&lt;/span&gt;&lt;span&gt;=/home/mox/mox stop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Restart&lt;/span&gt;&lt;span&gt;=always&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RestartSec&lt;/span&gt;&lt;span&gt;=5s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;SyslogFacility&lt;/span&gt;&lt;span&gt;=mail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Mox starts as root to bind low ports, then drops privileges.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PrivateDevices&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PrivateTmp&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectSystem&lt;/span&gt;&lt;span&gt;=strict&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ReadWritePaths&lt;/span&gt;&lt;span&gt;=/home/mox/config /home/mox/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectKernelTunables&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectControlGroups&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;CapabilityBoundingSet&lt;/span&gt;&lt;span&gt;=CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE CAP_CHOWN CAP_FSETID CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_KILL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;NoNewPrivileges&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RestrictAddressFamilies&lt;/span&gt;&lt;span&gt;=AF_INET AF_INET6 AF_UNIX AF_NETLINK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectProc&lt;/span&gt;&lt;span&gt;=invisible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RestrictNamespaces&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RestrictRealtime&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RemoveIPC&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectHostname&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectClock&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectKernelLogs&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ProtectKernelModules&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;MemoryDenyWriteExecute&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;LockPersonality&lt;/span&gt;&lt;span&gt;=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;DevicePolicy&lt;/span&gt;&lt;span&gt;=closed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;SystemCallArchitectures&lt;/span&gt;&lt;span&gt;=native&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;SystemCallFilter&lt;/span&gt;&lt;span&gt;=@system-service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Install]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;WantedBy&lt;/span&gt;&lt;span&gt;=multi-user.target&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enable it:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl enable&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --now&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl status mox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;6-traefik-file-provider-route&quot;&gt;6. Traefik File Provider Route&lt;/h2&gt;
&lt;p&gt;Because Mox is not a Docker container in this setup, use the Traefik file provider instead of Docker labels.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/traefik-stack/traefik/dynamic/mox.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;http&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  routers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    mox-mail&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      rule&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Host(`mail.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      entryPoints&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; websecure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      service&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox-account&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      tls&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        certResolver&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tls_resolver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      middlewares&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; security-headers@file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; crowdsec-bouncer@docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    mox-autoconfig&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      rule&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Host(`autoconfig.your-domain.com`) || Host(`autodiscover.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      entryPoints&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; websecure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      service&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      tls&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        certResolver&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tls_resolver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      middlewares&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; security-headers@file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; crowdsec-bouncer@docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    mox-mta-sts&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      rule&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Host(`mta-sts.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      entryPoints&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; websecure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      service&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      tls&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        certResolver&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tls_resolver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      middlewares&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; security-headers@file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; crowdsec-bouncer@docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    mox-account&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      loadBalancer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        servers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;http://172.18.0.1:1080&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    mox-web&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      loadBalancer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        servers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;http://172.18.0.1:81&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;172.18.0.1&lt;/code&gt; with the Docker bridge gateway address Traefik can use to reach the host.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; network inspect proxy&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --format&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{{range .IPAM.Config}}{{println .Gateway}}{{end}}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If UFW is enabled, allow only the Traefik Docker network to reach those host ports:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow in on br-REPLACE_WITH_PROXY_BRIDGE_IFACE&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  from 172.18.0.0/16 to&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 172.18.0.1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; port&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1080&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proto tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow in on br-REPLACE_WITH_PROXY_BRIDGE_IFACE&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  from 172.18.0.0/16 to&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 172.18.0.1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; port&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 81&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proto tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without these narrow bridge rules, Traefik may return &lt;code&gt;504 Gateway Timeout&lt;/code&gt; even though Mox is listening correctly.&lt;/p&gt;
&lt;h2 id=&quot;7-tls-for-mail-protocols&quot;&gt;7. TLS for Mail Protocols&lt;/h2&gt;
&lt;p&gt;Traefik can terminate HTTPS for web routes, but Mox still needs certificates for SMTP and IMAP TLS. You have two practical options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Let Mox manage its own ACME certificates for the mail host.&lt;/li&gt;
&lt;li&gt;Export the Traefik ACME certificate for the mail-related names and configure it in &lt;code&gt;mox.conf&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For a Traefik-centered setup, exporting from &lt;code&gt;acme.json&lt;/code&gt; keeps one certificate authority flow. The exact script depends on your resolver name and SAN layout, but the important result is that Mox has PEM files for:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/home/mox/tls/mail.your-domain.com-chain.crt.pem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/home/mox/tls/mail.your-domain.com.key.pem&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then reference them under the public listener’s &lt;code&gt;TLS&lt;/code&gt; section:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TLS:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	KeyCerts:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			CertFile: /home/mox/tls/mail.your-domain.com-chain.crt.pem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			KeyFile: /home/mox/tls/mail.your-domain.com.key.pem&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            A ONE-TIME EXPORT IS NOT ENOUGH
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Traefik renews the certificate inside &lt;code&gt;acme.json&lt;/code&gt;, but it does not update separate PEM files used by Mox. Automate the export and restart Mox after a validated certificate change, or the mail protocols will eventually serve an expired certificate even while HTTPS on port &lt;code&gt;443&lt;/code&gt; remains valid.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The following root-owned script finds the certificate by hostname across all Traefik resolvers, validates its hostname, remaining lifetime, and private key, and only restarts Mox when the files actually change.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;/usr/local/sbin/sync-traefik-cert-to-mox&lt;/code&gt; and adjust &lt;code&gt;host_name&lt;/code&gt;, &lt;code&gt;acme_json&lt;/code&gt;, and &lt;code&gt;tls_dir&lt;/code&gt; if your paths differ:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -euo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;readonly&lt;/span&gt;&lt;span&gt; host_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;mail.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;readonly&lt;/span&gt;&lt;span&gt; acme_json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/opt/containers/traefik-stack/traefik/certs/acme.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;readonly&lt;/span&gt;&lt;span&gt; tls_dir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/home/mox/tls&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;readonly&lt;/span&gt;&lt;span&gt; cert_dst&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;tls_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/${&lt;/span&gt;&lt;span&gt;host_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}-chain.crt.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;readonly&lt;/span&gt;&lt;span&gt; key_dst&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;tls_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/${&lt;/span&gt;&lt;span&gt;host_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}.key.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 9&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/run/lock/mox-traefik-cert-sync.lock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;flock&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;umask 077&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tls_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/.traefik-cert-sync.XXXXXX&amp;quot;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cleanup&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    find&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -mindepth 1 -maxdepth 1 -type&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -delete&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    rmdir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;trap&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cleanup EXIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -er --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; host &amp;quot;&lt;/span&gt;&lt;span&gt;$host_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    to_entries[].value.Certificates[]?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    | select(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        .domain.main == $host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        or ((.domain.sans // []) | index($host))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  | if length == 1 then .[0].certificate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    elif length == 0 then error(&amp;quot;certificate not found for &amp;quot; + $host)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    else error(&amp;quot;multiple certificates found for &amp;quot; + $host)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$acme_json&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; base64&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --decode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -er --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; host &amp;quot;&lt;/span&gt;&lt;span&gt;$host_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    to_entries[].value.Certificates[]?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    | select(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        .domain.main == $host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        or ((.domain.sans // []) | index($host))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  | if length == 1 then .[0].key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    elif length == 0 then error(&amp;quot;private key not found for &amp;quot; + $host)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    else error(&amp;quot;multiple private keys found for &amp;quot; + $host)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$acme_json&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; base64&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --decode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; x509&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -noout -checkhost&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$host_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; x509&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -noout -checkend 86400&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; x509&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -pubkey -noout \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pkey&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -pubin -outform&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; DER&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pub&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pkey&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -pubout -outform&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; DER&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pub&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cmp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pub&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pub&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chown&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root:root &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$cert_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$key_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cmp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$cert_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cmp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pem&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$key_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Mox TLS certificate for ${&lt;/span&gt;&lt;span&gt;host_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} is already current.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0600 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/certificate.pem&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;cert_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}.next&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0600 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;${&lt;/span&gt;&lt;span&gt;tmp_dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/private-key.pem&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;key_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}.next&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mv&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;cert_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}.next&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$cert_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mv&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;key_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}.next&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$key_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; restart mox.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; is-active&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Updated Mox TLS certificate for ${&lt;/span&gt;&lt;span&gt;host_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}:&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; x509&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$cert_dst&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -noout -subject -dates -serial -fingerprint -sha256&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install it with restricted permissions:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown root:root /usr/local/sbin/sync-traefik-cert-to-mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0750&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /usr/local/sbin/sync-traefik-cert-to-mox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;/etc/systemd/system/mox-traefik-cert-sync.service&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Unit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Description&lt;/span&gt;&lt;span&gt;=Synchronize Traefik ACME certificate to Mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;After&lt;/span&gt;&lt;span&gt;=docker.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RequiresMountsFor&lt;/span&gt;&lt;span&gt;=/opt/containers/traefik-stack/traefik/certs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ConditionPathExists&lt;/span&gt;&lt;span&gt;=/opt/containers/traefik-stack/traefik/certs/acme.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Service]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Type&lt;/span&gt;&lt;span&gt;=oneshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ExecStart&lt;/span&gt;&lt;span&gt;=/usr/local/sbin/sync-traefik-cert-to-mox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;/etc/systemd/system/mox-traefik-cert-sync.path&lt;/code&gt; to react when Traefik changes &lt;code&gt;acme.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Unit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Description&lt;/span&gt;&lt;span&gt;=Watch Traefik ACME storage for Mox certificate updates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Path]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PathChanged&lt;/span&gt;&lt;span&gt;=/opt/containers/traefik-stack/traefik/certs/acme.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Unit&lt;/span&gt;&lt;span&gt;=mox-traefik-cert-sync.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Install]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;WantedBy&lt;/span&gt;&lt;span&gt;=paths.target&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;/etc/systemd/system/mox-traefik-cert-sync.timer&lt;/code&gt; as a fallback in case a filesystem event is missed:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Unit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Description&lt;/span&gt;&lt;span&gt;=Periodic fallback sync of Traefik certificate to Mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Timer]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;OnBootSec&lt;/span&gt;&lt;span&gt;=2min&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;OnUnitActiveSec&lt;/span&gt;&lt;span&gt;=6h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;RandomizedDelaySec&lt;/span&gt;&lt;span&gt;=5min&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Persistent&lt;/span&gt;&lt;span&gt;=true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Unit&lt;/span&gt;&lt;span&gt;=mox-traefik-cert-sync.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Install]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;WantedBy&lt;/span&gt;&lt;span&gt;=timers.target&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the first synchronization, then enable both triggers:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl start mox-traefik-cert-sync.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl enable&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --now \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mox-traefik-cert-sync.path&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mox-traefik-cert-sync.timer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirm that Mox, the watcher, and the fallback timer are active:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl is-active&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mox.service&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mox-traefik-cert-sync.path&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mox-traefik-cert-sync.timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl list-timers mox-traefik-cert-sync.timer&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;8-firewall&quot;&gt;8. Firewall&lt;/h2&gt;
&lt;p&gt;Open the mail ports:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 25/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 465/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 587/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 993/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keep the Mox internal HTTP ports restricted to Traefik’s Docker bridge only. Do not expose &lt;code&gt;1080&lt;/code&gt; or &lt;code&gt;81&lt;/code&gt; publicly.&lt;/p&gt;
&lt;h2 id=&quot;9-dns-checklist&quot;&gt;9. DNS Checklist&lt;/h2&gt;
&lt;p&gt;Mox has a built-in DNS record generator and checker. Use both:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/config/mox.conf config dnsrecords your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/config/mox.conf config dnscheck your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated output is authoritative for your installation. Do not copy the example values below blindly, but use them as a checklist for the record types your DNS provider should contain.&lt;/p&gt;
&lt;h3 id=&quot;core-mail-records&quot;&gt;Core Mail Records&lt;/h3&gt;
&lt;p&gt;At minimum, configure the mail host, MX, and SPF:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mail.your-domain.com.       A      YOUR_IPV4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mail.your-domain.com.       AAAA   YOUR_IPV6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mail.your-domain.com.       TXT    &amp;quot;v=spf1 a -all&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;your-domain.com.            MX     10 mail.your-domain.com.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;your-domain.com.            TXT    &amp;quot;v=spf1 ip4:YOUR_IPV4 ip6:YOUR_IPV6 mx ~all&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only publish one SPF TXT record per name. Two TXT records beginning with &lt;code&gt;v=spf1&lt;/code&gt; on the same name are invalid and Mox will report &lt;code&gt;multiple spf txt records in dns&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you do not use IPv6, omit the &lt;code&gt;AAAA&lt;/code&gt; record and the &lt;code&gt;ip6:&lt;/code&gt; mechanism. If you do use IPv6, make sure Mox binds to that same address and that reverse DNS exists for it.&lt;/p&gt;
&lt;h3 id=&quot;dkim&quot;&gt;DKIM&lt;/h3&gt;
&lt;p&gt;Add all DKIM selector records generated by Mox, for example:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2026a._domainkey.your-domain.com. TXT &amp;quot;v=DKIM1;h=sha256;p=...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2026b._domainkey.your-domain.com. TXT &amp;quot;v=DKIM1;h=sha256;p=...&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When entering DKIM through a DNS provider web UI, combine the zonefile-style split strings into one long TXT value. Keep old DKIM selectors only if you still need to validate mail sent before the migration or from another system; Mox itself signs with the selectors configured in &lt;code&gt;domains.conf&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;dmarc-and-tls-reporting&quot;&gt;DMARC and TLS Reporting&lt;/h3&gt;
&lt;p&gt;Mox can route technical reports into dedicated mailboxes on an existing account. A typical generated domain config looks like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DMARC:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Localpart: dmarcreports&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Account: operator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Mailbox: DMARC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TLSRPT:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Localpart: tlsreports&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Account: operator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	Mailbox: TLSRPT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That means the following addresses do not have to be normal login accounts:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dmarcreports@your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tlsreports@your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tlsreports@mail.your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They are technical report sinks. Mox delivers them to the configured account and mailbox.&lt;/p&gt;
&lt;p&gt;Example records:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_dmarc.your-domain.com.             TXT &amp;quot;v=DMARC1;p=reject;rua=mailto:dmarcreports@your-domain.com!10m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_smtp._tls.your-domain.com.         TXT &amp;quot;v=TLSRPTv1; rua=mailto:tlsreports@your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_smtp._tls.mail.your-domain.com.    TXT &amp;quot;v=TLSRPTv1; rua=mailto:tlsreports@mail.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;!10m&lt;/code&gt; suffix in the DMARC &lt;code&gt;rua&lt;/code&gt; value is a report size limit, not part of the mailbox name.&lt;/p&gt;
&lt;h3 id=&quot;mta-sts&quot;&gt;MTA-STS&lt;/h3&gt;
&lt;p&gt;MTA-STS needs both the HTTPS endpoint and the TXT policy ID:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mta-sts.your-domain.com.       CNAME mail.your-domain.com.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_mta-sts.your-domain.com.      TXT &amp;quot;v=STSv1; id=20260701T110042&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The TXT &lt;code&gt;id&lt;/code&gt; must match the current policy ID in Mox. Whenever you change the MTA-STS policy, change both the Mox &lt;code&gt;PolicyID&lt;/code&gt; and this DNS TXT value. Do not leave multiple &lt;code&gt;_mta-sts&lt;/code&gt; TXT records behind; Mox will report &lt;code&gt;multiple mta-sts records&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;autoconfig-and-srv-records&quot;&gt;Autoconfig and SRV Records&lt;/h3&gt;
&lt;p&gt;For client autoconfiguration:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;autoconfig.your-domain.com.          CNAME mail.your-domain.com.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;autodiscover.your-domain.com.        CNAME mail.your-domain.com.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_autodiscover._tcp.your-domain.com.  SRV 0 1 443 mail.your-domain.com.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_imaps._tcp.your-domain.com.         SRV 0 1 993 mail.your-domain.com.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_submissions._tcp.your-domain.com.   SRV 0 1 465 mail.your-domain.com.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mox may also generate optional SRV records that explicitly disable plaintext IMAP, plaintext submission, and POP3:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_imap._tcp.your-domain.com.          SRV 0 0 0 .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_submission._tcp.your-domain.com.    SRV 0 0 0 .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_pop3._tcp.your-domain.com.          SRV 0 0 0 .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_pop3s._tcp.your-domain.com.         SRV 0 0 0 .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These optional records are useful for a completely quiet &lt;code&gt;dnscheck&lt;/code&gt;, but some DNS web interfaces do not accept &lt;code&gt;.&lt;/code&gt; as a target. If your provider rejects them, leave them out; the secure IMAPS and submissions SRV records above are the important ones.&lt;/p&gt;
&lt;h3 id=&quot;reverse-dns&quot;&gt;Reverse DNS&lt;/h3&gt;
&lt;p&gt;Set reverse DNS/PTR at your server provider, not at the domain DNS provider:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;YOUR_IPV4 -&amp;gt; mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;YOUR_IPV6 -&amp;gt; mail.your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Forward and reverse DNS should agree: &lt;code&gt;mail.your-domain.com&lt;/code&gt; must resolve back to the same public IP addresses.&lt;/p&gt;
&lt;h3 id=&quot;checking-authoritative-dns&quot;&gt;Checking Authoritative DNS&lt;/h3&gt;
&lt;p&gt;Resolver caches can show stale values for a while. If &lt;code&gt;dnscheck&lt;/code&gt; still reports an old DMARC, TLSRPT, SPF, or MTA-STS record after you changed it, query the authoritative nameserver directly:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +short @ns1.your-dns-provider.example TXT _dmarc.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +short @ns1.your-dns-provider.example TXT _smtp._tls.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +short @ns1.your-dns-provider.example TXT _mta-sts.your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the authoritative nameserver is correct but Mox still sees old records, wait for the previous TTL to expire.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DNSBL RESOLVER WARNINGS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Some cloud provider resolvers can trigger DNSBL “open resolver” warnings, especially with Spamhaus checks. If you use DNSBLs in production, make sure your recursive resolver and DNSBL access pattern are acceptable for the provider.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;10-accounts-and-passwords&quot;&gt;10. Accounts and Passwords&lt;/h2&gt;
&lt;p&gt;Create accounts in the admin UI at:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://mail.your-domain.com/admin/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Users can change their own account settings and password at:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://mail.your-domain.com/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also set account passwords from the CLI:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;%s\n&amp;#39; &amp;#39;NEW_PASSWORD&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/config/mox.conf setaccountpassword user&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use the account name without the domain if that is how the account exists in Mox.&lt;/p&gt;
&lt;h2 id=&quot;11-client-configuration&quot;&gt;11. Client Configuration&lt;/h2&gt;
&lt;p&gt;For IMAP clients:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Server: mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Port: 993&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TLS: IMAPS / implicit TLS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Username: full email address&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For SMTP clients:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Server: mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Port: 465&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TLS: implicit TLS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Username: full email address&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For &lt;code&gt;mbsync&lt;/code&gt;, Mox worked reliably with &lt;code&gt;PLAIN&lt;/code&gt; over IMAPS. The credentials are still protected by the TLS connection:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;IMAPStore user@your-domain.com-remote&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Host mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Port 993&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;User user@your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PassCmd &amp;quot;pass user@your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AuthMechs PLAIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TLSType IMAPS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CertificateFile /etc/ssl/certs/ca-certificates.crt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you see this with &lt;code&gt;AuthMechs LOGIN&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LOGIN unrecognized syntax/command: invalid escape char&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;switch to &lt;code&gt;AuthMechs PLAIN&lt;/code&gt;. Do not enable plaintext IMAP; &lt;code&gt;TLSType IMAPS&lt;/code&gt; must remain set.&lt;/p&gt;
&lt;h2 id=&quot;12-junk-training-and-introbox&quot;&gt;12. Junk Training and Introbox&lt;/h2&gt;
&lt;p&gt;Mox combines sender reputation with a per-account Bayesian junk filter. Authentication results such as SPF, DKIM, and DMARC establish sender identity, but an authenticated domain can still send spam. Correct user feedback is therefore essential.&lt;/p&gt;
&lt;p&gt;The generated account configuration commonly treats &lt;code&gt;Junk&lt;/code&gt; or &lt;code&gt;Spam&lt;/code&gt; as junk, &lt;code&gt;Inbox&lt;/code&gt; and technical mailboxes as neutral, and all remaining mailboxes as not-junk. That can be surprising: deleting spam into &lt;code&gt;Trash&lt;/code&gt; may teach the filter that the message is legitimate.&lt;/p&gt;
&lt;p&gt;For users who delete unwanted mail before classifying it, make &lt;code&gt;Trash&lt;/code&gt; neutral and enable an Introbox for first-time correspondents:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Accounts:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	user:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		Introbox: Introbox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		AutomaticJunkFlags:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			Enabled: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			JunkMailboxRegexp: ^(junk|spam)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			NeutralMailboxRegexp: ^(inbox|introbox|neutral|postmaster|dmarc|tlsrpt|rejects|trash)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the &lt;code&gt;Introbox&lt;/code&gt; mailbox in webmail or through IMAP before enabling it. With this configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Move actual spam to &lt;code&gt;Junk&lt;/code&gt;; moving it only to &lt;code&gt;Trash&lt;/code&gt; no longer trains the filter.&lt;/li&gt;
&lt;li&gt;Move legitimate messages incorrectly placed in &lt;code&gt;Junk&lt;/code&gt; to &lt;code&gt;Archive&lt;/code&gt; or explicitly mark them as not junk.&lt;/li&gt;
&lt;li&gt;Messages from first-time correspondents are separated in &lt;code&gt;Introbox&lt;/code&gt;. Moving a wanted message out of Introbox establishes positive reputation for future messages.&lt;/li&gt;
&lt;li&gt;Keep enough classified messages for useful training. Emptying all training mail immediately makes the content filter less effective.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After correcting classifications or changing junk-filter parameters, rebuild the account filter:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox retrain user&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            TRASH CAN POISON JUNK TRAINING
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;When &lt;code&gt;AutomaticJunkFlags&lt;/code&gt; is enabled and neither &lt;code&gt;Trash&lt;/code&gt; nor another mailbox matches the junk or neutral expressions, it can fall into the implicit not-junk category. Repeatedly deleting a spam campaign into that mailbox then gives its senders and vocabulary positive reputation. Inspect the &lt;code&gt;X-Mox-Reason&lt;/code&gt; header and Mox logs if obviously repetitive spam starts receiving &lt;code&gt;msgfromdomain&lt;/code&gt; or very low content-spam scores.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;13-migrating-from-mailcow&quot;&gt;13. Migrating from Mailcow&lt;/h2&gt;
&lt;p&gt;Do not blindly copy Mailcow/Dovecot files into Mox.&lt;/p&gt;
&lt;p&gt;Mailcow installations may use Dovecot plugins such as &lt;code&gt;mail_crypt&lt;/code&gt; and &lt;code&gt;zlib&lt;/code&gt;. In that case, the files in the Mailcow vmail volume can be encrypted or compressed in a Dovecot-specific format. Importing those raw files into Mox produces broken messages with binary-looking headers.&lt;/p&gt;
&lt;p&gt;Safer migration options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;IMAP-to-IMAP migration&lt;/strong&gt; with a tool such as &lt;code&gt;imapsync&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local decrypted Maildir import&lt;/strong&gt; from an existing &lt;code&gt;mbsync&lt;/code&gt; cache that was synced through Dovecot/IMAP before the migration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selective migration&lt;/strong&gt; of only active mailboxes and folders.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For a lightweight move, migrate active accounts and skip stale test folders. Keep the old Mailcow server stopped but preserved for a short rollback window.&lt;/p&gt;
&lt;h2 id=&quot;14-verification&quot;&gt;14. Verification&lt;/h2&gt;
&lt;p&gt;Web routes:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://mail.your-domain.com/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://autoconfig.your-domain.com/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://mta-sts.your-domain.com/.well-known/mta-sts.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IMAPS:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; s_client&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -connect&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com:993&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -servername&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -brief&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SMTPS:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; s_client&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -connect&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com:465&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -servername&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -brief&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Submission:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; s_client&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -starttls&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; smtp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -connect&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com:587&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -servername&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -brief&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SMTP delivery:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nc&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -vz&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 25&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, send mail to and from an external mailbox and check:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/config/mox.conf config dnscheck your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;15-backups-and-updates&quot;&gt;15. Backups and Updates&lt;/h2&gt;
&lt;p&gt;Do not replace a production binary first and hope that its data migration succeeds. Read the release notes for every version between the installed and target releases, then test the candidate against a disposable backup.&lt;/p&gt;
&lt;p&gt;Build the candidate from an explicit release tag:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox /home/mox/src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ! -d&lt;/span&gt;&lt;span&gt; /home/mox/src/mox/.git ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox git clone https://github.com/mjl-/mox.git /home/mox/src/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/src/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox git fetch&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags --force&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox git checkout&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --detach&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; vNEW.VERSION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox git show&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --no-patch --format=fuller&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox env CGO_ENABLED=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; go build&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -trimpath -ldflags=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;-s -w&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox.new .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox ./mox.new version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create and verify a dry-run backup with the currently installed binary, then inspect the same copy with the candidate:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox config test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox backup data/tmp/testupgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox verifydata data/tmp/testupgrade/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/src/mox/mox.new verifydata data/tmp/testupgrade/data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The candidate &lt;code&gt;verifydata&lt;/code&gt; may upgrade database files inside &lt;code&gt;testupgrade&lt;/code&gt;. Never use that modified dry-run directory as the rollback backup. Create a fresh backup with the old binary after the dry run succeeds:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox backup data/tmp/pre-upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox verifydata data/tmp/pre-upgrade/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mox ./mox.rollback&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install, restart, and verify:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0750 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  /home/mox/src/mox/mox.new /home/mox/mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl restart mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl is-active mox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/mox version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /home/mox/config/mox.conf config test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mox&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --since&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;5 minutes ago&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --no-pager -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; warning&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also include these locations in normal off-host backups:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/home/mox/config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/home/mox/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/home/mox/tls&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Mox works best as a real mail server with direct ownership of SMTP and IMAP. Traefik remains valuable for the browser-facing endpoints, but it should not hide the fact that mail delivery depends on DNS, reverse DNS, provider port policy, TLS on mail protocols, and careful migration of existing mail data.&lt;/p&gt;
&lt;a href=&quot;https://www.xmox.nl/docs/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;MOX DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/mjl-/mox&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;MOX GITHUB REPOSITORY&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Adding Authelia 2FA to Matrix Synapse with OpenID Connect</title>
          <pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/authelia-matrix-synapse-2fa/</link>
          <guid>https://criticalbasics.xyz/posts/authelia-matrix-synapse-2fa/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/authelia-matrix-synapse-2fa/">&lt;p&gt;Synapse does not provide native TOTP login for local Matrix passwords. It can, however, delegate interactive login to an OpenID Connect Provider. This guide connects Authelia to Synapse so a human Matrix login can require an Authelia password plus TOTP or WebAuthn.&lt;/p&gt;
&lt;p&gt;The difficult part is not the redirect. It is preserving the identity of an existing Matrix user. If automatic OIDC registration remains enabled, a careless first login can create a second account; a premature password shutdown can then lock you out of the original account. The migration below disables new OIDC registration and keeps the old login available until the mapping is proven.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Added Authelia OIDC, Element X compatibility warning, safe existing-account linking, E2EE-aware session cleanup, bot-token checks, rollback, and password-login cutover.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-read-this-compatibility-gate-first&quot;&gt;1. Read This Compatibility Gate First&lt;/h2&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            ELEMENT X REQUIRES A DIFFERENT ARCHITECTURE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;matrix-docker-ansible-deploy&lt;/code&gt; project currently warns that newer clients such as &lt;strong&gt;Element X support SSO only through Matrix Authentication Service (MAS), not through legacy Synapse OIDC&lt;/strong&gt;. The direct Synapse-to-Authelia setup in this article is suitable only if every required client supports Synapse’s legacy SSO flow, such as the compatible Element Web/Desktop path you have tested.&lt;/p&gt;
&lt;p&gt;If Element X is mandatory, stop here. Keep password login for now or design &lt;strong&gt;MAS with Authelia as its upstream OIDC Provider&lt;/strong&gt;. Do not discover the incompatibility after disabling passwords.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;This is the most important correction to the seemingly simple “Authelia → Synapse → disable passwords” plan. Authelia itself is not the compatibility problem; the client-facing Matrix authentication architecture is.&lt;/p&gt;
&lt;h2 id=&quot;2-prerequisites-and-scope&quot;&gt;2. Prerequisites and Scope&lt;/h2&gt;
&lt;p&gt;Complete these guides first:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../authelia-traefik-sso-2fa/&quot;&gt;Authelia with Docker Compose and Traefik&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../matrix-synapse-server/&quot;&gt;Deploying a Matrix Synapse Server with Docker and Traefik&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This article assumes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authelia is available at &lt;code&gt;https://auth.your-domain.com&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Synapse is available at &lt;code&gt;https://matrix.your-domain.com&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the Matrix ID to preserve is &lt;code&gt;@your-username:your-domain.com&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the Authelia username is exactly &lt;code&gt;your-username&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Synapse is managed by &lt;code&gt;matrix-docker-ansible-deploy&lt;/code&gt; in &lt;code&gt;/opt/containers/matrix&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the existing Matrix password login remains enabled during migration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The integration has four independent identifiers. Do not conflate them:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Matrix localpart&lt;/td&gt;&lt;td&gt;&lt;code&gt;your-username&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Left side of the existing Matrix ID.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OIDC &lt;code&gt;preferred_username&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;your-username&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Candidate localpart used only when linking/creating the Matrix user.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OIDC &lt;code&gt;sub&lt;/code&gt;&lt;/td&gt;&lt;td&gt;opaque stable value&lt;/td&gt;&lt;td&gt;Permanent external identity key stored by Synapse.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OIDC provider ID&lt;/td&gt;&lt;td&gt;&lt;code&gt;authelia&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Becomes &lt;code&gt;oidc-authelia&lt;/code&gt; in Synapse’s external-ID Admin API.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;sub&lt;/code&gt; claim does &lt;strong&gt;not&lt;/strong&gt; become the Matrix username. It is the opaque anchor that Synapse binds to the account after mapping. The mapping template uses &lt;code&gt;preferred_username&lt;/code&gt; to find the existing localpart.&lt;/p&gt;
&lt;h2 id=&quot;3-protect-the-existing-matrix-account-before-migration&quot;&gt;3. Protect the Existing Matrix Account Before Migration&lt;/h2&gt;
&lt;p&gt;Before changing authentication:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Confirm the exact Matrix ID in the currently logged-in client.&lt;/li&gt;
&lt;li&gt;Secure the Matrix recovery key or recovery phrase.&lt;/li&gt;
&lt;li&gt;Keep at least one verified, working Element session.&lt;/li&gt;
&lt;li&gt;Review the client/device list and record which sessions are yours.&lt;/li&gt;
&lt;li&gt;Create consistent backups of Synapse’s database and configuration.&lt;/li&gt;
&lt;li&gt;Back up the Authelia configuration, database, and secrets as one set.&lt;/li&gt;
&lt;li&gt;Test the required Matrix clients against a non-critical account if possible.&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DO NOT LOG OUT EVERY E2EE SESSION YET
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Matrix access tokens issued before 2FA remain valid until revoked, so they must eventually be reviewed. But blindly logging out every device can also remove the easiest route to verify a new session and recover encrypted history. First prove that account recovery and the OIDC login work; then revoke unknown or deliberately retired sessions.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;4-add-the-matrix-group-to-authelia&quot;&gt;4. Add the Matrix Group to Authelia&lt;/h2&gt;
&lt;p&gt;Edit &lt;code&gt;/opt/containers/authelia/config/users_database.yml&lt;/code&gt; and add a dedicated group to every human allowed to log in to Matrix:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;users&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  your-username&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    disabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    displayname&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Your Name&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;$argon2id$v=19$m=65536,t=3,p=4$YOUR-EXISTING-DIGEST&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    email&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;you@your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    groups&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;admins&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;synapse-users&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Synapse will require the &lt;code&gt;synapse-users&lt;/code&gt; claim, so an authenticated Authelia user outside this group still cannot use this OIDC client.&lt;/p&gt;
&lt;h2 id=&quot;5-generate-oidc-keys-and-the-client-secret&quot;&gt;5. Generate OIDC Keys and the Client Secret&lt;/h2&gt;
&lt;p&gt;Authelia needs an HMAC secret and at least one RSA signing key. Create them as protected files:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o 1000 -g 1000 -m 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null secrets/OIDC_HMAC_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 64&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee secrets/OIDC_HMAC_SECRET&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; openssl genrsa&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -out&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; secrets/OIDC_JWKS_RSA_PRIVATE_KEY&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 4096&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown 1000:1000 secrets/OIDC_JWKS_RSA_PRIVATE_KEY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; secrets/OIDC_JWKS_RSA_PRIVATE_KEY&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;1000:1000&lt;/code&gt; if the Authelia stack uses different &lt;code&gt;PUID&lt;/code&gt; and &lt;code&gt;PGID&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;Generate a random RFC 3986-safe plaintext client secret and its PBKDF2-SHA512 digest:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia/authelia:4.39.20&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  authelia crypto hash generate pbkdf2&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --variant&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sha512&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --random \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --random.length 72 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --random.charset&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rfc3986&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command prints two different values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Random Password:&lt;/strong&gt; the plaintext secret, stored on the Synapse side as &lt;code&gt;client_secret&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Digest:&lt;/strong&gt; the &lt;code&gt;$pbkdf2-sha512$...&lt;/code&gt; value, stored in Authelia’s client definition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not swap them. Save the plaintext directly in your secret manager; do not paste it into a chat, issue, or Git repository.&lt;/p&gt;
&lt;h2 id=&quot;6-enable-authelia-s-oidc-provider&quot;&gt;6. Enable Authelia’s OIDC Provider&lt;/h2&gt;
&lt;h3 id=&quot;6-1-enable-the-configuration-template-filter&quot;&gt;6.1. Enable the Configuration Template Filter&lt;/h3&gt;
&lt;p&gt;The official Authelia documentation recommends reading the private signing key from a file through its configuration template filter. Add these variables to the Authelia service in &lt;code&gt;/opt/containers/authelia/compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Keep all variables from the base Authelia guide.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  X_AUTHELIA_CONFIG_FILTERS&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;template&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /secrets/OIDC_HMAC_SECRET&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The existing read-only &lt;code&gt;./secrets:/secrets:ro&lt;/code&gt; mount makes both OIDC files available without baking them into the image.&lt;/p&gt;
&lt;h3 id=&quot;6-2-add-the-provider-and-synapse-client&quot;&gt;6.2. Add the Provider and Synapse Client&lt;/h3&gt;
&lt;p&gt;Append this block to &lt;code&gt;/opt/containers/authelia/config/configuration.yml&lt;/code&gt;. Replace the client digest with the &lt;strong&gt;Digest&lt;/strong&gt; from the previous section:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;identity_providers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  oidc&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    jwks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; algorithm&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;RS256&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        use&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;sig&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        key&lt;/span&gt;&lt;span&gt;: {{&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; secret &amp;quot;/secrets/OIDC_JWKS_RSA_PRIVATE_KEY&amp;quot; | mindent 10 &amp;quot;|&amp;quot; | msquote&lt;/span&gt;&lt;span&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    clients&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; client_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;synapse&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        client_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Synapse&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        client_secret&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;$pbkdf2-sha512$REPLACE-WITH-THE-DIGEST&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        public&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        authorization_policy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;two_factor&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        require_pkce&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        pkce_challenge_method&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        redirect_uris&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;https://matrix.your-domain.com/_synapse/client/oidc/callback&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        scopes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;openid&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;profile&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;email&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;groups&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        response_types&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;code&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        grant_types&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;authorization_code&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        access_token_signed_response_alg&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;none&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        userinfo_signed_response_alg&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;none&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        token_endpoint_auth_method&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;client_secret_basic&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;authorization_policy: &#39;two_factor&#39;&lt;/code&gt; is the hard Authelia policy for this OIDC client. A logged-in one-factor Authelia session alone is not sufficient to authorize Synapse.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHY PKCE IS DISABLED FOR THIS CLIENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This follows the current official Authelia/Synapse integration profile: Synapse is a confidential client authenticating with &lt;code&gt;client_secret_basic&lt;/code&gt;, while this integration does not use PKCE. Do not generalize this setting to public browser or mobile OIDC clients.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Validate and restart Authelia:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec authelia authelia config validate&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /config/configuration.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail=150&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check the discovery endpoint:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://auth.your-domain.com/.well-known/openid-configuration&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .issuer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It must report the exact HTTPS issuer URL used in the Synapse configuration.&lt;/p&gt;
&lt;h2 id=&quot;7-configure-synapse-oidc-without-disabling-passwords&quot;&gt;7. Configure Synapse OIDC Without Disabling Passwords&lt;/h2&gt;
&lt;p&gt;Edit:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/matrix/inventory/host_vars/matrix.your-domain.com/vars.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following variables. Replace the client secret with the &lt;strong&gt;Random Password&lt;/strong&gt; generated in section 5:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_synapse_oidc_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_synapse_oidc_providers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; idp_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;authelia&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    idp_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Authelia&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    discover&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    issuer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;https://auth.your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    client_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;synapse&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    client_secret&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;REPLACE-WITH-THE-RANDOM-PASSWORD&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    scopes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;openid&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;profile&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;email&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;groups&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    allow_existing_users&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    enable_registration&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    user_profile_method&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;userinfo_endpoint&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    user_mapping_provider&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      config&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        subject_template&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;{{ user.sub }}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        localpart_template&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;{{ user.preferred_username }}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        display_name_template&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;{{ user.name }}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        email_template&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;{{ user.email }}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    attribute_requirements&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; attribute&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;groups&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        value&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;synapse-users&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Keep local password login enabled throughout the migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_synapse_password_config_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Keep normal Matrix registration disabled as a second, global control.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_synapse_enable_registration&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;user_profile_method: &#39;userinfo_endpoint&#39;&lt;/code&gt; is the current Authelia-documented compatibility escape hatch for Synapse’s claim handling. The provider-level &lt;code&gt;enable_registration: false&lt;/code&gt; is distinct from the global Matrix setting and makes this OIDC flow sign-in-only.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            ALLOW_EXISTING_USERS IS POWERFUL
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;&lt;code&gt;allow_existing_users: true&lt;/code&gt; permits an OIDC identity whose mapped localpart matches a pre-existing Matrix user to bind to that account. This is necessary for the migration, but it also means control of Authelia’s usernames and claims is security-critical. Restrict the client to &lt;code&gt;synapse-users&lt;/code&gt;, keep public Matrix registration disabled, and do not let users claim another person’s &lt;code&gt;preferred_username&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Apply the playbook using the same Ansible environment and conventions as the main Matrix guide:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=install-all,start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point both OIDC and the original password login should be available.&lt;/p&gt;
&lt;h2 id=&quot;8-prove-the-existing-account-mapping&quot;&gt;8. Prove the Existing-Account Mapping&lt;/h2&gt;
&lt;h3 id=&quot;8-1-test-in-a-separate-browser-session&quot;&gt;8.1. Test in a Separate Browser Session&lt;/h3&gt;
&lt;p&gt;Keep the current verified Matrix client open. In a private browser window:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the compatible Element Web login page.&lt;/li&gt;
&lt;li&gt;Choose the Authelia SSO option.&lt;/li&gt;
&lt;li&gt;Complete the password and second factor.&lt;/li&gt;
&lt;li&gt;Check the Matrix ID after login.&lt;/li&gt;
&lt;li&gt;Confirm it is exactly &lt;code&gt;@your-username:your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm the expected joined rooms and account data are present.&lt;/li&gt;
&lt;li&gt;Verify the new E2EE session from the existing trusted session or recovery material.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Seeing an empty room list or a different Matrix ID means the mapping did not land on the existing account. Stop immediately and keep password login enabled.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            A WRONG MAPPING DOES NOT DELETE THE OLD ACCOUNT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;With this guide’s provider-level &lt;code&gt;enable_registration: false&lt;/code&gt;, an unknown mapping should fail instead of creating a new Matrix user. If automatic OIDC registration was enabled elsewhere and a mismatch created a separate account, it still did not erase the original one. A lockout happens only if you then disable the original login route or discard its remaining sessions. Correct the mapping and retry while the original account is still accessible.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;8-2-verify-the-external-id-with-synapse-s-admin-api&quot;&gt;8.2. Verify the External ID with Synapse’s Admin API&lt;/h3&gt;
&lt;p&gt;Use a Synapse administrator token without writing it into shell history:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;read -rsp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Synapse admin token: &amp;#39; SYNAPSE_ADMIN_TOKEN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -H&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Authorization: Bearer ${&lt;/span&gt;&lt;span&gt;SYNAPSE_ADMIN_TOKEN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;https://matrix.your-domain.com/_synapse/admin/v2/users/%40your-username%3Ayour-domain.com&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{name, external_ids}&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;unset&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; SYNAPSE_ADMIN_TOKEN&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result should show the original Matrix ID and an external entry resembling:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;auth_provider&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;oidc-authelia&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;external_id&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;an-opaque-stable-subject&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;external_id&lt;/code&gt; is Authelia’s &lt;code&gt;sub&lt;/code&gt;, not the username.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DO NOT PATCH THE SYNAPSE DATABASE WITH SQL
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Do not use an ad-hoc &lt;code&gt;INSERT INTO user_external_ids ...&lt;/code&gt; as the normal migration method. Synapse provides a supported User Admin API for external IDs. If manual pre-binding is genuinely necessary, use that API, preserve every existing account field and external ID from a preceding &lt;code&gt;GET&lt;/code&gt;, and take a database backup first. A partial &lt;code&gt;PUT&lt;/code&gt; can replace array-valued fields, so this is a break-glass procedure, not a copy-and-paste shortcut.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;9-review-sessions-without-losing-e2ee-recovery&quot;&gt;9. Review Sessions Without Losing E2EE Recovery&lt;/h2&gt;
&lt;p&gt;OIDC 2FA protects &lt;strong&gt;new interactive logins&lt;/strong&gt;. It does not retroactively add a second factor to existing Matrix access tokens.&lt;/p&gt;
&lt;p&gt;After the mapping and E2EE recovery path are proven:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review every Matrix device/session.&lt;/li&gt;
&lt;li&gt;Revoke unknown sessions immediately.&lt;/li&gt;
&lt;li&gt;Retire old sessions you no longer need.&lt;/li&gt;
&lt;li&gt;Keep enough verified sessions or recovery material to bootstrap new E2EE clients.&lt;/li&gt;
&lt;li&gt;If you require a strict clean cutover, revoke all pre-2FA human sessions only after the new OIDC session is verified and recovery has been tested.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;“Log out all other devices” is therefore a policy choice, not an automatic prerequisite. It closes old-token bypasses but must be sequenced around encrypted-session recovery.&lt;/p&gt;
&lt;h2 id=&quot;10-verify-bots-and-automation&quot;&gt;10. Verify Bots and Automation&lt;/h2&gt;
&lt;p&gt;Before disabling password login, verify that Hermes bots, bridges, and other automations use existing Matrix access tokens rather than logging in with a username and password.&lt;/p&gt;
&lt;p&gt;Disabling &lt;code&gt;password_config.enabled&lt;/code&gt; prevents new password logins; it does not invalidate already-issued access tokens. Token-authenticated bots should continue to work. However, if a bot token is later lost or revoked, the bot cannot obtain a replacement through password login while the feature is disabled. Document a recovery path, such as temporarily re-enabling password login under controlled conditions.&lt;/p&gt;
&lt;p&gt;Test each automation before and after the cutover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;receive an allowed Matrix message;&lt;/li&gt;
&lt;li&gt;send a reply;&lt;/li&gt;
&lt;li&gt;restart the bot and confirm it reconnects with the stored token;&lt;/li&gt;
&lt;li&gt;confirm Matrix user and room allowlists remain enforced.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;11-optional-disable-matrix-password-login&quot;&gt;11. Optional: Disable Matrix Password Login&lt;/h2&gt;
&lt;p&gt;Only continue after all of the following are true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;every required client is compatible with legacy Synapse OIDC;&lt;/li&gt;
&lt;li&gt;the OIDC login reaches the exact old Matrix ID;&lt;/li&gt;
&lt;li&gt;the Admin API shows &lt;code&gt;oidc-authelia&lt;/code&gt; on that account;&lt;/li&gt;
&lt;li&gt;E2EE recovery and session verification work;&lt;/li&gt;
&lt;li&gt;bot and bridge token authentication has been tested;&lt;/li&gt;
&lt;li&gt;a current rollback backup exists.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then change the playbook variable:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_synapse_password_config_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apply and test again:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=install-all,start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirm that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Authelia SSO still reaches the existing account.&lt;/li&gt;
&lt;li&gt;The second factor is required in a genuinely new Authelia session.&lt;/li&gt;
&lt;li&gt;Direct Matrix password login is rejected.&lt;/li&gt;
&lt;li&gt;Hermes and other token-based integrations still work after restart.&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccccff&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            📝 
            YOU MAY KEEP PASSWORD LOGIN AS A RECOVERY ROUTE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Running OIDC and local passwords in parallel is a valid compatibility phase, but the local password remains a 2FA bypass for new logins. If you keep it, treat it as an explicit risk decision: use a long unique password, tightly control who has one, monitor sessions, and periodically retest the OIDC path.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;12-rollback&quot;&gt;12. Rollback&lt;/h2&gt;
&lt;p&gt;If the cutover fails:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;matrix_synapse_password_config_enabled: true&lt;/code&gt; again.&lt;/li&gt;
&lt;li&gt;Re-apply the playbook.&lt;/li&gt;
&lt;li&gt;Use the retained verified session or local password to regain the original account.&lt;/li&gt;
&lt;li&gt;Do not delete the OIDC external-ID binding unless you have identified a mapping error.&lt;/li&gt;
&lt;li&gt;Inspect Synapse and Authelia logs before retrying.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; matrix-synapse.service&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --since&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;30 minutes ago&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --since=30m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If a separate account was accidentally created, deactivate it only after confirming that it is not the original account and contains no data you need.&lt;/p&gt;
&lt;h2 id=&quot;13-what-this-setup-protects&quot;&gt;13. What This Setup Protects&lt;/h2&gt;
&lt;p&gt;The final login path is:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Element Web/Desktop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Synapse ──OIDC redirect──&amp;gt; Authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ▲                         │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        │                         ├─ password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        └──── authorization code ─└─ TOTP or WebAuthn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This protects new human SSO logins against password-only compromise. It does not make the following disappear:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;already-issued Matrix access tokens;&lt;/li&gt;
&lt;li&gt;a compromised verified Element session;&lt;/li&gt;
&lt;li&gt;loss of the Matrix recovery key;&lt;/li&gt;
&lt;li&gt;an administrator who can change Authelia claims or Synapse mappings;&lt;/li&gt;
&lt;li&gt;a stolen bot token;&lt;/li&gt;
&lt;li&gt;application or host compromise.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is not a flaw in OIDC; it is the normal boundary between authentication, sessions, authorization, and host security.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Authelia can add real TOTP or WebAuthn enforcement to compatible Synapse SSO logins without replacing the existing Matrix account. The safe sequence is what matters: preserve E2EE recovery, enable OIDC alongside passwords, map &lt;code&gt;preferred_username&lt;/code&gt; to the exact existing localpart, verify the persistent &lt;code&gt;sub&lt;/code&gt; binding, review old tokens, test bots, and only then decide whether password login should disappear.&lt;/p&gt;
&lt;p&gt;For Element X, use the compatibility gate rather than forcing this legacy path: evaluate MAS with Authelia upstream or retain a supported login method.&lt;/p&gt;
&lt;a href=&quot;https://www.authelia.com/integration/openid-connect/clients/synapse/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL AUTHELIA + SYNAPSE GUIDE&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://element-hq.github.io/synapse/latest/openid.html&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔐&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;SYNAPSE OIDC DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-synapse.md&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🧩&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;MATRIX PLAYBOOK OIDC NOTES&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;../authelia-traefik-sso-2fa/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;↩️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;GENERAL AUTHELIA GUIDE&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Authelia with Docker Compose and Traefik: Lightweight SSO and 2FA</title>
          <pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/authelia-traefik-sso-2fa/</link>
          <guid>https://criticalbasics.xyz/posts/authelia-traefik-sso-2fa/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/authelia-traefik-sso-2fa/">&lt;p&gt;Authelia is a self-hosted authentication and authorization server. It can add a central login and a second factor to web applications through a reverse proxy, and it can act as an OpenID Connect (OIDC) Provider for applications with native SSO support.&lt;/p&gt;
&lt;p&gt;This guide builds a small, single-node Authelia deployment with Docker Compose, a file-based user directory, SQLite storage, SMTP notifications, and the Traefik stack used throughout this site. It is a practical fit for a personal server or a small trusted group; it is not a high-availability design.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Added a pinned Authelia deployment, Traefik ForwardAuth, TOTP/WebAuthn enrollment, secret files, testing, backups, and upgrade guidance.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-what-authelia-does-and-what-it-does-not-do&quot;&gt;1. What Authelia Does — and What It Does Not Do&lt;/h2&gt;
&lt;p&gt;Authelia provides two related integration modes:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Best for&lt;/th&gt;&lt;th&gt;How it works&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Traefik ForwardAuth&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Browser-based services without native OIDC&lt;/td&gt;&lt;td&gt;Traefik asks Authelia whether each request may pass.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenID Connect Provider&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Applications with native SSO support&lt;/td&gt;&lt;td&gt;The application redirects the user to Authelia and receives an identity token.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Both modes can share the same account and second-factor registration. That makes Authelia more useful than a Matrix-only authentication component: one instance can protect dashboards through ForwardAuth and also provide OIDC to services such as Synapse, Forgejo, or other compatible applications.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DO NOT PUT EVERY API BEHIND FORWARDAUTH
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;ForwardAuth is ideal for interactive browser applications. Native mobile clients, webhooks, CalDAV/CardDAV endpoints, and machine APIs may not understand a redirect to a login portal. Prefer the application’s native OIDC integration, a dedicated API token, or a narrowly scoped bypass rule for those endpoints.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Authelia strengthens the &lt;strong&gt;login path&lt;/strong&gt;. It does not revoke sessions that an application already issued, repair weak application permissions, replace backups, or make a compromised reverse proxy harmless.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Browser ──HTTPS──&amp;gt; Traefik ──ForwardAuth──&amp;gt; Authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                       │                       │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                       │ allowed               ├─ password file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                       ▼                       ├─ TOTP / WebAuthn state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 protected app                └─ SQLite + SMTP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OIDC-capable app ──redirect──&amp;gt; Authelia ──signed identity──&amp;gt; app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;2-prerequisites-and-design-choices&quot;&gt;2. Prerequisites and Design Choices&lt;/h2&gt;
&lt;p&gt;Complete the &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec guide&lt;/a&gt;&lt;/strong&gt; first. This article reuses its:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;external Docker network named &lt;code&gt;proxy&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;HTTPS entrypoint named &lt;code&gt;websecure&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;certificate resolver named &lt;code&gt;tls_resolver&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;security-headers@file&lt;/code&gt; and &lt;code&gt;crowdsec-bouncer@docker&lt;/code&gt; middlewares.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You also need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a DNS record such as &lt;code&gt;auth.your-domain.com&lt;/code&gt; pointing to the server;&lt;/li&gt;
&lt;li&gt;working SMTP credentials for registration and recovery messages;&lt;/li&gt;
&lt;li&gt;Docker Compose and OpenSSL;&lt;/li&gt;
&lt;li&gt;a password manager and an authenticator or security key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide pins &lt;strong&gt;Authelia 4.39.20&lt;/strong&gt;, the current release tested by the official Synapse integration guide at the time of writing. Review the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/authelia/authelia/releases&quot;&gt;Authelia releases&lt;/a&gt; before changing the pin.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHY SQLITE HERE?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Authelia supports SQLite for a single instance. It is simple and sufficient for this small deployment, but it prevents a multi-instance high-availability setup. Use PostgreSQL or MySQL if you later run multiple Authelia replicas.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;3-create-the-directory-structure&quot;&gt;3. Create the Directory Structure&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/authelia/{config,data,secrets}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; touch config/configuration.yml config/users_database.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config/configuration.yml config/users_database.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; secrets&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting layout is deliberately split by purpose:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/authelia/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── config/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── configuration.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── users_database.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── data/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── db.sqlite3             # created by Authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── secrets/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── RESET_PASSWORD_JWT_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── SESSION_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── STORAGE_ENCRYPTION_KEY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── SMTP_PASSWORD&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;4-create-the-environment-and-secret-files&quot;&gt;4. Create the Environment and Secret Files&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/authelia/.env&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;dotenv&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;AUTHELIA_HOST&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;auth.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;TZ&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;Europe/Vienna&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;PUID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;PGID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;PUID&lt;/code&gt; and &lt;code&gt;PGID&lt;/code&gt; with the account that owns the stack:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Align the bind-mount ownership with those values (replace &lt;code&gt;1000:1000&lt;/code&gt; if necessary):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1000:1000 config data secrets&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generate the three local cryptographic secrets without printing them to the terminal:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o 1000 -g 1000 -m 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null secrets/RESET_PASSWORD_JWT_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 64&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee secrets/RESET_PASSWORD_JWT_SECRET&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o 1000 -g 1000 -m 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null secrets/SESSION_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 64&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee secrets/SESSION_SECRET&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o 1000 -g 1000 -m 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null secrets/STORAGE_ENCRYPTION_KEY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 64&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee secrets/STORAGE_ENCRYPTION_KEY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o 1000 -g 1000 -m 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null secrets/SMTP_PASSWORD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano secrets/SMTP_PASSWORD&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enter only the SMTP password in the last file. Do not put a trailing explanation or username in it. The &lt;code&gt;-o&lt;/code&gt; and &lt;code&gt;-g&lt;/code&gt; values must stay aligned with &lt;code&gt;PUID&lt;/code&gt; and &lt;code&gt;PGID&lt;/code&gt;, otherwise the unprivileged container process cannot read the files.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            THE STORAGE ENCRYPTION KEY IS NOT DISPOSABLE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Back up &lt;code&gt;STORAGE_ENCRYPTION_KEY&lt;/code&gt; securely. Authelia encrypts sensitive database values with it, including TOTP material. Losing the key can make the corresponding database state unusable; leaking it weakens the protection of a stolen database.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;5-configure-authelia&quot;&gt;5. Configure Authelia&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/authelia/config/configuration.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;server&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;tcp://0.0.0.0:9091/&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;log&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  level&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;info&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;theme&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;dark&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;totp&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  disable&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  issuer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  period&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  skew&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;webauthn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  disable&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  display_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Your Domain&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;identity_validation&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  reset_password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    jwt_lifespan&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;5 minutes&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;authentication_backend&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  password_reset&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    disable&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  refresh_interval&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;5 minutes&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  file&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    path&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;/config/users_database.yml&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    watch&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      algorithm&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;argon2&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      argon2&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        variant&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;argon2id&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        iterations&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        memory&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 65536&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        parallelism&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        key_length&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        salt_length&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;access_control&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  default_policy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;deny&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  rules&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; domain&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;protected.your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      policy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;two_factor&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;session&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;authelia_session&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  same_site&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lax&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  inactivity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;5 minutes&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  expiration&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;1 hour&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  remember_me&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;1 month&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  cookies&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; domain&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      authelia_url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;https://auth.your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      default_redirection_url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;https://protected.your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;regulation&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  max_retries&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  find_time&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;2 minutes&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  ban_time&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;5 minutes&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;storage&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  local&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    path&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;/data/db.sqlite3&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;notifier&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  smtp&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;submission://mail.your-domain.com:587&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    username&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;authelia@your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    sender&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Authelia &amp;lt;authelia@your-domain.com&amp;gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    subject&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;[Authelia] {title}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The password, session, reset-token, and storage secrets are intentionally absent. Docker injects them from files in the next section.&lt;/p&gt;
&lt;p&gt;Adjust the session cookie domain to the parent domain shared by the portal and protected services. Never set it to a public suffix such as &lt;code&gt;.com&lt;/code&gt;. Add one sequential &lt;code&gt;access_control.rules&lt;/code&gt; entry per protected host or path; with &lt;code&gt;default_policy: deny&lt;/code&gt;, an unlisted destination remains closed.&lt;/p&gt;
&lt;h2 id=&quot;6-create-the-first-user&quot;&gt;6. Create the First User&lt;/h2&gt;
&lt;p&gt;Generate an Argon2id password digest interactively, so the plaintext password does not appear in shell history:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm -it&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia/authelia:4.39.20&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  authelia crypto hash generate argon2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy only the resulting &lt;code&gt;$argon2id$...&lt;/code&gt; digest into &lt;code&gt;/opt/containers/authelia/config/users_database.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;users&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  your-username&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    disabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    displayname&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Your Name&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;$argon2id$v=19$m=65536,t=3,p=4$REPLACE-WITH-YOUR-DIGEST&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    email&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;you@your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    groups&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;admins&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The username is security-sensitive when an application automatically links OIDC identities to existing accounts. Users must not be allowed to rename themselves to another person’s application username.&lt;/p&gt;
&lt;h2 id=&quot;7-create-the-docker-compose-stack&quot;&gt;7. Create the Docker Compose Stack&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/authelia/compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  authelia&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia/authelia:4.39.20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    container_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    user&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;${PUID}:${PGID}&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      TZ&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${TZ}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /secrets/RESET_PASSWORD_JWT_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      AUTHELIA_SESSION_SECRET_FILE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /secrets/SESSION_SECRET&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /secrets/STORAGE_ENCRYPTION_KEY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /secrets/SMTP_PASSWORD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./config:/config:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./data:/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./secrets:/secrets:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.enable=true&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.docker.network=proxy&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.authelia.rule=Host(`${AUTHELIA_HOST}`)&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.authelia.entrypoints=websecure&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.authelia.tls.certresolver=tls_resolver&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.authelia.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.services.authelia.loadbalancer.server.port=9091&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;      # Reusable ForwardAuth middleware. Do not add this middleware to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;      # the Authelia portal router itself, or you will create a loop.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.middlewares.authelia.forwardAuth.address=http://authelia:9091/api/authz/forward-auth&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.middlewares.authelia.forwardAuth.trustForwardHeader=true&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.middlewares.authelia.forwardAuth.maxResponseBodySize=8192&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  proxy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Validate the rendered Compose model before starting it:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail=100&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The container runs directly as the unprivileged UID/GID from &lt;code&gt;.env&lt;/code&gt;; its entrypoint never needs to start as root. It also has no host port and no Docker socket. Traefik reaches it only through the shared &lt;code&gt;proxy&lt;/code&gt; network.&lt;/p&gt;
&lt;h2 id=&quot;8-protect-a-web-service&quot;&gt;8. Protect a Web Service&lt;/h2&gt;
&lt;p&gt;Add the &lt;code&gt;authelia@docker&lt;/code&gt; middleware to an application’s Traefik router &lt;strong&gt;and&lt;/strong&gt; add a matching Authelia access-control rule.&lt;/p&gt;
&lt;p&gt;Example labels for &lt;code&gt;protected.your-domain.com&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.enable=true&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.docker.network=proxy&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.protected.rule=Host(`protected.your-domain.com`)&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.protected.entrypoints=websecure&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.protected.tls.certresolver=tls_resolver&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.routers.protected.middlewares=security-headers@file,crowdsec-bouncer@docker,authelia@docker&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;traefik.http.services.protected.loadbalancer.server.port=8080&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The corresponding rule already exists in the sample configuration:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;access_control&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  default_policy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;deny&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  rules&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; domain&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;protected.your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      policy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;two_factor&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart Authelia after changing the configuration:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose restart authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail=100&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            KEEP AUTHORIZATION IN THE APPLICATION TOO
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Authelia can decide who may reach a service, but the service should still enforce its own roles and permissions. Authentication proves identity; it does not automatically make every authenticated user an administrator.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;9-enroll-and-test-the-second-factor&quot;&gt;9. Enroll and Test the Second Factor&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;https://protected.your-domain.com&lt;/code&gt; in a private browser window.&lt;/li&gt;
&lt;li&gt;Sign in with the Authelia username and password.&lt;/li&gt;
&lt;li&gt;Use the portal to register TOTP or a WebAuthn security key.&lt;/li&gt;
&lt;li&gt;Confirm that the protected service is inaccessible without completing the second factor.&lt;/li&gt;
&lt;li&gt;Test logout and a new private window; an existing remembered session is not a valid 2FA test.&lt;/li&gt;
&lt;li&gt;Test the recovery email flow before depending on it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;TOTP is widely compatible. WebAuthn with a hardware security key or platform authenticator is generally more phishing-resistant. Register a second recovery-capable authenticator and store recovery material safely before removing any existing login route.&lt;/p&gt;
&lt;p&gt;Useful diagnostics:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://auth.your-domain.com/api/health&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail=200&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec authelia authelia config validate&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /config/configuration.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;10-backups-and-recovery&quot;&gt;10. Backups and Recovery&lt;/h2&gt;
&lt;p&gt;Back up these items together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;config/configuration.yml&lt;/code&gt; and &lt;code&gt;config/users_database.yml&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the complete &lt;code&gt;secrets/&lt;/code&gt; directory;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data/db.sqlite3&lt;/code&gt; using an application-consistent snapshot;&lt;/li&gt;
&lt;li&gt;the pinned &lt;code&gt;compose.yml&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;your SMTP and DNS recovery procedure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An encrypted off-host backup is the real disaster-recovery copy. A second copy on the same filesystem does not protect against disk loss, ransomware, or a destructive administrative error.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            RESTORE AS A SET
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The database and its storage encryption key belong together. Restoring only one side can leave TOTP registrations and other encrypted state unreadable. Test a restore into an isolated environment before you need it.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;11-safe-upgrades&quot;&gt;11. Safe Upgrades&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Read the Authelia release notes and configuration changes.&lt;/li&gt;
&lt;li&gt;Create a consistent, encrypted backup.&lt;/li&gt;
&lt;li&gt;Change the image pin deliberately; do not switch production to &lt;code&gt;latest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pull, validate, and recreate the service.&lt;/li&gt;
&lt;li&gt;Test password login, the second factor, SMTP, ForwardAuth, and every OIDC client.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose pull authelia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail=100&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; authelia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;12-extending-authelia-with-oidc&quot;&gt;12. Extending Authelia with OIDC&lt;/h2&gt;
&lt;p&gt;ForwardAuth is only half of the design. Applications with native OIDC support should normally use it, because their browser and API flows remain application-aware.&lt;/p&gt;
&lt;p&gt;The next guide applies this to an existing Matrix account without accidentally creating a second Matrix identity: &lt;strong&gt;&lt;a href=&quot;../authelia-matrix-synapse-2fa/&quot;&gt;Adding Authelia 2FA to Matrix Synapse with OpenID Connect&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now have a compact central authentication service that can enforce TOTP or WebAuthn for browser applications and later serve native OIDC clients. The useful security boundary is not the login page alone: keep the Traefik routing, Authelia policy, application permissions, existing sessions, secrets, and backups aligned.&lt;/p&gt;
&lt;a href=&quot;https://www.authelia.com/integration/deployment/docker/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;AUTHELIA DOCKER DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://www.authelia.com/integration/proxies/traefik/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔐&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;TRAEFIK INTEGRATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;../authelia-matrix-synapse-2fa/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;💬&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;AUTHELIA + MATRIX GUIDE&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Self-Hosting Tandoor Recipes with Docker Compose and Traefik</title>
          <pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/tandoor-recipes/</link>
          <guid>https://criticalbasics.xyz/posts/tandoor-recipes/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/tandoor-recipes/">&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://tandoor.dev/&quot;&gt;Tandoor Recipes&lt;/a&gt;&lt;/strong&gt; is a self-hosted recipe manager with meal planning, shopping lists, cookbooks, recipe imports, sharing, and a mobile-friendly Progressive Web App. It is designed for private households and small groups rather than as a public recipe website.&lt;/p&gt;
&lt;p&gt;This guide deploys Tandoor in an existing &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec Docker ecosystem&lt;/a&gt;&lt;/strong&gt;. It stays close to Tandoor’s official Traefik Compose example: PostgreSQL runs as &lt;code&gt;db_recipes&lt;/code&gt;, the application runs as &lt;code&gt;web_recipes&lt;/code&gt;, static files use a Docker volume, and recipe images are stored in a bind-mounted &lt;code&gt;mediafiles&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;The only deliberate additions are version pinning, a PostgreSQL healthcheck, the existing &lt;code&gt;proxy&lt;/code&gt; network, and the Traefik labels required by our stack.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            TANDOOR 2 ARCHITECTURE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Tandoor 2 includes its own Nginx server and exposes container port &lt;code&gt;80&lt;/code&gt;. Do not add the separate Nginx container found in older Tandoor 1 guides. Traefik connects directly to &lt;code&gt;web_recipes:80&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-12&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Tandoor 2.6.9 with PostgreSQL 16, Traefik v3, CrowdSec, trusted-proxy configuration, and backups.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-architecture&quot;&gt;1. Architecture&lt;/h2&gt;
&lt;p&gt;The finished deployment has only one public path:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Internet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   | HTTPS :443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Traefik + CrowdSec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   | Docker network: proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;web_recipes:80 (Tandoor + built-in Nginx)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   | Private Compose network&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;db_recipes:5432 (PostgreSQL 16)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PostgreSQL is not attached to the shared &lt;code&gt;proxy&lt;/code&gt; network and publishes no host port. Tandoor also publishes no host port; only Traefik can reach it through Docker.&lt;/p&gt;
&lt;p&gt;This guide pins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tandoor &lt;code&gt;2.6.9&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL &lt;code&gt;16-alpine&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pinning Tandoor makes updates deliberate and prevents an unattended &lt;code&gt;latest&lt;/code&gt; pull from applying irreversible database migrations. Tandoor explicitly warns that database downgrades are not supported.&lt;/p&gt;
&lt;h2 id=&quot;2-prerequisites&quot;&gt;2. Prerequisites&lt;/h2&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec stack&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Docker and Docker Compose.&lt;/li&gt;
&lt;li&gt;The external Docker network named &lt;code&gt;proxy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A DNS &lt;code&gt;A&lt;/code&gt; and/or &lt;code&gt;AAAA&lt;/code&gt; record for &lt;code&gt;recipes.criticalbasics.xyz&lt;/code&gt; pointing to the server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openssl&lt;/code&gt; for secret generation.&lt;/li&gt;
&lt;li&gt;Root or &lt;code&gt;sudo&lt;/code&gt; access.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Verify the shared network:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; network inspect proxy&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-directory-structure&quot;&gt;3. Directory Structure&lt;/h2&gt;
&lt;p&gt;Create a dedicated directory for the stack:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor/{postgresql,mediafiles}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting persistent layout is:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/tandoor/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── docker-compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── mediafiles/       # Recipe images and uploaded files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── postgresql/       # PostgreSQL 16 data directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Static application assets live in the Docker volume &lt;code&gt;tandoor_staticfiles&lt;/code&gt;. They are rebuilt by Tandoor during startup and do not contain user-created recipe data.&lt;/p&gt;
&lt;h2 id=&quot;4-generate-secrets&quot;&gt;4. Generate Secrets&lt;/h2&gt;
&lt;p&gt;Generate two independent, shell-safe secrets:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TANDOOR_SECRET_KEY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Tandoor secret:  &lt;/span&gt;&lt;span&gt;$TANDOOR_SECRET_KEY&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Database secret: &lt;/span&gt;&lt;span&gt;$POSTGRES_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Django &lt;code&gt;SECRET_KEY&lt;/code&gt; must be at least 50 characters and must remain stable for the lifetime of the instance. Save both values in a password manager before continuing.&lt;/p&gt;
&lt;h2 id=&quot;5-environment-file&quot;&gt;5. Environment File&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/tandoor/.env&lt;/code&gt; with restrictive permissions:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano .env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use the following configuration and insert the secrets generated above:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Required Tandoor settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SECRET_KEY=REPLACE_WITH_TANDOOR_SECRET_KEY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TZ=Europe/Berlin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ALLOWED_HOSTS=recipes.criticalbasics.xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CSRF_TRUSTED_ORIGINS=https://recipes.criticalbasics.xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Tandoor 2 includes its own nginx. Traefik is the second trusted proxy.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TANDOOR_PORT=80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ALLAUTH_TRUSTED_PROXY_COUNT=2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ENABLE_SIGNUP=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# PostgreSQL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DB_ENGINE=django.db.backends.postgresql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_HOST=db_recipes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_DB=djangodb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_PORT=5432&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_USER=djangouser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_PASSWORD=REPLACE_WITH_POSTGRES_PASSWORD&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;why-allauth-trusted-proxy-count-2&quot;&gt;Why &lt;code&gt;ALLAUTH_TRUSTED_PROXY_COUNT=2&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;Tandoor applies IP-based rate limits to login, signup, and password-reset requests. The request passes through two proxies before reaching Django:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The external Traefik reverse proxy.&lt;/li&gt;
&lt;li&gt;Tandoor’s built-in Nginx server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The default value of &lt;code&gt;1&lt;/code&gt; accounts only for the built-in Nginx server. Behind Traefik it can produce login failures or HTTP 403 responses because Tandoor selects the wrong address from &lt;code&gt;X-Forwarded-For&lt;/code&gt;. Therefore this deployment must use &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            PROTECT THE ENVIRONMENT FILE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file contains both the Django signing key and the database password. Keep it at mode &lt;code&gt;0600&lt;/code&gt;, never commit it to Git, and include it in encrypted off-server backups.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;6-docker-compose&quot;&gt;6. Docker Compose&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/tandoor/docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  db_recipes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; always&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres:16-alpine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./postgresql:/var/lib/postgresql/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    env_file&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./.env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    healthcheck&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      test&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;CMD-SHELL&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      interval&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 10s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      timeout&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 5s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      retries&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      start_period&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 20s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  web_recipes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; always&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; vabene1111/recipes:2.6.9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    env_file&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./.env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; staticfiles:/opt/recipes/staticfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./mediafiles:/opt/recipes/mediafiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    depends_on&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      db_recipes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        condition&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; service_healthy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.tandoor.rule=Host(`recipes.criticalbasics.xyz`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.tandoor.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.tandoor.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.tandoor.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.tandoor.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  default&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  proxy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  staticfiles&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is intentionally close to the upstream Traefik Compose example. The important local adaptations are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vabene1111/recipes:2.6.9&lt;/code&gt; instead of an unpinned image.&lt;/li&gt;
&lt;li&gt;A database healthcheck and health-based startup dependency.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proxy&lt;/code&gt; instead of the generic upstream Traefik network name.&lt;/li&gt;
&lt;li&gt;The router, TLS resolver, security-header, and CrowdSec labels used by our existing stack.&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;ports:&lt;/code&gt; section. Traefik reaches Tandoor directly over the Docker network.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Validate the merged configuration without printing the secrets:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;7-launch-the-stack&quot;&gt;7. Launch the Stack&lt;/h2&gt;
&lt;p&gt;Pull the pinned images and start the stack:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The expected services are:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tandoor-db_recipes-1     postgres:16-alpine         healthy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tandoor-web_recipes-1    vabene1111/recipes:2.6.9   running&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Monitor the first startup:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web_recipes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tandoor waits for PostgreSQL, applies all Django migrations, collects static files, and finally starts Gunicorn. Exit the log view with &lt;code&gt;CTRL+C&lt;/code&gt; after you see:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Database is ready&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Migrating database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Collecting static files, this may take a while...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Starting gunicorn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            TEMPORARY 502 DURING FIRST STARTUP
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Tandoor starts its internal Nginx before database migrations and Gunicorn are ready. Traefik may therefore return HTTP 502 for a short time during the first launch. This is expected. Do not delete the database or restart repeatedly; wait for the migration and static-file steps to finish.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;8-create-the-first-user&quot;&gt;8. Create the First User&lt;/h2&gt;
&lt;p&gt;Open:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://recipes.criticalbasics.xyz/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the database contains no users, Tandoor automatically redirects to &lt;code&gt;/setup/&lt;/code&gt;. Create the first account there. This account becomes the instance superuser.&lt;/p&gt;
&lt;p&gt;The setting &lt;code&gt;ENABLE_SIGNUP=0&lt;/code&gt; does not block this one-time setup page. After the first user exists, &lt;code&gt;/setup/&lt;/code&gt; can no longer create another account. Create additional household members from Tandoor’s space settings using invite links.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            CREATE THE FIRST ACCOUNT PROMPTLY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The initial setup form is publicly reachable until the first account exists. Create the superuser immediately after deployment and use a unique, strong password.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;9-verification&quot;&gt;9. Verification&lt;/h2&gt;
&lt;h3 id=&quot;9-1-https-and-redirects&quot;&gt;9.1. HTTPS and Redirects&lt;/h3&gt;
&lt;p&gt;Check the public route:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://recipes.criticalbasics.xyz/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; http://recipes.criticalbasics.xyz/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before the first account is created, HTTPS should return &lt;code&gt;302&lt;/code&gt; with &lt;code&gt;location: /setup/&lt;/code&gt;. Plain HTTP should return a permanent redirect to HTTPS.&lt;/p&gt;
&lt;h3 id=&quot;9-2-security-headers&quot;&gt;9.2. Security Headers&lt;/h3&gt;
&lt;p&gt;The HTTPS response should include headers such as:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;strict-transport-security: max-age=31536000; includeSubDomains; preload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;x-content-type-options: nosniff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;x-frame-options: DENY&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These come from the shared &lt;code&gt;security-headers@file&lt;/code&gt; Traefik middleware.&lt;/p&gt;
&lt;h3 id=&quot;9-3-database-health&quot;&gt;9.3. Database Health&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec db_recipes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  pg_isready&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; djangouser&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; djangodb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Expected output:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/var/run/postgresql:5432 - accepting connections&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9-4-confirm-the-image-version&quot;&gt;9.4. Confirm the Image Version&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose images&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirm that &lt;code&gt;web_recipes&lt;/code&gt; uses &lt;code&gt;vabene1111/recipes:2.6.9&lt;/code&gt; and the database remains on PostgreSQL major version 16.&lt;/p&gt;
&lt;h2 id=&quot;10-optional-email-configuration&quot;&gt;10. Optional Email Configuration&lt;/h2&gt;
&lt;p&gt;Tandoor works without SMTP, but password-reset emails require a mail server. Add the following variables to &lt;code&gt;.env&lt;/code&gt; if needed:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EMAIL_HOST=mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EMAIL_PORT=587&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EMAIL_HOST_USER=tandoor@your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EMAIL_HOST_PASSWORD=REPLACE_WITH_MAILBOX_PASSWORD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EMAIL_USE_TLS=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EMAIL_USE_SSL=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DEFAULT_FROM_EMAIL=&amp;quot;Tandoor Recipes &amp;lt;tandoor@your-domain.com&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recreate the application container after changing the environment:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --force-recreate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web_recipes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use either STARTTLS on port 587 or implicit TLS on port 465, never both &lt;code&gt;EMAIL_USE_TLS=1&lt;/code&gt; and &lt;code&gt;EMAIL_USE_SSL=1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;11-backups-and-restore&quot;&gt;11. Backups and Restore&lt;/h2&gt;
&lt;p&gt;Tandoor stores user data in two places:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PostgreSQL: recipes, users, meal plans, shopping lists, and settings.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mediafiles&lt;/code&gt;: recipe images and uploaded files.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file must also be preserved because it contains the stable Django secret key and database credentials.&lt;/p&gt;
&lt;h3 id=&quot;11-1-create-a-backup&quot;&gt;11.1. Create a Backup&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; backups&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Logical PostgreSQL backup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; db_recipes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  pg_dump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; djangouser&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; djangodb&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -Fc \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee &amp;quot;backups/tandoor-db-$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F).dump&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Media, Compose file, and encrypted-secret source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -czf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; backups/tandoor-files-&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.tar.gz&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mediafiles docker-compose.yml .env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy the resulting files to encrypted off-server storage. A backup that only remains on the VPS is not sufficient.&lt;/p&gt;
&lt;h3 id=&quot;11-2-restore-the-database&quot;&gt;11.2. Restore the Database&lt;/h3&gt;
&lt;p&gt;Stop the web application while keeping PostgreSQL running:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose stop web_recipes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; db_recipes&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  pg_restore&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; djangouser&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; djangodb&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --clean --if-exists \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; backups/tandoor-db-YYYY-MM-DD.dump&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose start web_recipes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restore the &lt;code&gt;mediafiles&lt;/code&gt; directory from its matching archive before starting the web service. Always test the complete restore procedure before relying on a backup strategy.&lt;/p&gt;
&lt;h2 id=&quot;12-updating-tandoor&quot;&gt;12. Updating Tandoor&lt;/h2&gt;
&lt;p&gt;Read the Tandoor release notes before every update. Database migrations can move forward automatically, but Tandoor does not support automatic database downgrades.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create and copy an off-server backup.&lt;/li&gt;
&lt;li&gt;Change the pinned image tag in &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pull and recreate the stack:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose down&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web_recipes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not change the PostgreSQL major version as part of a routine Tandoor update. PostgreSQL data directories are not directly compatible across major versions; use a logical dump and restore for a major database upgrade.&lt;/p&gt;
&lt;h2 id=&quot;13-troubleshooting&quot;&gt;13. Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;http-502-after-deployment&quot;&gt;HTTP 502 after deployment&lt;/h3&gt;
&lt;p&gt;Check whether migrations and static-file collection are still running:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tail=200&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web_recipes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On first start, wait several minutes before treating a 502 response as an error.&lt;/p&gt;
&lt;h3 id=&quot;http-403-when-logging-in&quot;&gt;HTTP 403 when logging in&lt;/h3&gt;
&lt;p&gt;Confirm this exact setting in &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ALLAUTH_TRUSTED_PROXY_COUNT=2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then recreate the application container:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --force-recreate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web_recipes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;csrf-errors-or-incorrect-redirects&quot;&gt;CSRF errors or incorrect redirects&lt;/h3&gt;
&lt;p&gt;Verify:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ALLOWED_HOSTS=recipes.criticalbasics.xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CSRF_TRUSTED_ORIGINS=https://recipes.criticalbasics.xyz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also confirm that the Traefik router uses the same hostname and the &lt;code&gt;websecure&lt;/code&gt; entrypoint.&lt;/p&gt;
&lt;h3 id=&quot;recipe-images-are-missing&quot;&gt;Recipe images are missing&lt;/h3&gt;
&lt;p&gt;Verify the media mount and filesystem:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec web_recipes ls&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -ld&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/recipes/mediafiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ls&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -ld&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/tandoor/mediafiles&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not remove or replace the &lt;code&gt;mediafiles&lt;/code&gt; directory during updates.&lt;/p&gt;
&lt;h3 id=&quot;crowdsec-blocks-a-legitimate-client&quot;&gt;CrowdSec blocks a legitimate client&lt;/h3&gt;
&lt;p&gt;Inspect current decisions in the Traefik stack:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec crowdsec cscli decisions list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The normal deployment keeps CrowdSec enabled. Only remove &lt;code&gt;crowdsec-bouncer@docker&lt;/code&gt; from the Tandoor router after confirming a persistent false positive and understanding the security tradeoff.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Tandoor Recipes is now running as a small, maintainable two-service stack. PostgreSQL and recipe media are persistent, the database remains private, and all public traffic passes through the existing Traefik TLS and CrowdSec security layer.&lt;/p&gt;
&lt;p&gt;By staying close to the official Compose layout, future Tandoor documentation and release notes remain directly applicable, while version pinning, trusted-proxy configuration, tested backups, and explicit Traefik labels make the setup appropriate for a production VPS.&lt;/p&gt;
&lt;a href=&quot;https://docs.tandoor.dev/install/docker/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL TANDOOR DOCKER DOCS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/TandoorRecipes/recipes&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;TANDOOR RECIPES ON GITHUB&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Essential Initial Setup for a Secure Debian Server</title>
          <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/debian-server-initial-setup/</link>
          <guid>https://criticalbasics.xyz/posts/debian-server-initial-setup/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/debian-server-initial-setup/">&lt;p&gt;Welcome to the essential security guide for any new Debian server. A fresh installation is a blank slate, and taking the right steps immediately after setup is crucial for protecting your server from threats. This guide provides a logical, step-by-step process to establish a strong security baseline.&lt;/p&gt;
&lt;p&gt;We will cover user management, hardening SSH access, configuring a firewall, setting up automatic intrusion prevention, and enabling automatic security updates.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            FOLLOW THE ORDER
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;These steps are designed to be followed sequentially. For example, we will set up SSH key authentication &lt;em&gt;before&lt;/em&gt; disabling password logins to ensure you don’t lock yourself out.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;Added rsyslog/UFW logging notes and clarified Docker firewall caveats.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-03-03&lt;/td&gt;&lt;td&gt;Comprehensive update: hardened SSH config, added backup strategy, monitoring, and WireGuard.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-07-10&lt;/td&gt;&lt;td&gt;Initial version of the comprehensive Debian hardening guide.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-1-initial-login-update-and-hostname&quot;&gt;Step 1: Initial Login, Update and Hostname&lt;/h2&gt;
&lt;p&gt;First, log into your new server as the &lt;code&gt;root&lt;/code&gt; user. Your cloud provider will have supplied you with the initial IP address and password.&lt;/p&gt;
&lt;p&gt;The very first action should always be to update the package list and upgrade all installed packages. For a fresh server, we use &lt;code&gt;full-upgrade&lt;/code&gt; to ensure even kernel updates and new dependencies are handled.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Log in as root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root@your_server_ip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Update package lists&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;apt&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Upgrade all installed packages (including kernel updates)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;apt&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; full-upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Reboot to ensure the new kernel and all updates are active&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;reboot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the reboot, log back in. It’s best practice to set the hostname immediately so all subsequent logs reflect the correct name.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Set your server&amp;#39;s hostname&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hostnamectl set-hostname my-awesome-server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should also edit &lt;code&gt;/etc/hosts&lt;/code&gt; to associate the new hostname with &lt;code&gt;127.0.1.1&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-2-create-a-dedicated-admin-user&quot;&gt;Step 2: Create a Dedicated Admin User&lt;/h2&gt;
&lt;p&gt;Operating directly as the &lt;code&gt;root&lt;/code&gt; user is risky. We will create a new user account with administrative privileges via the &lt;code&gt;sudo&lt;/code&gt; command. This improves security and provides better auditing.&lt;/p&gt;
&lt;p&gt;Replace &lt;code&gt;adminuser&lt;/code&gt; with a username of your choice.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create a new user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;adduser&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; adminuser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# You will be prompted to set a password and fill in user information.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add the new user to the &amp;#39;sudo&amp;#39; group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;usermod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -aG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sudo adminuser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Log out from the root session&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;exit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            SUDO PASSWORD SECURITY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;By default, &lt;code&gt;sudo&lt;/code&gt; will ask for your user password before executing administrative commands. Do not configure &lt;code&gt;NOPASSWD&lt;/code&gt; for your admin user. This password prompt prevents accidental destructive commands and is an additional authentication layer if your SSH session is compromised.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;From now on, you will log in as this new user and prefix any administrative commands with &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-3-harden-ssh-access&quot;&gt;Step 3: Harden SSH Access&lt;/h2&gt;
&lt;p&gt;Securing SSH is the single most effective thing you can do to protect your server. While we will change the default port to reduce log noise from automated scanners, the real security comes from key-only authentication and the hardening settings below.&lt;/p&gt;
&lt;h3 id=&quot;3-1-set-up-ssh-key-authentication&quot;&gt;3.1. Set Up SSH Key Authentication&lt;/h3&gt;
&lt;p&gt;SSH keys are far more secure than passwords. A key pair consists of a private key (which you keep on your local computer) and a public key (which you place on the server).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On your local computer (not the server):&lt;/strong&gt;
If you don’t have an SSH key pair yet, generate one. The &lt;code&gt;ed25519&lt;/code&gt; algorithm is modern and highly secure.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# This command is run on your local machine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh-keygen&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ed25519&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;your_email@example.com&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Press Enter to accept the default file location and set an optional (but recommended) passphrase for your key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Copy your public key to the server:&lt;/strong&gt;
The &lt;code&gt;ssh-copy-id&lt;/code&gt; command is the easiest way to do this. It will automatically add your public key to the correct file on the server.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Replace with your new username and server IP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh-copy-id&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; adminuser@your_server_ip&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this, you should be able to log into your server as &lt;code&gt;adminuser&lt;/code&gt; without being asked for a password (you might be asked for your key’s passphrase if you set one).&lt;/p&gt;
&lt;h3 id=&quot;3-2-configure-and-secure-the-ssh-daemon&quot;&gt;3.2. Configure and Secure the SSH Daemon&lt;/h3&gt;
&lt;p&gt;Now we will edit the main SSH configuration file to improve security.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DO NOT CLOSE YOUR TERMINAL!
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Keep your current SSH session open while performing these steps. If you make a mistake, you can revert the changes. Only close the terminal after you have successfully tested the new login method in a separate terminal window.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Open the configuration file with a text editor:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; vim /etc/ssh/sshd_config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the following changes to harden the configuration:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Change port (optional, reduces log noise from bots)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Port&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 8496&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Authentication&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;PermitRootLogin&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;PasswordAuthentication&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;PubkeyAuthentication&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;MaxAuthTries&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;LoginGraceTime&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Restrict to specific user(s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AllowUsers&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; adminuser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Disable unnecessary features&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;X11Forwarding&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AllowTcpForwarding&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AllowAgentForwarding&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Restrict key algorithms to modern, secure options&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;PubkeyAcceptedAlgorithms&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ssh-ed25519,sk-ssh-ed25519@openssh.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key explanations for these options:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MaxAuthTries 3&lt;/strong&gt; — Limits login attempts per connection to 3.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LoginGraceTime 30&lt;/strong&gt; — Disconnects after 30 seconds without successful authentication.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AllowUsers adminuser&lt;/strong&gt; — Only the specified user(s) can log in via SSH.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X11Forwarding no&lt;/strong&gt; — Disables GUI forwarding, reducing attack surface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AllowTcp/AgentForwarding no&lt;/strong&gt; — Prevents SSH tunneling and potential agent exploitation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PubkeyAcceptedAlgorithms&lt;/strong&gt; — Restricts to Ed25519 and FIDO2/Hardware keys (YubiKey).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Save the file and exit the editor.&lt;/p&gt;
&lt;h3 id=&quot;3-3-test-and-restart-ssh&quot;&gt;3.3. Test and Restart SSH&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            CRITICAL: TEST BEFORE RESTART
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Always validate your configuration before restarting the SSH daemon. A syntax error can lead to a permanent lockout.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ALWAYS test configuration before restarting&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sshd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Only if no errors are shown, restart the service:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl restart sshd.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, &lt;strong&gt;open a new terminal window&lt;/strong&gt; and try to connect using the new port and your key.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Use your username, IP, and the new port number&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; adminuser@your_server_ip&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p 8496&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the login is successful, your SSH hardening is complete. You can now safely close the old terminal window.&lt;/p&gt;
&lt;h2 id=&quot;step-4-configure-a-firewall-with-ufw&quot;&gt;Step 4: Configure a Firewall with UFW&lt;/h2&gt;
&lt;p&gt;A firewall is essential for controlling network traffic. We will use UFW (Uncomplicated Firewall) because it is user-friendly and effective.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Install UFW&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install ufw&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will set up some basic rules. By default, we will deny all incoming traffic and allow all outgoing traffic. Then we will explicitly allow traffic for the services we need.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Set default policies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw default deny incoming&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw default allow outgoing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Allow standard web traffic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow http&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Port 80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow https&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Port 443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# IMPORTANT: Allow your new SSH port&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# We use &amp;#39;limit&amp;#39; to help protect against brute-force attacks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw limit 8496/tcp&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Use the port you chose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, enable the firewall. It will ask for confirmation to proceed.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw enable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check the status of the firewall at any time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw status verbose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            CLOUD FIREWALL
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Cloud providers like Hetzner, DigitalOcean, or AWS offer cloud-level firewalls in their web panel. These filter traffic before it reaches your server. If available, mirror your UFW rules there as an additional layer.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DOCKER AND UFW
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Docker publishes ports by adding its own iptables/nftables rules. UFW is still useful, but it should not be treated as the only network boundary for a Docker host. Prefer publishing only the reverse proxy ports (&lt;code&gt;80&lt;/code&gt; and &lt;code&gt;443&lt;/code&gt;) and keep application containers on internal Docker networks unless a service truly needs direct host ports.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-5-prevent-intrusion-with-fail2ban&quot;&gt;Step 5: Prevent Intrusion with Fail2Ban&lt;/h2&gt;
&lt;p&gt;With key-only SSH authentication, brute-force attacks against SSH are already neutralized. So why Fail2Ban? Because your server will likely run more than SSH. Once you deploy a web server, mail server, or other services, Fail2Ban protects those too. It is a general-purpose intrusion prevention tool.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Install Fail2Ban&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install fail2ban&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fail2Ban’s configuration should be done in a local file, which overrides the default settings without being changed during package updates.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create a local configuration file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, edit the new local file to configure it for our custom SSH port.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; vim /etc/fail2ban/jail.local&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Find the &lt;code&gt;[sshd]&lt;/code&gt; section. Most settings can be left as default, but you must update the &lt;code&gt;port&lt;/code&gt; to match your custom SSH port and ensure it’s enabled.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[sshd]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;enabled&lt;/span&gt;&lt;span&gt;  = true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;port&lt;/span&gt;&lt;span&gt;     = 8496&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;maxretry&lt;/span&gt;&lt;span&gt; = 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;bantime&lt;/span&gt;&lt;span&gt;  = 1h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;findtime&lt;/span&gt;&lt;span&gt; = 10m&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save the file and restart Fail2Ban to apply the changes.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl restart fail2ban&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check the status of the SSH jail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fail2ban-client status sshd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            VERSATILE PROTECTION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Fail2Ban is incredibly powerful. You can configure it to protect many other services, such as web servers (Nginx, Apache) or mail servers, by creating custom jails.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-6-automate-security-updates&quot;&gt;Step 6: Automate Security Updates&lt;/h2&gt;
&lt;p&gt;Even with a hardened server, new vulnerabilities are discovered all the time. It is vital to install security updates promptly. The &lt;code&gt;unattended-upgrades&lt;/code&gt; package can do this for you automatically.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Install the package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install unattended-upgrades apt-listchanges&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, run the configuration wizard to enable it.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# This will open a simple text-based interface&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dpkg-reconfigure&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -plow&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unattended-upgrades&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Select &lt;strong&gt;“Yes”&lt;/strong&gt; to enable automatic updates. This will create a configuration file that tells the system to automatically install packages from Debian’s security repository.&lt;/p&gt;
&lt;p&gt;To further harden this, you can configure email notifications and an automatic reboot policy (essential for kernel updates) in &lt;code&gt;/etc/apt/apt.conf.d/50unattended-upgrades&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Email notification (requires a working mail setup like msmtp)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Unattended-Upgrade::Mail &amp;quot;your@email.com&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Automatic reboot policy (e.g., at 04:00 AM)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Unattended-Upgrade::Automatic-Reboot &amp;quot;true&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Unattended-Upgrade::Automatic-Reboot-Time &amp;quot;04:00&amp;quot;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-7-final-system-housekeeping&quot;&gt;Step 7: Final System Housekeeping&lt;/h2&gt;
&lt;p&gt;A few final touches will make your server easier to manage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Set the Timezone:&lt;/strong&gt; Correct log timestamps are crucial for troubleshooting.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Set your timezone, e.g., for Berlin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; timedatectl set-timezone Europe/Berlin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. Install Useful Tools:&lt;/strong&gt; These small utilities are incredibly helpful for administration.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install htop ncdu curl git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;htop&lt;/code&gt;: An interactive process viewer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ncdu&lt;/code&gt;: A disk usage analyzer to easily find large files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl&lt;/code&gt;: A tool for transferring data with URLs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git&lt;/code&gt;: Version control system, often needed to download software.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-8-basic-monitoring-and-logging&quot;&gt;Step 8: Basic Monitoring and Logging&lt;/h2&gt;
&lt;p&gt;A secure server is one where you &lt;em&gt;notice&lt;/em&gt; when something goes wrong.&lt;/p&gt;
&lt;h3 id=&quot;8-1-persistent-journal-logging&quot;&gt;8.1. Persistent Journal Logging&lt;/h3&gt;
&lt;p&gt;On some Debian installations, journal logs are lost upon reboot. This makes them persistent:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var/log/journal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemd-tmpfiles&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --create --prefix&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var/log/journal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl restart systemd-journald&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;8-2-ufw-logs-with-rsyslog-optional&quot;&gt;8.2. UFW Logs with rsyslog (Optional)&lt;/h3&gt;
&lt;p&gt;If you want UFW messages in &lt;code&gt;/var/log/ufw.log&lt;/code&gt; instead of relying only on the journal, install &lt;code&gt;rsyslog&lt;/code&gt; before adding rsyslog snippets.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install rsyslog&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example filter:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee /etc/rsyslog.d/20-ufw.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;:msg,contains,&amp;quot;[UFW &amp;quot; /var/log/ufw.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;amp; stop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Validate and restart:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rsyslogd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -N1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl restart rsyslog&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without the &lt;code&gt;rsyslog&lt;/code&gt; package, this configuration file will simply never be processed.&lt;/p&gt;
&lt;h3 id=&quot;8-3-logwatch-optional&quot;&gt;8.3. Logwatch (Optional)&lt;/h3&gt;
&lt;p&gt;Logwatch provides a daily summary of SSH attempts, disk usage, and service errors.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install logwatch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; logwatch&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --detail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Med&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --range&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; yesterday&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --output&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; stdout&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;8-4-monitoring-disk-space&quot;&gt;8.4. Monitoring Disk Space&lt;/h3&gt;
&lt;p&gt;Full disks are a common cause of service failures.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;df&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ncdu /&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-9-backup-strategy&quot;&gt;Step 9: Backup Strategy&lt;/h2&gt;
&lt;p&gt;Security = &lt;strong&gt;Prevent&lt;/strong&gt; + &lt;strong&gt;Detect&lt;/strong&gt; + &lt;strong&gt;Recover&lt;/strong&gt;. A server without a backup is not truly secure.&lt;/p&gt;
&lt;h3 id=&quot;core-principles&quot;&gt;Core Principles&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Provider Snapshots:&lt;/strong&gt; Enable them as your first layer of defense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application-Level Backups:&lt;/strong&gt; Use tools like &lt;code&gt;borgbackup&lt;/code&gt; or &lt;code&gt;restic&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3-2-1 Rule:&lt;/strong&gt; 3 copies, 2 different media, 1 offsite.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Restores:&lt;/strong&gt; A backup is only as good as its last successful restore.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Example with BorgBackup:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install borgbackup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;borg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --encryption=repokey&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /path/to/backup/repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Note: Adjust paths like /var/lib depending on your data volume (e.g., Docker volumes, databases).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;borg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; create /path/to/backup/repo::&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%Y-%m-%d&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc /home /var/lib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Verify your backup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;borg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; list /path/to/backup/repo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-10-optional-maximum-security-ssh-via-wireguard&quot;&gt;Step 10 (Optional): Maximum Security — SSH via WireGuard&lt;/h2&gt;
&lt;p&gt;For maximum security, do not expose SSH publicly at all. Access your server through a WireGuard VPN tunnel; SSH then listens only on the VPN interface. This eliminates scanning and brute-force attacks entirely.&lt;/p&gt;
&lt;h3 id=&quot;10-1-setup-wireguard-server&quot;&gt;10.1. Setup WireGuard Server&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install wireguard&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create directory with restricted permissions first&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;umask 077&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;wg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; genkey&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tee&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/wireguard/server_private.key&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; wg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pubkey&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/wireguard/server_public.key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(Note: The &lt;code&gt;tee&lt;/code&gt; command outputs the private key to your terminal. Do not share this output.)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;10-2-server-configuration&quot;&gt;10.2. Server Configuration&lt;/h3&gt;
&lt;p&gt;Create &lt;code&gt;/etc/wireguard/wg0.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Interface]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Address&lt;/span&gt;&lt;span&gt; = 10.0.0.1/24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ListenPort&lt;/span&gt;&lt;span&gt; = 51820&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PrivateKey&lt;/span&gt;&lt;span&gt; = &amp;lt;contents of server_private.key&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Peer]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PublicKey&lt;/span&gt;&lt;span&gt; = &amp;lt;client_public_key&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;AllowedIPs&lt;/span&gt;&lt;span&gt; = 10.0.0.2/32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enable the service:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl enable wg-quick@wg0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl start wg-quick@wg0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;10-3-restrict-ssh-to-vpn&quot;&gt;10.3. Restrict SSH to VPN&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;, set:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ListenAddress&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 10.0.0.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test and restart:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sshd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl restart sshd.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;10-4-update-firewall&quot;&gt;10.4. Update Firewall&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 51820/udp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw delete limit 8496/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            WARNING
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;After this change, SSH is ONLY reachable via WireGuard. Ensure your VPN connection works before closing your session.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;10-5-client-configuration&quot;&gt;10.5. Client Configuration&lt;/h3&gt;
&lt;p&gt;To connect to your newly secured server, you will need to configure a WireGuard client on your local machine using the public key from the server and a newly generated client key pair:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# /etc/wireguard/wg0.conf on client&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Interface]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Address&lt;/span&gt;&lt;span&gt; = 10.0.0.2/24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PrivateKey&lt;/span&gt;&lt;span&gt; = &amp;lt;client_private_key&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Peer]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;PublicKey&lt;/span&gt;&lt;span&gt; = &amp;lt;server_public_key&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Endpoint&lt;/span&gt;&lt;span&gt; = your_server_ip:51820&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;AllowedIPs&lt;/span&gt;&lt;span&gt; = 10.0.0.1/32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations! You have successfully performed the essential first steps to harden your new Debian server. By creating a sudo user, securing SSH with key authentication, and setting up a firewall and intrusion prevention system, you have built a solid foundation for any application you wish to deploy.&lt;/p&gt;
&lt;p&gt;Combined with monitoring, a solid backup strategy, and optionally a VPN-secured access layer, your server is well-prepared for production use. Your server is now significantly more resistant to common automated attacks and hardware failures.&lt;/p&gt;
&lt;hr size=&quot;2&quot; noshade color=&quot;#666666&quot; style=&quot;margin: 15px 0; border-style: double;&quot;&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHAT&#39;S NEXT?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;With this secure base, you are now ready to install your applications, such as a web server (Nginx/Apache), a database, or a Docker environment.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;a href=&quot;https://www.debian.org/doc/manuals/securing-debian-manual/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL DEBIAN SECURITY MANUAL&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://wiki.debian.org/Fail2ban&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🛡️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;DEBIAN WIKI: FAIL2BAN&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying Forgejo with Traefik and Docker Compose</title>
          <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/forgejo/</link>
          <guid>https://criticalbasics.xyz/posts/forgejo/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/forgejo/">&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt;&lt;/strong&gt; is a lightweight self-hosted Git forge with repositories, issues, pull requests, releases, packages, and optional Actions-compatible CI. It is a good fit when GitLab is too heavy but a plain Git server is not enough.&lt;/p&gt;
&lt;p&gt;This guide installs Forgejo in an existing &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec Docker ecosystem&lt;/a&gt;&lt;/strong&gt;. Forgejo runs as a rootless Docker container, PostgreSQL stores the application database, Traefik handles HTTPS, and Forgejo’s built-in SSH server exposes Git over a dedicated host port.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            FRESH INSTALL FIRST
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The main path below is a clean Forgejo installation. GitHub import, container registry usage, and Forgejo Runner are covered as optional sections after the base instance is working.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Fresh Forgejo install with PostgreSQL, rootless Docker, Traefik labels, SSH, registry, and backups.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-architecture&quot;&gt;1. Architecture&lt;/h2&gt;
&lt;p&gt;The target architecture looks like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Internet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | 443/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Traefik -&amp;gt; Forgejo web UI/API/registry on port 3000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Internet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | 2222/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Forgejo built-in SSH server for Git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Forgejo -&amp;gt; PostgreSQL on a private Docker network&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup deliberately starts without a runner. CI jobs can execute arbitrary project code, so it is better to enable the runner only after the Git service itself is stable.&lt;/p&gt;
&lt;h2 id=&quot;2-prerequisites&quot;&gt;2. Prerequisites&lt;/h2&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec stack&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Docker and Docker Compose.&lt;/li&gt;
&lt;li&gt;An external Docker network named &lt;code&gt;proxy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A subdomain such as &lt;code&gt;forgejo.your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;DNS &lt;code&gt;A&lt;/code&gt;/&lt;code&gt;AAAA&lt;/code&gt; records pointing the subdomain to your server.&lt;/li&gt;
&lt;li&gt;Open firewall ports &lt;code&gt;80/tcp&lt;/code&gt;, &lt;code&gt;443/tcp&lt;/code&gt;, and one Git SSH port, e.g. &lt;code&gt;2222/tcp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Forgejo &lt;code&gt;15.0.3-rootless&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL &lt;code&gt;16-alpine&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Traefik TLS resolver named &lt;code&gt;tls_resolver&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://forgejo.org/docs/latest/admin/installation/docker/&quot;&gt;Forgejo Docker installation docs&lt;/a&gt; before changing major versions. Upgrading from one major Forgejo version to the next should be done deliberately, not through &lt;code&gt;latest&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;3-directory-structure&quot;&gt;3. Directory Structure&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; data config postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1000:1000 data config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rootless Forgejo container runs as UID/GID &lt;code&gt;1000:1000&lt;/code&gt;. Adjust this if your Docker host uses a different unprivileged user.&lt;/p&gt;
&lt;h2 id=&quot;4-environment-file&quot;&gt;4. Environment File&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/forgejo/.env&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano .env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TZ=Europe/Berlin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FORGEJO_DOMAIN=forgejo.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FORGEJO_DB_PASSWORD=REPLACE_WITH_LONG_RANDOM_VALUE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FORGEJO_SECRET_KEY=REPLACE_WITH_LONG_RANDOM_VALUE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FORGEJO_INTERNAL_TOKEN=REPLACE_WITH_LONG_RANDOM_VALUE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FORGEJO_JWT_SECRET=REPLACE_WITH_LONG_RANDOM_VALUE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generate secrets with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;5-docker-compose&quot;&gt;5. Docker Compose&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;/opt/containers/forgejo/docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  forgejo-db&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker.io/postgres:16-alpine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    container_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo-db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      POSTGRES_DB&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      POSTGRES_USER&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      POSTGRES_PASSWORD&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${FORGEJO_DB_PASSWORD}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./postgres:/var/lib/postgresql/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo-internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    healthcheck&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      test&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;CMD-SHELL&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;pg_isready -U forgejo -d forgejo&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      interval&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 10s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      timeout&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 5s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      retries&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      start_period&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 20s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  forgejo&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; codeberg.org/forgejo/forgejo:15.0.3-rootless&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    container_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    user&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;1000:1000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    depends_on&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      forgejo-db&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        condition&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; service_healthy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      USER_UID&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      USER_GID&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO____APP_NAME&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;My Forgejo&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__database__DB_TYPE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__database__HOST&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo-db:5432&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__database__NAME&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__database__USER&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__database__PASSWD&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${FORGEJO_DB_PASSWORD}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__database__SSL_MODE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; disable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__security__INSTALL_LOCK&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__security__SECRET_KEY&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${FORGEJO_SECRET_KEY}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__security__INTERNAL_TOKEN&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${FORGEJO_INTERNAL_TOKEN}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__oauth2__JWT_SECRET&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${FORGEJO_JWT_SECRET}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__DOMAIN&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${FORGEJO_DOMAIN}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__ROOT_URL&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://${FORGEJO_DOMAIN}/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__HTTP_ADDR&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.0.0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__HTTP_PORT&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__PROTOCOL&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; http&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__START_SSH_SERVER&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__SSH_DOMAIN&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${FORGEJO_DOMAIN}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__SSH_PORT&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2222&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__SSH_LISTEN_PORT&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2222&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__server__LFS_START_SERVER&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__repository__DEFAULT_PRIVATE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; private&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__service__DISABLE_REGISTRATION&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__service__REQUIRE_SIGNIN_VIEW&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__openid__ENABLE_OPENID_SIGNIN&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__openid__ENABLE_OPENID_SIGNUP&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__packages__ENABLED&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__actions__ENABLED&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      TZ&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${TZ}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./data:/var/lib/gitea&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./config:/etc/gitea&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/timezone:/etc/timezone:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/localtime:/etc/localtime:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    ports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2222:2222&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo-internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.forgejo.rule=Host(`forgejo.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.forgejo.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.forgejo.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.forgejo.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.forgejo.loadbalancer.server.port=3000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  proxy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  forgejo-internal&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open the Git SSH port on the host:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 2222/tcp comment &amp;#39;Forgejo SSH&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start Forgejo:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;6-create-the-admin-user&quot;&gt;6. Create the Admin User&lt;/h2&gt;
&lt;p&gt;With the rootless container image, the generated &lt;code&gt;app.ini&lt;/code&gt; usually lives at:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/var/lib/gitea/custom/conf/app.ini&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the first admin user:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  forgejo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var/lib/gitea/custom/conf/app.ini&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --work-path&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var/lib/gitea&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  admin user create&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --username&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; youradmin&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --password&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;REPLACE_WITH_TEMPORARY_PASSWORD&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --email&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; you@your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --admin \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --must-change-password=false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Log in at:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://forgejo.your-domain.com/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add your SSH public key under:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Settings -&amp;gt; SSH / GPG Keys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test SSH:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T -p 2222&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git@forgejo.your-domain.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;7-optional-mail-via-mox&quot;&gt;7. Optional: Mail via Mox&lt;/h2&gt;
&lt;p&gt;Forgejo works without mail, but password resets and notifications require SMTP. If you run &lt;strong&gt;&lt;a href=&quot;../mox-e-mail-server/&quot;&gt;Mox&lt;/a&gt;&lt;/strong&gt;, create a dedicated mailbox such as &lt;code&gt;forgejo@your-domain.com&lt;/code&gt;, then add:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__mailer__ENABLED&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__mailer__PROTOCOL&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; smtp+starttls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__mailer__SMTP_ADDR&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__mailer__SMTP_PORT&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 587&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__mailer__USER&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo@your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__mailer__PASSWD&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;REPLACE_WITH_MAILBOX_PASSWORD&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FORGEJO__mailer__FROM&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Forgejo &amp;lt;forgejo@your-domain.com&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart Forgejo after changing mail settings:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;8-container-registry&quot;&gt;8. Container Registry&lt;/h2&gt;
&lt;p&gt;Forgejo includes a Docker/OCI-compatible container registry. With the setup above, the registry uses the same hostname as the web UI:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; login forgejo.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; build&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo.your-domain.com/youruser/myapp:v1.0.0 .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push forgejo.your-domain.com/youruser/myapp:v1.0.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For production, prefer immutable tags:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;v1.2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;main-a1b2c3d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2026-07-01-a1b2c3d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using only &lt;code&gt;latest&lt;/code&gt; makes rollbacks and audits harder.&lt;/p&gt;
&lt;h2 id=&quot;9-optional-import-or-mirror-github-repositories&quot;&gt;9. Optional: Import or Mirror GitHub Repositories&lt;/h2&gt;
&lt;p&gt;For a simple source-code backup, mirror the Git repository first. Do not start by copying thousands of old container images or CI artifacts.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --mirror&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://github.com/ORG/REPO.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; REPO.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --mirror&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://forgejo.your-domain.com/ORG/REPO.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For private GitHub repositories, use the GitHub CLI locally:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; auth login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; auth refresh&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; github.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; repo&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; read:org&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --mirror&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://github.com/ORG/REPO.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to avoid importing GitHub-specific pull request refs as hundreds of Forgejo branches, push only normal branches and tags:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push https://forgejo.your-domain.com/ORG/REPO.git &amp;#39;+refs/heads/*:refs/heads/*&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push https://forgejo.your-domain.com/ORG/REPO.git &amp;#39;+refs/tags/*:refs/tags/*&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GitHub Actions caches are rebuildable. Old Playwright reports and expired artifacts are usually safe to delete once they are no longer needed for debugging. Container package versions should be reduced to release tags and a small number of recent main builds; stale untagged image versions should not be mirrored blindly into your new registry.&lt;/p&gt;
&lt;h2 id=&quot;10-optional-forgejo-runner&quot;&gt;10. Optional: Forgejo Runner&lt;/h2&gt;
&lt;p&gt;Forgejo Actions can be enabled later. The conservative path is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep Forgejo itself on the production VPS.&lt;/li&gt;
&lt;li&gt;Add a runner only when you know which workflows you need.&lt;/li&gt;
&lt;li&gt;Avoid running untrusted CI jobs on the same host as production data.&lt;/li&gt;
&lt;li&gt;If you start on the same VPS, keep it as a temporary convenience and move the runner to a separate build host later.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The risky part is Docker access from CI jobs. Mounting &lt;code&gt;/var/run/docker.sock&lt;/code&gt; gives jobs effective host-root power. If you need container builds, prefer a dedicated runner host or a rootless build tool such as BuildKit, Buildah, or Kaniko.&lt;/p&gt;
&lt;h2 id=&quot;11-backups&quot;&gt;11. Backups&lt;/h2&gt;
&lt;p&gt;Back up at least:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/forgejo/docker-compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/forgejo/.env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/forgejo/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/forgejo/config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/opt/containers/forgejo/postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A simple dump:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo-db&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  pg_dump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo forgejo&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo-db.sql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -czf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo-data-backup.tar.gz data config forgejo-db.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Store backups off-server and test restores before relying on them.&lt;/p&gt;
&lt;h2 id=&quot;12-updates&quot;&gt;12. Updates&lt;/h2&gt;
&lt;p&gt;For patch updates within the same major version:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/forgejo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; forgejo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For major upgrades, read the Forgejo release notes first. Do not jump major versions unattended, and do not use &lt;code&gt;latest&lt;/code&gt; in production.&lt;/p&gt;
</description>
      </item>
      <item>
          <title>Deploying a Matrix Synapse Server with Docker and Traefik</title>
          <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/matrix-synapse-server/</link>
          <guid>https://criticalbasics.xyz/posts/matrix-synapse-server/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/matrix-synapse-server/">&lt;p&gt;This guide will walk you through deploying a powerful, federated Matrix Synapse homeserver. We will use the popular &lt;code&gt;matrix-docker-ansible-deploy&lt;/code&gt; playbook, which simplifies the setup of Synapse and its various components, including bridges for other chat platforms.&lt;/p&gt;
&lt;p&gt;This setup is designed to integrate seamlessly with an existing Traefik v3 reverse proxy and a root-domain &lt;a href=&quot;../nginx-webserver/&quot;&gt;Nginx web server&lt;/a&gt;, making it a perfect addition to a modern, container-based infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Authentication Guide:&lt;/strong&gt; Linked the safe Authelia OIDC and 2FA migration for existing Synapse accounts.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Migration Notes:&lt;/strong&gt; Added homeserver identity, bridge-state, MatrixRTC discovery, and media-retention guidance.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-06-12&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Playbook Compatibility:&lt;/strong&gt; Refreshed the guide for current Ketesa, Telegram bridgev2, migration validation, Docker collection requirements, and a safer baseline without Matrix RTC.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-02-20&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Configuration Update:&lt;/strong&gt; Updated &lt;code&gt;matrix_coturn_enabled&lt;/code&gt; to &lt;code&gt;coturn_enabled&lt;/code&gt;, removed Sliding Sync, and added PostgreSQL upgrade instructions.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-09-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide created, focusing on Traefik v3 integration, Ansible deployment, and enabling various bridges and features like Sliding Sync.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;: This is the foundation for our reverse proxy and security.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../nginx-webserver/&quot;&gt;Deploying a Secure Nginx Website with Traefik and Docker Compose&lt;/a&gt;&lt;/strong&gt;: This step is crucial as it establishes a web server on your root domain and correctly configures the &lt;code&gt;.well-known/matrix&lt;/code&gt; delegation required for federation.&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            HARD REQUIREMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The following steps will not work correctly without the Traefik and Nginx stacks running as described in the prerequisite guides.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            ROOT DOMAIN REMAINS FREE FOR YOUR WEBSITE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Synapse runs on a dedicated subdomain (e.g., &lt;code&gt;matrix.your-domain.com&lt;/code&gt;). The root domain (e.g., &lt;code&gt;your-domain.com&lt;/code&gt;) continues to serve your main website via &lt;a href=&quot;../nginx-webserver/&quot;&gt;Nginx&lt;/a&gt;. The &lt;code&gt;.well-known&lt;/code&gt; files on the root domain merely delegate clients and federation to the subdomain, so your homepage remains unaffected.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Architecture (simplified)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Users / Browsers / Homeservers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      your-domain.com  ──&amp;gt;  [Nginx](../nginx-webserver/) on root domain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             │                 │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             │                 ├─ Serves your website (/, /assets, ...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             │                 └─ Serves .well-known/matrix/{server,client}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             │                                  │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             │                                  ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             └────────────────────────── delegates to ──&amp;gt; matrix.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                       (Synapse via Traefik)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                            │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                            ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                               Traefik (websecure, synapse)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                            │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                            ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                        Synapse&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will also need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt;, and &lt;code&gt;pwgen&lt;/code&gt; for version control, JSON parsing, and password generation.&lt;/li&gt;
&lt;li&gt;Python 3 and &lt;code&gt;pip&lt;/code&gt; installed on your server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Install the required tools:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install git jq pwgen python3-pip python3-venv make&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;2-directory-structure&quot;&gt;2. Directory Structure&lt;/h2&gt;
&lt;p&gt;First, we’ll create a dedicated directory for the Matrix playbook configuration and files.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-download-the-ansible-playbook&quot;&gt;3. Download the Ansible Playbook&lt;/h2&gt;
&lt;p&gt;Next, clone the official &lt;code&gt;matrix-docker-ansible-deploy&lt;/code&gt; repository from GitHub into the directory you just created.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git clone https://github.com/spantaleev/matrix-docker-ansible-deploy.git /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;4-initial-configuration&quot;&gt;4. Initial Configuration&lt;/h2&gt;
&lt;p&gt;The playbook is configured using Ansible variables. We’ll start by creating a configuration directory based on your Matrix server’s hostname and copying the example &lt;code&gt;vars.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            HOSTNAME CONVENTION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The playbook expects the server to be available at &lt;code&gt;matrix.your-domain.com&lt;/code&gt;. The configuration directory must match this hostname.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Replace &amp;#39;matrix.your-domain.com&amp;#39; with your actual server name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/host_vars/matrix.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp examples/vars.yml inventory/host_vars/matrix.your-domain.com/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-1-generate-secret-keys&quot;&gt;4.1. Generate Secret Keys&lt;/h3&gt;
&lt;p&gt;The configuration requires two strong secret keys. You can generate these using &lt;code&gt;pwgen&lt;/code&gt; or &lt;code&gt;openssl&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Generate two strong keys and save them for the next step&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pwgen&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s 64 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pwgen&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s 64 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-customize-vars-yml&quot;&gt;4.2. Customize &lt;code&gt;vars.yml&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Now, open the &lt;code&gt;vars.yml&lt;/code&gt; file and customize it for your environment. This is the most critical step.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano inventory/host_vars/matrix.your-domain.com/vars.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Below is a complete configuration based on a feature-rich setup. Adjust the values to match your domain, secrets, and desired features.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Acknowledge the playbook breaking changes reviewed for this guide.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_playbook_migration_validated_version&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; v2026.05.18.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# The bare domain name which represents your Matrix identity.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_domain&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_homeserver_implementation&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; synapse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_homeserver_generic_secret_key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;PASTE-YOUR-GENERIC-SECRET-KEY-HERE&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Use our own Traefik (externally managed)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_playbook_reverse_proxy_type&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; other-traefik-container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;traefik_certs_dumper_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;postgres_connection_password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;PASTE-YOUR-POSTGRES-PASSWORD-HERE&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;devture_systemd_docker_base_docker_service_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_playbook_docker_installation_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# We delegate .well-known from the root domain via Nginx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_static_files_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_static_files_container_labels_traefik_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;coturn_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Traefik integration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_playbook_reverse_proxy_container_network&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_playbook_reverse_proxy_hostname&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;traefik_entrypoint_primary&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; websecure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;traefik_certResolver_primary&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tls_resolver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_federation_traefik_entrypoint_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; synapse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Core services ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_synapse_container_labels_traefik_docker_network&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_client_element_container_labels_traefik_docker_network&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_client_element_hostname&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;{{ matrix_server_fqn_matrix }}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_client_element_path_prefix&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /element&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_admin&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;@your-username:your-domain.com&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_container_http_host_bind_port&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_container_labels_traefik_docker_network&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# E-Mail relay (optional)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;exim_relay_sender_address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;matrix@your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;exim_relay_relay_use&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;exim_relay_relay_host_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;mail.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;exim_relay_relay_host_port&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 587&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;exim_relay_relay_auth&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;exim_relay_relay_auth_username&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;user@your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;exim_relay_relay_auth_password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;YOUR-EMAIL-PASSWORD&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_appservice_double_puppet_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Bridges ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# The playbook can install and configure various bridges to connect your Matrix homeserver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# to other chat networks like Telegram, Discord, Signal, etc. When enabling a bridge,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# it is crucial to provide the `homeserver` configuration block to ensure it communicates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# correctly with Synapse via Traefik. For more details on available bridges and their&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# specific configurations, refer to the official documentation.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Telegram – Correct EntryPoints + specify Homeserver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_telegram_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_telegram_api_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 12345678&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_telegram_api_hash&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;your_telegram_api_hash&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_telegram_configuration_extension_yaml&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  homeserver:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    address: &amp;quot;https://matrix.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    domain: &amp;quot;your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  bridge:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    permissions:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;#39;{{ matrix_admin }}&amp;#39;: admin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Meta Messenger&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_meta_messenger_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_meta_messenger_configuration_extension_yaml&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  homeserver:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    address: &amp;quot;https://matrix.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    domain: &amp;quot;your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  bridge:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    permissions:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;#39;*&amp;#39;: relay&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;#39;your-domain.com&amp;#39;: admin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;#39;{{ matrix_admin }}&amp;#39;: admin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Discord – Correct Avatar-Proxy &amp;amp; general EntryPoints&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_discord_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_mautrix_discord_configuration_extension_yaml&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  homeserver:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    address: &amp;quot;https://matrix.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    domain: &amp;quot;your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            TRAEFIK MIDDLEWARES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The playbook generates Traefik router labels for each Matrix component. Do not add custom middleware variables such as &lt;code&gt;*_container_labels_traefik_middlewares&lt;/code&gt;; current roles do not use them. If you want to apply &lt;code&gt;security-headers@file&lt;/code&gt; or &lt;code&gt;crowdsec-bouncer@docker&lt;/code&gt; to Matrix routes, do it via the role-specific &lt;code&gt;*_container_labels_additional_labels&lt;/code&gt; variables after checking the generated router names, or enforce the middleware in your Traefik stack.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            ELEMENT CALL / MATRIX RTC
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Element Call and the Matrix RTC stack are deliberately not enabled in the baseline configuration above. They need additional firewall ports (&lt;code&gt;7881/tcp&lt;/code&gt;, &lt;code&gt;7882/udp&lt;/code&gt;, &lt;code&gt;3479/udp&lt;/code&gt;, &lt;code&gt;5350/tcp&lt;/code&gt;, and &lt;code&gt;30000-30020/udp&lt;/code&gt;) and, when using an externally managed Traefik container, explicit TURN/TLS handling. Add them only after the core homeserver is working.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;5-install-ansible-and-dependencies&quot;&gt;5. Install Ansible and Dependencies&lt;/h2&gt;
&lt;p&gt;This playbook uses Ansible to automate the setup. Choose the installation method that fits your distribution policy.&lt;/p&gt;
&lt;h3 id=&quot;for-debian-12-system-pip-with-break-system-packages&quot;&gt;For Debian 12 (system pip with –break-system-packages)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ensure pip is available&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; python3-pip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Install Ansible and required Python packages system-wide&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pip3 install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --break-system-packages&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible docker passlib&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;for-other-linux-distributions-recommended-python-virtual-environment&quot;&gt;For Other Linux Distributions (recommended: Python virtual environment)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create and activate a dedicated virtual environment&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; venv ~/.venvs/matrix-ansible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.venvs/matrix-ansible/bin/activate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Upgrade pip and install required packages in the venv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --upgrade&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install ansible docker passlib&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            VIRTUALENV REMINDER
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If you use the virtual environment, remember to reactivate it in new shell sessions with:
&lt;code&gt;source ~/.venvs/matrix-ansible/bin/activate&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            USE ONE ANSIBLE ENVIRONMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Run &lt;code&gt;ansible-galaxy&lt;/code&gt;, &lt;code&gt;ansible-doc&lt;/code&gt;, and &lt;code&gt;ansible-playbook&lt;/code&gt; with the same Ansible installation. The commands below use &lt;code&gt;sudo&lt;/code&gt; because this guide creates &lt;code&gt;/opt/containers/matrix&lt;/code&gt; as a root-owned checkout and runs the playbook with &lt;code&gt;sudo&lt;/code&gt;. If you use a user-owned checkout or a virtual environment, omit &lt;code&gt;sudo&lt;/code&gt; consistently for the Ansible commands.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Next, install the Ansible roles required by the playbook:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make roles&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install the Docker collection used by several playbook roles:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-galaxy collection install community.docker&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --upgrade&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can verify that Ansible can resolve the Docker image module:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-doc community.docker.docker_image_pull&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;6-configure-ansible-hosts&quot;&gt;6. Configure Ansible Hosts&lt;/h2&gt;
&lt;p&gt;Now, we need to tell Ansible which server to configure. Since we are running it locally, the setup is simple.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Copy the example hosts file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp examples/hosts inventory/hosts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Edit the file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano inventory/hosts&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Modify the file to look like this. The &lt;code&gt;ansible_connection=local&lt;/code&gt; tells Ansible to run all commands on the machine it’s currently on, instead of connecting to a remote server via SSH. Because of this, &lt;code&gt;ansible_host=127.0.0.1&lt;/code&gt; (localhost) is the correct value. Parameters like &lt;code&gt;ansible_ssh_user=root&lt;/code&gt; are ignored in this mode, as the playbook runs with the permissions of the user executing it (in our case, &lt;code&gt;root&lt;/code&gt; via &lt;code&gt;sudo&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[matrix_servers]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;matrix.your-domain.com &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ansible_host&lt;/span&gt;&lt;span&gt;=127.0.0.1 &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ansible_connection&lt;/span&gt;&lt;span&gt;=local&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;7-adjust-traefik-for-federation&quot;&gt;7. Adjust Traefik for Federation&lt;/h2&gt;
&lt;p&gt;For Matrix federation to work, other servers need to connect to yours on port &lt;code&gt;8448&lt;/code&gt;. We must expose this port in our main Traefik stack and create a dedicated entrypoint for it.&lt;/p&gt;
&lt;p&gt;Go to your Traefik stack’s directory (e.g., &lt;code&gt;/opt/containers/traefik-stack&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;7-1-expose-federation-port&quot;&gt;7.1. Expose Federation Port&lt;/h3&gt;
&lt;p&gt;Edit your main &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano docker-compose.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add port &lt;code&gt;8448&lt;/code&gt; to the &lt;code&gt;ports&lt;/code&gt; section of the &lt;code&gt;traefik&lt;/code&gt; service:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  traefik&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # ... other settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    ports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;80:80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;443:443&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;8448:8448&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Add this line for Matrix federation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # ... rest of the settings&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;7-2-create-federation-and-internal-entrypoints&quot;&gt;7.2. Create Federation and Internal Entrypoints&lt;/h3&gt;
&lt;p&gt;Edit your static Traefik configuration (&lt;code&gt;traefik/config/traefik.yml&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano traefik/config/traefik.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add a new &lt;code&gt;synapse&lt;/code&gt; entrypoint for federation and a &lt;code&gt;matrix-internal-matrix-client-api&lt;/code&gt; entrypoint for internal communication.&lt;/p&gt;
&lt;p&gt;For recent playbook versions, it is recommended to also define the internal &lt;code&gt;matrix-internal-matrix-client-api&lt;/code&gt; entrypoint on port 8008. This port is &lt;strong&gt;not&lt;/strong&gt; published to the host and serves as an internal C2S route for bridges and add-ons, preventing errors in the Traefik dashboard.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;entryPoints&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  web&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;:80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  websecure&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;:443&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  synapse&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # For federation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;:8448&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  matrix-internal-matrix-client-api&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # For internal C2S communication&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;:8008&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;7-3-restart-traefik&quot;&gt;7.3. Restart Traefik&lt;/h3&gt;
&lt;p&gt;Apply the changes by restarting your Traefik stack:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;8-run-the-matrix-installation&quot;&gt;8. Run the Matrix Installation&lt;/h2&gt;
&lt;p&gt;With all the configuration in place, we can now run the Ansible playbook to set up and install everything.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=install-all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will download all necessary Docker images, generate configuration files, and prepare the services. It may take several minutes. The &lt;code&gt;install-all&lt;/code&gt; tag is the recommended path for a new server when you are not importing old Matrix data.&lt;/p&gt;
&lt;h2 id=&quot;9-start-the-matrix-services&quot;&gt;9. Start the Matrix Services&lt;/h2&gt;
&lt;p&gt;Once the setup is complete, start all the Matrix containers:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=ensure-matrix-users-created,start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After a few moments, all the services you enabled should be running. The &lt;code&gt;ensure-matrix-users-created&lt;/code&gt; tag creates the internal service users required by bots and bridges. You can verify the running containers with &lt;code&gt;docker ps&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;10-verify-the-installation&quot;&gt;10. Verify the Installation&lt;/h2&gt;
&lt;p&gt;After starting the services, it’s crucial to verify that all components are running and communicating correctly.&lt;/p&gt;
&lt;h3 id=&quot;10-1-check-running-containers&quot;&gt;10.1. Check Running Containers&lt;/h3&gt;
&lt;p&gt;First, ensure all enabled services are running. The exact names will vary based on your &lt;code&gt;matrix_domain&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ps&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --format&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{{.Names}}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;synapse|element|ketesa|mautrix&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;10-2-verify-well-known-delegation-cli&quot;&gt;10.2. Verify &lt;code&gt;.well-known&lt;/code&gt; Delegation (CLI)&lt;/h3&gt;
&lt;p&gt;Check if your Nginx server is correctly serving the delegation files for your root domain.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Replace &amp;#39;your-domain.com&amp;#39; with your actual domain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://your-domain.com/.well-known/matrix/server&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://your-domain.com/.well-known/matrix/client&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this guide, the expected federation delegation uses port &lt;code&gt;8448&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;m.server&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;matrix.your-domain.com:8448&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The client delegation should point clients to the Matrix HTTPS endpoint:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;m.homeserver&amp;quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;base_url&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;https://matrix.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;10-3-verify-federation-endpoint-cli&quot;&gt;10.3. Verify Federation Endpoint (CLI)&lt;/h3&gt;
&lt;p&gt;Test if the Synapse federation port (&lt;code&gt;8448&lt;/code&gt;) is correctly exposed through Traefik.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Replace &amp;#39;matrix.your-domain.com&amp;#39; with your actual matrix subdomain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://matrix.your-domain.com:8448/_matrix/federation/v1/version&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should return a JSON object with server information, confirming the federation endpoint is reachable.&lt;/p&gt;
&lt;h3 id=&quot;10-4-verify-crowdsec-bouncer-registration&quot;&gt;10.4. Verify CrowdSec Bouncer Registration&lt;/h3&gt;
&lt;p&gt;Check if the CrowdSec bouncer for Traefik has successfully registered with the CrowdSec agent.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec crowdsec cscli bouncers list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see the Traefik bouncer in the list with a valid status.&lt;/p&gt;
&lt;h3 id=&quot;10-5-web-based-federation-test&quot;&gt;10.5. Web-based Federation Test&lt;/h3&gt;
&lt;p&gt;Finally, use the official Federation Tester for a comprehensive check.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://federationtester.matrix.org/&quot;&gt;https://federationtester.matrix.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Enter your server name (e.g., &lt;code&gt;your-domain.com&lt;/code&gt;) and run the test.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If everything is configured correctly, you should see a success message.&lt;/p&gt;
&lt;h2 id=&quot;11-create-your-first-user&quot;&gt;11. Create Your First User&lt;/h2&gt;
&lt;p&gt;Use the playbook to register your administrator user.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            PASSWORD SECURITY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;To avoid leaving your password in your shell’s history, omit the &lt;code&gt;-e &#39;password=...&#39;&lt;/code&gt; part. The playbook will then prompt you to enter the password securely.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;... -e &#39;username=your-username&#39; -e &#39;admin=yes&#39;&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=register-user -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;username=your-username&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;admin=yes&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can re-run this command with &lt;code&gt;admin=no&lt;/code&gt; to create non-admin users.&lt;/p&gt;
&lt;h2 id=&quot;12-log-in-with-element&quot;&gt;12. Log In with Element&lt;/h2&gt;
&lt;p&gt;Your homeserver is now ready! You can access the Element web client by navigating to &lt;code&gt;https://matrix.your-domain.com/element&lt;/code&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click “Sign In”.&lt;/li&gt;
&lt;li&gt;Your homeserver should be pre-filled. If not, edit it to show your server’s address (&lt;code&gt;matrix.your-domain.com&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Log in with the username and password you just created.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;13-accessing-the-ketesa-admin-ui&quot;&gt;13. Accessing the Ketesa Admin UI&lt;/h2&gt;
&lt;p&gt;Because we set &lt;code&gt;matrix_ketesa_enabled: true&lt;/code&gt; in our &lt;code&gt;vars.yml&lt;/code&gt; configuration, a powerful web-based administration interface for Synapse is automatically deployed.&lt;/p&gt;
&lt;p&gt;You can access it at: &lt;code&gt;https://matrix.your-domain.com/synapse-admin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;By default, the playbook exposes Ketesa at the &lt;code&gt;/synapse-admin&lt;/code&gt; path. If you prefer a Ketesa-branded path, add &lt;code&gt;matrix_ketesa_path_prefix: /ketesa&lt;/code&gt; to &lt;code&gt;vars.yml&lt;/code&gt; and use &lt;code&gt;https://matrix.your-domain.com/ketesa&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Log in with your Matrix administrator account. From here, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manage users (deactivate, make admin, etc.).&lt;/li&gt;
&lt;li&gt;View server statistics and metrics.&lt;/li&gt;
&lt;li&gt;Explore rooms and manage their settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This interface is the primary tool for the day-to-day administration of your homeserver.&lt;/p&gt;
&lt;h2 id=&quot;14-maintenance&quot;&gt;14. Maintenance&lt;/h2&gt;
&lt;h3 id=&quot;routine-updates&quot;&gt;Routine Updates&lt;/h3&gt;
&lt;p&gt;To update your Matrix server and its components to the latest version:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Pull the latest changes from the git repository.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Update the playbook roles.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make roles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Keep Ansible collections current.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-galaxy collection install community.docker&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# It&amp;#39;s a good practice to review the CHANGELOG.md for breaking changes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sudo nano CHANGELOG.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Re-run the install and start tags to apply updates.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=install-all,start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you removed components from &lt;code&gt;vars.yml&lt;/code&gt;, run a full setup instead so the playbook can uninstall disabled services:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=setup-all,ensure-matrix-users-created,start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;migration-preserve-homeserver-identity&quot;&gt;Migration: Preserve Homeserver Identity&lt;/h3&gt;
&lt;p&gt;For a fresh homeserver, the normal installation flow above is enough. For a server migration where existing users should keep the same Matrix ID, clients should remain logged in, and bridges should continue to work, copying only &lt;code&gt;vars.yml&lt;/code&gt; is not enough.&lt;/p&gt;
&lt;p&gt;Preserve at least:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Synapse database.&lt;/li&gt;
&lt;li&gt;The Synapse signing key.&lt;/li&gt;
&lt;li&gt;Appservice registration files and tokens.&lt;/li&gt;
&lt;li&gt;Bridge configuration and bridge databases/state.&lt;/li&gt;
&lt;li&gt;The same &lt;code&gt;matrix_domain&lt;/code&gt; and public &lt;code&gt;.well-known&lt;/code&gt; delegation.&lt;/li&gt;
&lt;li&gt;Media that you still care about, especially local profile and room avatars.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DO NOT RUN BRIDGES TWICE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;When migrating bridge-heavy setups, stop the old bridge services before starting the new ones. Running the same Signal, Telegram, Discord, Instagram, Messenger, or LinkedIn bridge state on two servers at the same time can cause external-service conflicts and duplicate sessions.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;If historical Matrix media is not important, you can keep the migration lightweight by skipping most remote media. Do not forget that avatars are also media. A useful compromise is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep local media required for account and room avatars.&lt;/li&gt;
&lt;li&gt;Allow old remote cached media to be refetched when possible.&lt;/li&gt;
&lt;li&gt;Enable remote media retention so cached remote media does not grow forever.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Synapse’s media retention config, the intended policy looks like:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;media_retention&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  local_media_lifetime&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  remote_media_lifetime&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 14d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This keeps local uploads while allowing Synapse to purge remote cached media that has not been accessed recently.&lt;/p&gt;
&lt;h3 id=&quot;upgrade-notes-for-existing-installations&quot;&gt;Upgrade Notes for Existing Installations&lt;/h3&gt;
&lt;p&gt;Fresh installations using the configuration above can skip this subsection. These notes are for servers that were originally deployed with older versions of the playbook.&lt;/p&gt;
&lt;h4 id=&quot;playbook-migration-validation&quot;&gt;Playbook migration validation&lt;/h4&gt;
&lt;p&gt;Older installations can be blocked by the playbook’s migration validation gate:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your validated migration version (v2026.03.23.0) is behind the expected version (v2026.05.18.0).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is an intentional safety check. Review the relevant playbook changelog entries first, then raise the validated version in your host-specific &lt;code&gt;vars.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_playbook_migration_validated_version&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;v2026.05.18.0&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file usually lives at:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;inventory/host_vars/matrix.your-domain.com/vars.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;ketesa-configuration-for-older-synapse-admin-setups&quot;&gt;Ketesa configuration for older Synapse Admin setups&lt;/h4&gt;
&lt;p&gt;The bundled administration UI is now configured with &lt;code&gt;matrix_ketesa_*&lt;/code&gt; variables. Existing configurations that still contain &lt;code&gt;matrix_synapse_admin_*&lt;/code&gt; variables should be updated:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_enabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_container_http_host_bind_port&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_container_labels_traefik_docker_network&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_container_labels_traefik_entrypoints&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; websecure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;matrix_ketesa_container_labels_traefik_tls_certResolver&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tls_resolver&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can check your configuration with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -nE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;matrix_synapse_admin_|matrix_ketesa_&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;inventory/host_vars/matrix.your-domain.com/vars.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If any &lt;code&gt;matrix_synapse_admin_*&lt;/code&gt; variables still appear, rename them to their &lt;code&gt;matrix_ketesa_*&lt;/code&gt; equivalents.&lt;/p&gt;
&lt;h4 id=&quot;keep-the-docker-collection-current&quot;&gt;Keep the Docker collection current&lt;/h4&gt;
&lt;p&gt;The setup section already installs &lt;code&gt;community.docker&lt;/code&gt;. On older installations, update it before running the playbook:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-galaxy collection install community.docker&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --upgrade&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This avoids errors like:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ERROR! couldn&amp;#39;t resolve module/action &amp;#39;community.docker.docker_image_pull&amp;#39;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify that Ansible can resolve the module:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-doc community.docker.docker_image_pull&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;make roles&lt;/code&gt; installs Ansible roles, but it does not necessarily install or upgrade collections. If you see a warning that &lt;code&gt;community.docker&lt;/code&gt; does not support your Ansible version and later tasks fail, update Ansible itself, preferably in the dedicated Python virtual environment described above.&lt;/p&gt;
&lt;h4 id=&quot;remove-the-obsolete-telegram-public-endpoint-variable&quot;&gt;Remove the obsolete Telegram public endpoint variable&lt;/h4&gt;
&lt;p&gt;The Go/bridgev2-based &lt;code&gt;mautrix-telegram&lt;/code&gt; bridge no longer has a public web-based login endpoint. Existing configurations must not keep this variable:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;matrix_mautrix_telegram_container_labels_public_endpoint_traefik_entrypoints -&amp;gt; &amp;lt;removed (the bridge no longer has a public web-based login endpoint)&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remove or comment out this line:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# matrix_mautrix_telegram_container_labels_public_endpoint_traefik_entrypoints: websecure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After applying the relevant upgrade notes, run the update again:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=install-all,start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;upgrading-postgresql&quot;&gt;Upgrading PostgreSQL&lt;/h3&gt;
&lt;p&gt;If the playbook notifies you about a new PostgreSQL version being available, you can perform the upgrade with a specific tag.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            BACKUP RECOMMENDED
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Before upgrading the database, ensure you have a recent backup of your data.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=upgrade-postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;stopping-and-uninstalling&quot;&gt;Stopping and Uninstalling&lt;/h3&gt;
&lt;p&gt;To &lt;strong&gt;stop&lt;/strong&gt; all Matrix services:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=stop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To completely &lt;strong&gt;uninstall and delete all data&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ansible-playbook&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inventory/hosts setup.yml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags=uninstall&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DATA LOSS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;uninstall&lt;/code&gt; tag is destructive and will remove all user data, chat history, and media. Use with extreme caution.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;15-troubleshooting&quot;&gt;15. Troubleshooting&lt;/h2&gt;
&lt;p&gt;Below are common issues and quick checks to resolve them.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            TIP: VERIFY ONE LAYER AT A TIME
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;When in doubt, verify DNS → Traefik → Nginx &lt;code&gt;.well-known&lt;/code&gt; → Synapse federation endpoint step by step. Isolate the layer that fails.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;15-1-federation-test-fails&quot;&gt;15.1 Federation test fails&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ensure port 8448 is exposed by Traefik and the &lt;code&gt;synapse&lt;/code&gt; entrypoint exists.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose ps traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; inspect traefik&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.[0].NetworkSettings.Ports[&amp;quot;8448/tcp&amp;quot;]&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Test the federation version endpoint directly:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://matrix.your-domain.com:8448/_matrix/federation/v1/version&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;15-2-well-known-is-invalid-or-missing&quot;&gt;15.2 .well-known is invalid or missing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Verify the &lt;code&gt;.well-known&lt;/code&gt; delegation from your root domain (served by &lt;a href=&quot;../nginx-webserver/&quot;&gt;Nginx server&lt;/a&gt;):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://your-domain.com/.well-known/matrix/server&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://your-domain.com/.well-known/matrix/client&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;For this Traefik setup, &lt;code&gt;/.well-known/matrix/server&lt;/code&gt; must return &lt;code&gt;&quot;m.server&quot;: &quot;matrix.your-domain.com:8448&quot;&lt;/code&gt;. A value ending in &lt;code&gt;:443&lt;/code&gt; only works if your federation router is intentionally exposed on port 443.&lt;/li&gt;
&lt;li&gt;Re-check that the placeholders in &lt;code&gt;conf/nginx.conf&lt;/code&gt; were replaced via &lt;code&gt;sed&lt;/code&gt; and that CORS headers middleware uses camelCase keys in Traefik labels (e.g., &lt;code&gt;accessControlAllowOriginList&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;15-3-traefik-crowdsec-middleware-not-applied&quot;&gt;15.3 Traefik/CrowdSec middleware not applied&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ensure you reference providers correctly:
&lt;ul&gt;
&lt;li&gt;Security headers: &lt;code&gt;security-headers@file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CrowdSec bouncer: &lt;code&gt;crowdsec-bouncer@docker&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;15-4-acme-tls-issues&quot;&gt;15.4 ACME/TLS issues&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Inspect Traefik logs for ACME errors and DNS problems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n 200&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tail&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n 200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Confirm A/AAAA records for &lt;code&gt;traefik.your-domain.com&lt;/code&gt; and &lt;code&gt;matrix.your-domain.com&lt;/code&gt; point to your server and that port 443 is reachable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disable CDN Proxy for Initial Certificate:&lt;/strong&gt; If you are using a CDN like Cloudflare, ensure the proxy is disabled (set to “DNS Only” or “grey cloud”) for your domains during the first certificate request. The HTTP-01 challenge requires Let’s Encrypt to reach your server directly. You can re-enable the proxy after the certificate is issued.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;15-5-docker-network-not-found&quot;&gt;15.5 Docker network not found&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Make sure the external &lt;code&gt;proxy&lt;/code&gt; network exists and is used by all services behind Traefik:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; network ls&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; network create proxy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;15-6-permission-problems-in-inventory-host-vars&quot;&gt;15.6 Permission problems in inventory/host_vars&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If editing files is cumbersome, you can align ownership (optional):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span&gt;$USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; /opt/containers/matrix/inventory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;15-7-ansible-venv-not-active&quot;&gt;15.7 Ansible/venv not active&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If you installed Ansible in a virtualenv, reactivate it before running playbooks:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.venvs/matrix-ansible/bin/activate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;15-8-crowdsec-bouncer-not-registered&quot;&gt;15.8 CrowdSec bouncer not registered&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Check the bouncer status inside the CrowdSec container (run in your Traefik stack directory):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec crowdsec cscli bouncers list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;15-9-element-call-missing-matrix-rtc-transport&quot;&gt;15.9 Element Call: &lt;code&gt;MISSING_MATRIX_RTC_TRANSPORT&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If Element Web or another client says the server is not configured for Element Call and reports &lt;code&gt;MISSING_MATRIX_RTC_TRANSPORT&lt;/code&gt;, the client did not discover your MatrixRTC/LiveKit transport.&lt;/p&gt;
&lt;p&gt;When using Element Call with LiveKit, the root-domain &lt;code&gt;/.well-known/matrix/client&lt;/code&gt; response must include the RTC focus information in addition to the homeserver delegation:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;m.homeserver&amp;quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;base_url&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;https://matrix.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;org.matrix.msc4143.rtc_foci&amp;quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;livekit&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;livekit_service_url&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;https://matrix.your-domain.com/livekit-jwt-service&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the root domain serves &lt;code&gt;.well-known&lt;/code&gt; from an Nginx container with a single-file bind mount, replacing the file on the host may leave the running container attached to the old inode. After editing the well-known response, recreate the Nginx container or edit the mounted file in place and reload Nginx.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now have a fully functional, federated Matrix Synapse homeserver integrated with your Traefik proxy and Nginx web server. This powerful setup not only gives you control over your own secure communications but is also extensible with numerous bridges and features, allowing you to create a central hub for all your chat services.&lt;/p&gt;
&lt;p&gt;If you want to require TOTP or WebAuthn for compatible human SSO logins, continue with &lt;strong&gt;&lt;a href=&quot;../authelia-matrix-synapse-2fa/&quot;&gt;Adding Authelia 2FA to Matrix Synapse with OpenID Connect&lt;/a&gt;&lt;/strong&gt;. Read its Element X compatibility gate and existing-account migration checks before disabling local passwords.&lt;/p&gt;
&lt;a href=&quot;https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/README.md&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;PLAYBOOK DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://matrix.org/docs/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🛡️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;MATRIX DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;../authelia-matrix-synapse-2fa/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔐&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ADD AUTHELIA 2FA&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying the Nextcloud Talk High-Performance Backend with Docker</title>
          <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/nextcloud-talk-high-performance-backend/</link>
          <guid>https://criticalbasics.xyz/posts/nextcloud-talk-high-performance-backend/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/nextcloud-talk-high-performance-backend/">&lt;p&gt;This guide will walk you through deploying the official Nextcloud Talk High-Performance Backend (HPBE). This backend, which includes a signaling server (Spreed), a STUN/TURN server (Coturn), and a WebRTC MCU (Janus), significantly improves the performance and reliability of video calls, especially for multiple participants.&lt;/p&gt;
&lt;p&gt;This setup is designed to integrate seamlessly with an existing Traefik v3 reverse proxy, making it a powerful addition to your self-hosted infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Recording Update:&lt;/strong&gt; Added migration notes, pinned helper versions, Janus IP checks, TURN cert refresh, and Talk recording guidance.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-09-21&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide created, focusing on Docker Compose deployment and Traefik v3 integration.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide is part of a series and builds upon a secure Docker environment. Before you begin, you must have a fully functional Traefik v3 and CrowdSec stack.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            HARD REQUIREMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The following steps will not work correctly without the Traefik stack running as described in the prerequisite guide.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;: This is the foundation for our reverse proxy and security.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;You will also need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker and Docker Compose installed on your server.&lt;/li&gt;
&lt;li&gt;A dedicated subdomain for the signaling server (e.g., &lt;code&gt;signaling.your-domain.com&lt;/code&gt;) pointed to your server’s IP address.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;git&lt;/code&gt; utility installed (&lt;code&gt;sudo apt install git&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Firewall ports &lt;code&gt;80&lt;/code&gt;, &lt;code&gt;443&lt;/code&gt;, &lt;code&gt;3478/tcp&lt;/code&gt;, &lt;code&gt;3478/udp&lt;/code&gt; open. The ports &lt;code&gt;3478&lt;/code&gt; are required by the Coturn (TURN) server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;1-1-firewall-configuration-ufw-example&quot;&gt;1.1. Firewall Configuration (UFW Example)&lt;/h3&gt;
&lt;p&gt;If you are using &lt;code&gt;ufw&lt;/code&gt; (Uncomplicated Firewall), you can open the required ports with the following commands:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 3478/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 3478/udp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Example with media range 20000–20100 (choose any suitable range)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 20000:20100/udp&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;   # match your Janus media range&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Only if you enable TURNS (section 3.4):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 5349/tcp&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;         # required for TURNS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sudo ufw allow 5349/udp       # optional; enable only if you need UDP on 5349&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: Choose a media port range that is allowed by your provider/network. The exact same range must be configured in both &lt;code&gt;docker-compose.yml&lt;/code&gt; (Janus service &lt;code&gt;ports&lt;/code&gt;) and &lt;code&gt;janus/janus.jcfg&lt;/code&gt; (media min/max).&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            SECURITY NOTE &amp; CROWDSEC INTEGRATION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The TURN ports (&lt;code&gt;3478&lt;/code&gt;) are exposed directly and are not protected by the Traefik CrowdSec Bouncer. Securing them should be done at the host level.&lt;/p&gt;
&lt;p&gt;For advanced protection against abuse (e.g., brute-force attacks on the TURN server), you can feed Coturn’s logs into CrowdSec. This is achieved by configuring Docker’s logging driver for the &lt;code&gt;coturn&lt;/code&gt; service and telling CrowdSec where to find these logs.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure CrowdSec to read Docker logs:&lt;/strong&gt;
Open the acquisition file from the prerequisite guide and append the following YAML document. This tells CrowdSec to read the logs for the container named &lt;code&gt;coturn&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;File to edit: &lt;code&gt;/opt/containers/traefik-stack/crowdsec/config/acquis.yaml&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;source&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;container_name_regexp&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ^coturn$&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  type&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; coturn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Restart CrowdSec:&lt;/strong&gt;
For the new acquisition configuration to take effect, restart the CrowdSec container in your Traefik stack.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Navigate to your Traefik stack directory and restart only CrowdSec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose restart crowdsec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CrowdSec will now automatically parse the logs for the &lt;code&gt;coturn&lt;/code&gt; container. The &lt;code&gt;coturn&lt;/code&gt; service in &lt;code&gt;docker-compose.yml&lt;/code&gt; should also be configured with a logging driver to enable log rotation.&lt;/p&gt;
&lt;p&gt;If you use the CrowdSec Firewall Bouncer (iptables/nftables), ensure the Janus media UDP range (e.g., &lt;code&gt;20000–20100/udp&lt;/code&gt;), Coturn relay range (&lt;code&gt;30000–30100/udp&lt;/code&gt;), and TURN ports (&lt;code&gt;3478/tcp&lt;/code&gt;, &lt;code&gt;3478/udp&lt;/code&gt; and, if enabled, &lt;code&gt;5349/tcp&lt;/code&gt; [required], &lt;code&gt;5349/udp&lt;/code&gt; [optional]) are explicitly allowed and not blocked by bouncer rules.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;1-2-resource-planning&quot;&gt;1.2. Resource Planning&lt;/h3&gt;
&lt;p&gt;The High-Performance Backend, especially the Janus MCU, can be resource-intensive during video calls. For a small group of users (e.g., 3-5 concurrent participants in a call), plan for at least &lt;strong&gt;1-2 dedicated CPU cores and 2-4 GB of RAM&lt;/strong&gt; for the HPBE stack. For larger deployments, monitor your resource usage and scale accordingly. To keep an eye on performance, regularly check resource usage with tools like &lt;code&gt;htop&lt;/code&gt;, &lt;code&gt;docker stats&lt;/code&gt;, or a more comprehensive monitoring stack like Prometheus and Grafana.&lt;/p&gt;
&lt;h2 id=&quot;2-directory-structure-and-download&quot;&gt;2. Directory Structure and Download&lt;/h2&gt;
&lt;p&gt;First, we will clone the official repository, which contains all the necessary Docker configurations.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Navigate to your main containers directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Clone the repository&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git clone https://github.com/strukturag/nextcloud-spreed-signaling.git nextcloud-hpbe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Enter the new directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-hpbe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-configuration-files&quot;&gt;3. Configuration Files&lt;/h2&gt;
&lt;p&gt;This setup uses two main configuration files: &lt;code&gt;docker-compose.yml&lt;/code&gt; for defining the services and &lt;code&gt;server.conf&lt;/code&gt; for the signaling server itself. All configuration values will be hardcoded directly into these files for simplicity and clarity.&lt;/p&gt;
&lt;h3 id=&quot;3-1-docker-compose-file-docker-compose-yml&quot;&gt;3.1. Docker Compose File (&lt;code&gt;docker-compose.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Create the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. This version uses a hardcoded configuration and is optimized for Traefik v3.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  spreedbackend:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    build:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      context: .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      dockerfile: docker/server/Dockerfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      platforms:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;linux/amd64&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: spreedbackend&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - nats&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - janus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - coturn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./server.conf:/config/server.conf:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Router for certificate acquisition (Host-only rule)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe-cert.rule=Host(`signaling.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe-cert.entrypoints=web,websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe-cert.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe-cert.priority=1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Router for the actual service (Host + Path rule)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe.rule=Host(`signaling.your-domain.com`) &amp;amp;&amp;amp; PathPrefix(`/standalone-signaling`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe.tls=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe.priority=100&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Middlewares: Set X-Forwarded-Proto and strip the path prefix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.hpbe-headers.headers.customRequestHeaders.X-Forwarded-Proto=https&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.hpbe-strip.stripprefix.prefixes=/standalone-signaling&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.hpbe.middlewares=hpbe-headers@docker,hpbe-strip@docker,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Internal service port&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.hpbe.loadbalancer.server.port=8080&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  nats:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: nats:2.14.3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: nats&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command: [&amp;quot;-c&amp;quot;, &amp;quot;/config/gnatsd.conf&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - type: bind&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        source: ./gnatsd.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        target: /config/gnatsd.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        read_only: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  janus:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # Build Janus from source using the provided Dockerfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    build: docker/janus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: janus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command: [&amp;quot;janus&amp;quot;, &amp;quot;--full-trickle&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ports:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;20000-20100:20000-20100/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Optional only if you enabled ice_tcp=true (see section 3.3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # - &amp;quot;20000-20100:20000-20100/tcp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./janus/janus.jcfg:/usr/local/etc/janus/janus.jcfg:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  coturn:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: coturn/coturn:4.14.0-r0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: coturn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    logging:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      driver: &amp;quot;json-file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      options:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        max-size: &amp;quot;10m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        max-file: &amp;quot;3&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--realm&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;signaling.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--static-auth-secret&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;PASTE-A-STRONG-RANDOM-32-CHAR-HEX-SECRET-HERE&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--no-stdout-log&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--log-file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;stdout&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--stale-nonce=600&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--use-auth-secret&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Using shared-secret auth only; lt-cred-mech omitted to avoid mixed-auth warning&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--fingerprint&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--no-software-attribute&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--no-multicast-peers&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--min-port&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;30000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--max-port&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;30100&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--cert&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;/certs/fullchain.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--pkey&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;/certs/privkey.pem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;--tls-listening-port&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;5349&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ports:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;3478:3478/tcp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;3478:3478/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;5349:5349/tcp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;5349:5349/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;30000-30100:30000-30100/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./certs:/certs:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: Before launching, create &lt;code&gt;janus/janus.jcfg&lt;/code&gt; as described in section 3.3 (set &lt;code&gt;nat_1_1_mapping&lt;/code&gt; and the &lt;code&gt;min_port&lt;/code&gt;/&lt;code&gt;max_port&lt;/code&gt; media port range).&lt;/p&gt;
&lt;p&gt;Note: On hosts with a direct public IP, you typically do not need to set Coturn’s &lt;code&gt;--listening-ip&lt;/code&gt;, &lt;code&gt;--relay-ip&lt;/code&gt;, or &lt;code&gt;--external-ip&lt;/code&gt;. Relying on defaults avoids common binding errors (e.g., “Cannot assign requested address”, errno=99). Only set &lt;code&gt;--external-ip PUBLIC_IP/PRIVATE_HOST_IP&lt;/code&gt; (and optionally &lt;code&gt;--listening-ip&lt;/code&gt;/&lt;code&gt;--relay-ip&lt;/code&gt; to the private host IP) if your host is behind NAT.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            SERVER MIGRATION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;When moving this stack to a new server, update Janus’ &lt;code&gt;nat_1_1_mapping&lt;/code&gt; before testing calls. If it still advertises the old public IP address, signaling may work while media fails because clients receive unreachable ICE candidates.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-2-signaling-server-config-server-conf&quot;&gt;3.2. Signaling Server Config (&lt;code&gt;server.conf&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file configures the core logic of the HPBE. Create &lt;code&gt;server.conf&lt;/code&gt;, paste the template below, and replace the placeholder values with your own secrets and URLs.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee server.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[http]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;listen = 0.0.0.0:8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[app]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;debug = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[sessions]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Use &amp;#39;openssl rand -base64 16&amp;#39; to generate these&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;hashkey = PASTE-A-RANDOM-BASE64-KEY-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;blockkey = PASTE-A-RANDOM-BASE64-KEY-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[backend]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;backends = backend-1 #, backend-2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;allowall = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;timeout = 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;connectionsperhost = 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[backend-1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;url = https://cloud.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Use &amp;#39;openssl rand -hex 16&amp;#39; to generate this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;secret = PASTE-A-RANDOM-HEX-SECRET-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# To add a second backend, add it to the &amp;#39;backends&amp;#39; list and create a new section&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# [backend-2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# url = https://another-cloud.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# secret = PASTE-ANOTHER-RANDOM-HEX-SECRET-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[nats]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;url = nats://nats:4222&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[mcu]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;type = janus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;url = ws://janus:8188&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[turn]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Use &amp;#39;openssl rand -base64 16&amp;#39; to generate this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;apikey = PASTE-A-RANDOM-BASE64-KEY-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# This secret MUST be identical to the &amp;#39;--static-auth-secret&amp;#39; in docker-compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;secret = PASTE-THE-SAME-STRONG-SECRET-AS-IN-DOCKER-COMPOSE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;servers = turn:signaling.your-domain.com:3478?transport=udp,turn:signaling.your-domain.com:3478?transport=tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            SYNCHRONIZE TURN SECRET
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;secret&lt;/code&gt; in the &lt;code&gt;[turn]&lt;/code&gt; section of this file &lt;strong&gt;must&lt;/strong&gt; be identical to the &lt;code&gt;--static-auth-secret&lt;/code&gt; value used in the &lt;code&gt;coturn&lt;/code&gt; service in your &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Ensure the file has the correct permissions: &lt;code&gt;sudo chmod 644 server.conf&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;3-2-1-replace-placeholders-and-generate-secrets&quot;&gt;3.2.1 Replace placeholders and generate secrets&lt;/h3&gt;
&lt;p&gt;Before launching, perform these steps so your setup works on your domain and with strong secrets.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Replace the domain placeholder&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We use &lt;code&gt;signaling.your-domain.com&lt;/code&gt; as a placeholder. Replace it with your real domain in both files:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-hpbe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;s/signaling\.your-domain\.com/signaling.example.com/g&amp;#39; docker-compose.yml server.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;signaling.example.com&lt;/code&gt; with your actual TURN/signaling domain.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Generate the required secrets with openssl&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Sessions keys (base64) for &lt;code&gt;server.conf&lt;/code&gt; &lt;code&gt;[sessions]&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -base64 16&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # paste as sessions.hashkey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -base64 16&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # paste as sessions.blockkey&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Backend shared secret (hex) for each Nextcloud in &lt;code&gt;server.conf&lt;/code&gt; &lt;code&gt;[backend-*]&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 16&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     # paste as backend-1.secret (and for backend-2, backend-3, ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;TURN API key (base64) for &lt;code&gt;server.conf&lt;/code&gt; &lt;code&gt;[turn] apikey&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -base64 16&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # paste as turn.apikey&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;TURN static secret (hex) used in BOTH places:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;server.conf&lt;/code&gt; &lt;code&gt;[turn] secret&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;docker-compose &lt;code&gt;coturn&lt;/code&gt; command &lt;code&gt;--static-auth-secret&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 16&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     # paste into both places, values must be identical&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Open firewall ports (host level)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 3478/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 3478/udp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 20000:20100/udp&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;   # Janus media range&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 30000:30100/udp&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;   # Coturn relay range&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# The main docker-compose includes TURNS by default:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 5349/tcp&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;         # required for TURNS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sudo ufw allow 5349/udp       # optional; some clients might use it&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-2-2-example-multiple-nextcloud-backends&quot;&gt;3.2.2 Example: Multiple Nextcloud backends&lt;/h3&gt;
&lt;p&gt;If you operate more than one Nextcloud that should use the same signaling backend, model your &lt;code&gt;[backend]&lt;/code&gt; section like this. Replace the example domains and secrets with your own.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[backend]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;backends&lt;/span&gt;&lt;span&gt; = backend-1, backend-2, backend-3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;allowall&lt;/span&gt;&lt;span&gt; = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;timeout&lt;/span&gt;&lt;span&gt; = 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;connectionsperhost&lt;/span&gt;&lt;span&gt; = 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[backend-1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;url&lt;/span&gt;&lt;span&gt; = https://cloud1.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;secret&lt;/span&gt;&lt;span&gt; = PASTE-A-RANDOM-HEX-SECRET-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[backend-2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;url&lt;/span&gt;&lt;span&gt; = https://cloud2.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;secret&lt;/span&gt;&lt;span&gt; = PASTE-A-RANDOM-HEX-SECRET-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[backend-3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;url&lt;/span&gt;&lt;span&gt; = https://cloud3.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;secret&lt;/span&gt;&lt;span&gt; = PASTE-A-RANDOM-HEX-SECRET-HERE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: The &lt;code&gt;secret&lt;/code&gt; for each backend must match the “Shared secret” you configure in that specific Nextcloud under Admin -&amp;gt; Talk.&lt;/p&gt;
&lt;h4 id=&quot;3-2-3-optional-bind-the-http-listener-to-the-service-name&quot;&gt;3.2.3 Optional: Bind the HTTP listener to the service name&lt;/h4&gt;
&lt;p&gt;By default this guide uses &lt;code&gt;listen = 0.0.0.0:8080&lt;/code&gt; in &lt;code&gt;[http]&lt;/code&gt;, which is simple and works well behind Traefik. If you prefer to bind strictly to the Docker service name, you can set:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[http]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;listen&lt;/span&gt;&lt;span&gt; = spreedbackend:8080&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both are valid in a single Docker network; choose the variant that fits your operational preference.&lt;/p&gt;
&lt;h3 id=&quot;3-3-janus-nat-and-media-ports-required-for-working-audio-video&quot;&gt;3.3. Janus NAT and Media Ports (required for working audio/video)&lt;/h3&gt;
&lt;p&gt;WebRTC media flows (DTLS/SRTP) are carried on a dynamic UDP port range on the Janus SFU. If these ports are not reachable from the internet, calls will not establish and you will see errors like “publisher not sending yet” or repeated “requestoffer: context deadline exceeded” in the signaling logs.&lt;/p&gt;
&lt;p&gt;Do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a minimal Janus config that sets public IP mapping and a fixed media port range&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Create &lt;code&gt;./janus/janus.jcfg&lt;/code&gt; with the following content. Replace &lt;code&gt;PUBLIC.IP.OR.DNS&lt;/code&gt; with your server’s public address or a DNS name that resolves to it (no CDN/Orange-Cloud in front):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Minimal but complete Janus config for operation behind Docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# with a fixed UDP port range and correct 1:1 NAT mapping.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;general: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  configs_folder&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/usr/local/etc/janus&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Keep logging at &amp;quot;info&amp;quot; (default), set &amp;quot;debug = true&amp;quot; if needed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;at: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Important: public IP or DNS of the host that clients should see&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  nat_1_1_mapping&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;signaling.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # SRFLX candidates (optional, but doesn&amp;#39;t hurt)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  stun_server&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;signaling.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  stun_port&lt;/span&gt;&lt;span&gt;   = 3478&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # ICE Lite is fine for SFU operation and reduces complexity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  ice_lite&lt;/span&gt;&lt;span&gt; = true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;media: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Fixed, small port range: must match docker-compose (ports:)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  min_port&lt;/span&gt;&lt;span&gt; = 20000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  max_port&lt;/span&gt;&lt;span&gt; = 20100&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Prefer UDP (TCP disabled as it&amp;#39;s often problematic/unnecessary)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  ice_tcp&lt;/span&gt;&lt;span&gt; = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # (Optional) Enforce RTCP-MUX – common default, can help&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  rtcp_mux&lt;/span&gt;&lt;span&gt; = true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Websockets (HPBE communicates internally via ws://janus:8188)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Defaults are fine, no extra port publishing needed as it&amp;#39;s in the same Docker network.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;websockets: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  ws&lt;/span&gt;&lt;span&gt; = true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  ws_port&lt;/span&gt;&lt;span&gt; = 8188&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  ws_interface&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# REST &amp;amp; Admin disabled by default – not needed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;admin: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  admin_http&lt;/span&gt;&lt;span&gt; = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  admin_secret&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;changeit&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Ensure your main docker-compose includes the Janus media ports and config mount&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In section 3.1, the &lt;code&gt;janus&lt;/code&gt; service already contains the required &lt;code&gt;ports&lt;/code&gt; and &lt;code&gt;volumes&lt;/code&gt; lines. Verify that your configuration matches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ports: &quot;20000-20100:20000-20100/udp&quot;&lt;/code&gt; (optional TCP only if &lt;code&gt;ice_tcp=true&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;volumes: ./janus/janus.jcfg:/usr/local/etc/janus/janus.jcfg:ro&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Open the firewall for the media range (host level)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 20000:20100/udp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Adjust to the exact range you configured in janus.jcfg and docker-compose&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Only if you enabled ice_tcp=true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sudo ufw allow 20000:20100/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            CAPACITY PLANNING FOR MEDIA PORTS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;With RTCP-MUX/BUNDLE (Janus default), each active PeerConnection typically uses about one UDP port on the server.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Plan roughly 1 port per active participant (conservatively 2 if features like separate screen-share/recording open additional PeerConnections).&lt;/li&gt;
&lt;li&gt;Examples (illustrative):
&lt;ul&gt;
&lt;li&gt;Range 40000–40050 (51 ports) → about 25–50 concurrent PeerConnections (small groups).&lt;/li&gt;
&lt;li&gt;Range 40000–40199 (200 ports) → more headroom for spikes and larger meetings.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Always match your firewall (UFW) and CrowdSec rules to the same UDP range you configured in &lt;code&gt;janus.jcfg&lt;/code&gt; and in the &lt;code&gt;janus&lt;/code&gt; service &lt;code&gt;ports&lt;/code&gt;. The above examples use 40000-based ranges; choose the range you actually configured (e.g., 20000–20100).&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Apply the changes&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;If you have not launched the stack yet, skip this step. The changes will take effect when you start the stack in section 4.&lt;/li&gt;
&lt;li&gt;If Janus is already running, apply the updated config now:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --force-recreate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; janus&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Verify during a call attempt&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;In Firefox &lt;code&gt;about:webrtc&lt;/code&gt; or Chrome &lt;code&gt;chrome://webrtc-internals&lt;/code&gt; check that the remote ICE candidates from Janus show your public IP with ports in &lt;code&gt;20000–20100&lt;/code&gt; and that the ICE state becomes &lt;code&gt;connected/completed&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On the server, you should see traffic on those ports while a call is setting up:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tcpdump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -ni&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; any udp port&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3478&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tcpdump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -ni&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; any udp portrange 20000-20100&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you exclusively rely on shared-secret auth for TURN, you can still keep section 3.4 (TURNS) as-is; TURN helps with client NAT traversal but cannot replace opening Janus’ own media ports.&lt;/p&gt;
&lt;h3 id=&quot;3-4-enable-turn-over-tls-5349&quot;&gt;3.4. Enable TURN over TLS (5349)&lt;/h3&gt;
&lt;p&gt;Enabling &lt;code&gt;turns:&lt;/code&gt; adds TLS encryption to TURN traffic on port &lt;code&gt;5349&lt;/code&gt;. This often helps in restrictive networks and hides credentials from passive observers.&lt;/p&gt;
&lt;p&gt;Steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create the certs directory and export PEMs from Traefik’s ACME store&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since this guide builds on the prerequisite &lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec tutorial&lt;/a&gt;, your certificates are stored in Traefik’s ACME database at &lt;code&gt;/opt/containers/traefik-stack/traefik/certs/acme.json&lt;/code&gt;. Export the certificate and key for your TURN domain into &lt;code&gt;./certs&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-hpbe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Domain used for TURN/TURNS (anonymized placeholder)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TURN_DOMAIN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;signaling.your-domain.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ACME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/opt/containers/traefik-stack/traefik/certs/acme.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ensure tools are available&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt-get update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt-get install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create output directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./certs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# (Directory permissions are set in step 1.1 below)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Extract certificate and key for the TURN domain from acme.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; d &amp;quot;&lt;/span&gt;&lt;span&gt;$TURN_DOMAIN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  .. | objects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  | select(has(&amp;quot;domain&amp;quot;) and (.domain.main==$d or ((.domain.sans // []) | index($d))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  | .certificate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$ACME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; base64&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee ./certs/fullchain.pem&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; d &amp;quot;&lt;/span&gt;&lt;span&gt;$TURN_DOMAIN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  .. | objects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  | select(has(&amp;quot;domain&amp;quot;) and (.domain.main==$d or ((.domain.sans // []) | index($d))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  | .key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$ACME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; base64&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee ./certs/privkey.pem&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: The certificate must match the TURN realm/domain you advertise (e.g., &lt;code&gt;signaling.your-domain.com&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;1.1 Set Certificate and Directory Permissions&lt;/p&gt;
&lt;p&gt;Coturn does not run as root inside the container, but as the &lt;code&gt;nobody:nogroup&lt;/code&gt; user. Without the correct permissions on both the directory and the files, Coturn cannot read the certificates and the &lt;code&gt;turns:&lt;/code&gt; connection will fail (often shown as red in Nextcloud Talk).&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# In your project directory (e.g., /opt/containers/nextcloud-hpbe)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Detect the group ID used by Coturn inside the container (commonly 65534 for &amp;#39;nogroup&amp;#39;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; coturn sh&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;id -g&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;\r&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Ensure the certs directory is accessible to that group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chgrp &amp;quot;&lt;/span&gt;&lt;span&gt;$GID&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; ./certs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 750&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./certs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Set group ownership and restrictive permissions on the files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chgrp &amp;quot;&lt;/span&gt;&lt;span&gt;$GID&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; ./certs/privkey.pem ./certs/fullchain.pem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 640&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./certs/privkey.pem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 644&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./certs/fullchain.pem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Restart Coturn to load the updated certificates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --force-recreate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; coturn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: If your image uses the default &lt;code&gt;nobody:nogroup&lt;/code&gt;, you may alternatively use &lt;code&gt;sudo chgrp nogroup ...&lt;/code&gt; instead of the detected GID.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;TLS is already configured in the main &lt;code&gt;docker-compose.yml&lt;/code&gt; in this guide. After creating/exporting the certificates in step 1, simply recreate Coturn so it picks up the TLS files.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note: If you exclusively use shared-secret auth (&lt;code&gt;--use-auth-secret&lt;/code&gt; with &lt;code&gt;--static-auth-secret&lt;/code&gt;), you can omit &lt;code&gt;--lt-cred-mech&lt;/code&gt; to avoid a warning.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Update your &lt;code&gt;server.conf&lt;/code&gt; &lt;code&gt;servers&lt;/code&gt; list to include the &lt;code&gt;turns:&lt;/code&gt; endpoint:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[turn]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;servers&lt;/span&gt;&lt;span&gt; = turn:signaling.your-domain.com:3478?&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;transport&lt;/span&gt;&lt;span&gt;=udp,turn:signaling.your-domain.com:3478?&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;transport&lt;/span&gt;&lt;span&gt;=tcp,turns:signaling.your-domain.com:5349?&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;transport&lt;/span&gt;&lt;span&gt;=tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Open the firewall for port &lt;code&gt;5349&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 5349/tcp&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;         # required for TURNS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sudo ufw allow 5349/udp       # optional; enable only if you need UDP on 5349&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;4-launch-the-stack&quot;&gt;4. Launch the Stack&lt;/h2&gt;
&lt;p&gt;With the configuration complete, you can now build and start the services.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# From within the /opt/containers/nextcloud-hpbe directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --build -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;--build&lt;/code&gt; flag is important because it builds the Janus and the &lt;code&gt;spreedbackend&lt;/code&gt; images from their Dockerfiles. The Janus build, in particular, can take several minutes.&lt;/p&gt;
&lt;p&gt;You can monitor the logs to ensure everything starts correctly:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-1-verify-turn-turns-endpoints&quot;&gt;4.1 Verify TURN/TURNS endpoints&lt;/h3&gt;
&lt;p&gt;If &lt;code&gt;nc&lt;/code&gt; is not installed, install it first:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt-get update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt-get install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; netcat-openbsd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run these quick checks from a client or your server to verify connectivity:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1) Check TCP reachability (expect &amp;quot;succeeded&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nc&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -vz&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; signaling.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3478&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nc&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -vz&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; signaling.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5349&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # only if TURNS enabled&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2) Verify TLS on 5349 (should show certificate details; only if TURNS is enabled)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; s_client&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -connect&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; signaling.your-domain.com:5349&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -servername&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; signaling.your-domain.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -brief&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3) Check Coturn runtime logs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; coturn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have &lt;code&gt;turnutils_uclient&lt;/code&gt; available (from the coturn package), you can perform an end-to-end TURN allocation test as an advanced check.&lt;/p&gt;
&lt;h2 id=&quot;5-configure-nextcloud&quot;&gt;5. Configure Nextcloud&lt;/h2&gt;
&lt;p&gt;The final step is to tell your Nextcloud instance to use the new High-Performance Backend.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to Nextcloud as an administrator.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Administration Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Talk&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Scroll down to the “Signaling server” section.&lt;/li&gt;
&lt;li&gt;Check “Enable custom signaling server”.&lt;/li&gt;
&lt;li&gt;In the “Signaling server URL” field, enter the full path to your HPBE: &lt;code&gt;https://signaling.your-domain.com/standalone-signaling&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In the “Shared secret” field, paste the corresponding shared secret for this specific Nextcloud instance (e.g., the value of &lt;code&gt;NEXTCLOUD_1_SHARED_SECRET&lt;/code&gt; for your first instance).&lt;/li&gt;
&lt;li&gt;Click “Save changes”.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nextcloud will verify the connection. If everything is correct, you’re all set!&lt;/p&gt;
&lt;h3 id=&quot;clarifying-secret-mappings&quot;&gt;Clarifying Secret Mappings&lt;/h3&gt;
&lt;p&gt;To ensure all components communicate securely, it’s crucial to map the secrets correctly. Here is a quick reference:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;code&gt;server.conf&lt;/code&gt; Section &amp;amp; Key&lt;/th&gt;&lt;th&gt;Maps to…&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[backend]&lt;/code&gt; -&amp;gt; &lt;code&gt;secret&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Nextcloud Admin -&amp;gt; Talk -&amp;gt; &lt;strong&gt;Shared secret&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Authenticates Nextcloud with the signaling server.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[turn]&lt;/code&gt; -&amp;gt; &lt;code&gt;apikey&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Used by the signaling server to generate time-limited TURN credentials for clients. Janus does not use this key in this setup.&lt;/td&gt;&lt;td&gt;Allows signaling server to get TURN credentials.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[turn]&lt;/code&gt; -&amp;gt; &lt;code&gt;secret&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;coturn&lt;/code&gt; service -&amp;gt; &lt;code&gt;--static-auth-secret&lt;/code&gt; command argument&lt;/td&gt;&lt;td&gt;Authenticates TURN users (generated by signaling).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;6-talk-recording&quot;&gt;6. Talk Recording&lt;/h2&gt;
&lt;p&gt;Nextcloud Talk recording is a separate service. It is not provided automatically just because HPB, Janus, and Coturn are running.&lt;/p&gt;
&lt;p&gt;Create a separate stack, for example &lt;code&gt;/opt/containers/nextcloud-talk-recording/docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  nextcloud-talk-recording&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud/aio-talk-recording:20260609_115915&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    container_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-talk-recording&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    shm_size&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;4gb&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; TZ=Europe/Berlin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; NC_DOMAIN=cloud.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; HPB_DOMAIN=signaling.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; RECORDING_SECRET=PASTE-A-STRONG-RECORDING-SECRET-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; INTERNAL_SECRET=PASTE-A-STRONG-INTERNAL-SECRET-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./recording.conf:/conf/recording.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.nextcloud-talk-recording.rule=Host(`recording.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.nextcloud-talk-recording.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.nextcloud-talk-recording.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.nextcloud-talk-recording.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.nextcloud-talk-recording.loadbalancer.server.port=1234&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  proxy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not mount &lt;code&gt;recording.conf&lt;/code&gt; read-only. Current recording images generate or update &lt;code&gt;/conf/recording.conf&lt;/code&gt; from environment variables at startup. A read-only bind mount can cause startup warnings or broken configuration.&lt;/p&gt;
&lt;p&gt;If DNS still points &lt;code&gt;signaling.your-domain.com&lt;/code&gt; to an old server during a migration, add a temporary &lt;code&gt;extra_hosts&lt;/code&gt; entry so the recording container reaches the new HPB stack. Remove it after DNS cutover:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;extra_hosts&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;signaling.your-domain.com:YOUR_NEW_SERVER_IP&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Nextcloud’s Talk admin settings, configure the recording server URL and recording secret to match this stack.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            RECORDING VALIDATION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;A &lt;code&gt;404&lt;/code&gt; on &lt;code&gt;https://recording.your-domain.com/&lt;/code&gt; only proves that Traefik reaches the Flask service. The real validation is starting a recording from an actual Nextcloud Talk room and confirming that the recording is produced.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;7-troubleshooting-monitoring&quot;&gt;7. Troubleshooting &amp;amp; Monitoring&lt;/h2&gt;
&lt;p&gt;If you encounter issues, here are a few steps to diagnose the problem:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Verify the Signaling Server is Reachable&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You should get a &lt;code&gt;200 OK&lt;/code&gt; response from the &lt;code&gt;/welcome&lt;/code&gt; endpoint. This confirms that Traefik is routing requests correctly.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://signaling.your-domain.com/standalone-signaling/api/v1/welcome&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check the Container Logs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The logs are the best source for identifying errors. Pay close attention to messages about secrets, WebSocket connections, or backend timeouts.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# From within the /opt/containers/nextcloud-hpbe directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Common Errors &amp;amp; Fixes&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ERROR: the sessions block key must be...&lt;/code&gt; or &lt;code&gt;hash key should be...&lt;/code&gt;&lt;/strong&gt;: This error occurs when the keys in &lt;code&gt;server.conf&lt;/code&gt; are missing or have the wrong format. Use &lt;code&gt;openssl rand -base64 16&lt;/code&gt; to generate new keys and paste them into the &lt;code&gt;[sessions]&lt;/code&gt; section.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TURN Secret Mismatch&lt;/strong&gt;: If calls fail to connect, verify that the &lt;code&gt;secret&lt;/code&gt; in the &lt;code&gt;[turn]&lt;/code&gt; section of &lt;code&gt;server.conf&lt;/code&gt; is &lt;strong&gt;exactly&lt;/strong&gt; the same as the &lt;code&gt;--static-auth-secret&lt;/code&gt; in the &lt;code&gt;coturn&lt;/code&gt; command in &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“failed to establish signaling connection”&lt;/strong&gt;: This is a classic error.
&lt;ul&gt;
&lt;li&gt;Check that the URL in Nextcloud is exactly &lt;code&gt;https://.../standalone-signaling&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ensure your Traefik labels are correct (especially the &lt;code&gt;PathPrefix&lt;/code&gt; and &lt;code&gt;stripPrefix&lt;/code&gt; rules).&lt;/li&gt;
&lt;li&gt;Verify that the &lt;code&gt;Shared secret&lt;/code&gt; in Nextcloud matches the one in &lt;code&gt;server.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Media range not reachable: If ICE repeatedly fails or you see “publisher not sending yet”, ensure your chosen Janus media port range is open end-to-end (firewall/CrowdSec), and that the exact same range is configured in both &lt;code&gt;docker-compose.yml&lt;/code&gt; (Janus &lt;code&gt;ports&lt;/code&gt;) and &lt;code&gt;janus/janus.jcfg&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calls work for 2 people but fail with 3+&lt;/strong&gt;: This often points to a problem with Janus (the MCU) or Coturn (the TURN server). Check their logs specifically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No video/audio from external networks&lt;/strong&gt;: This is a typical TURN server issue. Ensure ports &lt;code&gt;3478&lt;/code&gt; (TCP/UDP) are open on your firewall and correctly forwarded to the Coturn container.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;turn:&lt;/code&gt; works, but &lt;code&gt;turns:&lt;/code&gt; fails (is red in Nextcloud)&lt;/strong&gt;: This is almost always a certificate permission issue. Coturn cannot read the TLS certificate or key. Verify that Coturn can access the files with &lt;code&gt;docker compose exec coturn ls -l /certs&lt;/code&gt;. If you see permission errors, re-run the permission-setting steps in section 3.4. You can also test externally with: &lt;code&gt;openssl s_client -connect signal.example.com:5349 -servername signal.example.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;7-1-diagnose-ice-rtp-issues-quickly&quot;&gt;7.1 Diagnose ICE/RTP issues quickly&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Check remote candidates in the browser&lt;/strong&gt;: Use &lt;code&gt;about:webrtc&lt;/code&gt; (Firefox) or &lt;code&gt;chrome://webrtc-internals&lt;/code&gt; (Chrome). You should see server-reflexive (srflx) and relayed (relay) candidates, and remote candidates from Janus on the public IP in the configured media range.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Look for ICE state&lt;/strong&gt;: &lt;code&gt;iceConnectionState&lt;/code&gt; should reach &lt;code&gt;connected/completed&lt;/code&gt;. If it stays in &lt;code&gt;checking/failed&lt;/code&gt;, open ports or NAT/public IP mapping are missing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server-side packet capture&lt;/strong&gt;: While attempting a call, run &lt;code&gt;sudo tcpdump -ni any udp portrange 20000-20100&lt;/code&gt; to confirm media packets hit the host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TURN sanity&lt;/strong&gt;: Use the Trickle ICE demo with your TURN URIs to confirm you get &lt;code&gt;relay&lt;/code&gt; candidates; verify your Coturn &lt;code&gt;realm&lt;/code&gt; and static secret match the values in &lt;code&gt;server.conf&lt;/code&gt; and &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;8-maintenance-and-updates&quot;&gt;8. Maintenance and Updates&lt;/h2&gt;
&lt;p&gt;Updating the High-Performance Backend involves fetching the latest version while preserving your custom configurations. The recommended method is to back up your current installation, clone the new version, and restore your configuration files. This avoids potential conflicts from a direct &lt;code&gt;git pull&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-1-stop-and-back-up-the-current-installation&quot;&gt;Step 1: Stop and Back Up the Current Installation&lt;/h3&gt;
&lt;p&gt;First, stop the running services and create a backup of your entire &lt;code&gt;nextcloud-hpbe&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Navigate to the parent directory of your HPBE installation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Stop the services using the existing docker-compose file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-hpbe/docker-compose.yml down&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create a backup by renaming the directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mv nextcloud-hpbe nextcloud-hpbe_BACKUP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-2-clone-the-new-version&quot;&gt;Step 2: Clone the New Version&lt;/h3&gt;
&lt;p&gt;Clone the latest version of the repository into a clean directory with the original name.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Stay in /opt/containers/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git clone https://github.com/strukturag/nextcloud-spreed-signaling.git nextcloud-hpbe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-3-restore-your-configuration&quot;&gt;Step 3: Restore Your Configuration&lt;/h3&gt;
&lt;p&gt;Copy your essential configuration files from the backup into the new directory. This ensures your secrets, domains, and other settings are preserved.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Copy your docker-compose.yml and server.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp nextcloud-hpbe_BACKUP/docker-compose.yml nextcloud-hpbe/docker-compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp nextcloud-hpbe_BACKUP/server.conf nextcloud-hpbe/server.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-4-launch-the-updated-stack&quot;&gt;Step 4: Launch the Updated Stack&lt;/h3&gt;
&lt;p&gt;Finally, navigate into the new directory and start the services. The &lt;code&gt;--build&lt;/code&gt; flag will create new images if required, and &lt;code&gt;--remove-orphans&lt;/code&gt; cleans up any old, unused containers.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Navigate into the new HPBE directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nextcloud-hpbe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Build and start the updated services&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --build -d --remove-orphans&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After a few moments, your updated High-Performance Backend will be running. You can optionally remove the backup directory (&lt;code&gt;sudo rm -rf /opt/containers/nextcloud-hpbe_BACKUP&lt;/code&gt;) once you have confirmed everything is working correctly.&lt;/p&gt;
&lt;h3 id=&quot;migration-checklist&quot;&gt;Migration Checklist&lt;/h3&gt;
&lt;p&gt;When moving an existing HPB stack to a new server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep the public signaling hostname stable if possible.&lt;/li&gt;
&lt;li&gt;Open the TURN, TURNS, Janus media, and Coturn relay ports before DNS cutover.&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;janus/janus.jcfg&lt;/code&gt; so &lt;code&gt;nat_1_1_mapping&lt;/code&gt; points to the new public IP or DNS name.&lt;/li&gt;
&lt;li&gt;Reissue or export fresh certificates for the TURN/TURNS hostname after DNS points to the new server.&lt;/li&gt;
&lt;li&gt;Restart &lt;code&gt;coturn&lt;/code&gt; after replacing certificate files.&lt;/li&gt;
&lt;li&gt;If recording is used, make sure the recording container resolves the HPB hostname to the new server.&lt;/li&gt;
&lt;li&gt;Test with a real Talk room, including a recording test.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your TURN certificate is exported from Traefik’s &lt;code&gt;acme.json&lt;/code&gt;, repeat that export after the new server has successfully obtained the certificate:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nextcloud-hpbe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --force-recreate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; coturn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations! You have successfully deployed a Nextcloud Talk High-Performance Backend. Your users will now experience more stable and performant video calls, especially in group settings. This powerful, containerized setup integrates perfectly with a modern Traefik proxy, providing a scalable and secure solution for your communication needs.&lt;/p&gt;
&lt;a href=&quot;https://github.com/strukturag/nextcloud-spreed-signaling&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL HPBE REPOSITORY&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack</title>
          <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/traefik-v3-crowdsec-tutorial/</link>
          <guid>https://criticalbasics.xyz/posts/traefik-v3-crowdsec-tutorial/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/traefik-v3-crowdsec-tutorial/">&lt;p&gt;This guide provides a streamlined approach to deploying a powerful and secure web stack using Traefik as a reverse proxy and CrowdSec for threat protection. We will use Docker Compose to orchestrate the services, creating a setup that is easy to manage, scale, and maintain.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-07-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Related Guide:&lt;/strong&gt; Linked the reusable Authelia SSO and 2FA deployment for Traefik-protected services.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-07-01&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Migration Hardening:&lt;/strong&gt; Pinned production versions, clarified Docker socket and CrowdSec scope, and added ACME migration guidance.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-03-03&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Security Fix:&lt;/strong&gt; Added &lt;code&gt;forwardedHeaders.trustedIPs&lt;/code&gt; to both entrypoints to prevent X-Forwarded-For spoofing.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-03-03&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Component Updates &amp;amp; Syntax Fixes:&lt;/strong&gt; Updated Traefik to v3.6, CrowdSec plugin to v1.4.7, and pinned CrowdSec to v1.6. Fixed Traefik v3 &lt;code&gt;HostRegexp&lt;/code&gt; syntax and improved healthchecks.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-01-26&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Robustness Update:&lt;/strong&gt; Added AccessLog filtering to prevent disk exhaustion and improved logrotate instructions with path discovery.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-01-15&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Docs Update:&lt;/strong&gt; Removed redundant &lt;code&gt;router.tls=true&lt;/code&gt; label from the bypass example and added a new section explaining how to route multiple (sub)domains to one service.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-12-10&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Production Hardening:&lt;/strong&gt; Added comprehensive log rotation configuration and disk troubleshooting section based on real-world feedback.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-09-18&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Final Review:&lt;/strong&gt; Switched to robust httpChallenge, corrected provider in example, added raw API key generation.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-09-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Major Refactor:&lt;/strong&gt; Switched from legacy bouncer container to modern Traefik Plugin. Moved all variable configs to Docker Labels.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-07-10&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Added Special Use-Case:&lt;/strong&gt; Included a clear example of how to deploy a service &lt;em&gt;without&lt;/em&gt; CrowdSec protection for specific needs.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-07-09&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Article created based on best practices for a modern Traefik v3 and CrowdSec deployment with Docker Compose.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;Before you begin, ensure you have the following installed on your server (e.g., Ubuntu 22.04 or Debian 12):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Docker&lt;/strong&gt; and &lt;strong&gt;Docker Compose&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;openssl&lt;/code&gt;, and &lt;code&gt;apache2-utils&lt;/code&gt; (for password generation)&lt;/li&gt;
&lt;li&gt;A domain name pointed to your server’s IP address&lt;/li&gt;
&lt;li&gt;Open firewall ports &lt;code&gt;80&lt;/code&gt; and &lt;code&gt;443&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can install the required utilities with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; curl openssl apache2-utils&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;2-directory-structure&quot;&gt;2. Directory Structure&lt;/h2&gt;
&lt;p&gt;A well-organized directory structure is key. We will create a central location for our stack’s configuration and data.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create the main directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create directories for each service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik/{dynamic,logs,certs}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; crowdsec/{config,data}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Prepare Let&amp;#39;s Encrypt certificates file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; touch traefik/certs/acme.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik/certs/acme.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This structure keeps everything tidy and separated.&lt;/p&gt;
&lt;h2 id=&quot;3-configuration-files&quot;&gt;3. Configuration Files&lt;/h2&gt;
&lt;p&gt;Now, let’s create the configuration files for our stack.&lt;/p&gt;
&lt;h3 id=&quot;3-1-main-configuration-env&quot;&gt;3.1. Main Configuration (&lt;code&gt;.env&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file holds all your environment-specific variables.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- General Settings ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;TZ=Europe/Berlin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;DOMAIN_NAME=your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Traefik Settings ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;TRAEFIK_DASHBOARD_HOST=traefik.${DOMAIN_NAME}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;LETSENCRYPT_EMAIL=your-email@example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- CrowdSec Settings ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;CROWDSEC_COLLECTIONS=&amp;quot;crowdsecurity/traefik crowdsecurity/linux&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Credentials ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;CROWDSEC_BOUNCER_API_KEY=PASTE-YOUR-GENERATED-KEY-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            IMPORTANT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Replace &lt;code&gt;your-domain.com&lt;/code&gt;, &lt;code&gt;your-email@example.com&lt;/code&gt;. The API key will be generated and pasted in a later step.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-2-traefik-static-configuration-traefik-yml&quot;&gt;3.2. Traefik Static Configuration (&lt;code&gt;traefik.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file contains the core Traefik settings that rarely change.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee traefik.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;global:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  checkNewVersion: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  sendAnonymousUsage: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;api:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  dashboard: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;ping: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;entryPoints:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  web:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    address: &amp;quot;:80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    http:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      redirections:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        entryPoint:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          to: websecure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          scheme: https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    forwardedHeaders:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      insecure: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      trustedIPs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;127.0.0.1/32&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;10.0.0.0/8&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;172.16.0.0/12&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;192.168.0.0/16&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  websecure:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    address: &amp;quot;:443&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    forwardedHeaders:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      insecure: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      trustedIPs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;127.0.0.1/32&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;10.0.0.0/8&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;172.16.0.0/12&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        - &amp;quot;192.168.0.0/16&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;providers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  docker:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    endpoint: &amp;quot;unix:///var/run/docker.sock&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    exposedByDefault: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    network: proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    directory: /etc/traefik/dynamic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    watch: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;experimental:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  plugins:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    crowdsec-bouncer:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      version: v1.6.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;certificatesResolvers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  tls_resolver:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    acme:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      storage: /certs/acme.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      httpChallenge:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        entryPoint: web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;log:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  level: INFO&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  filePath: /var/log/traefik/traefik.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;accessLog:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  filePath: /var/log/traefik/access.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  format: json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  filters:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    statusCodes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;400-599&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  fields:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    headers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      defaultMode: keep&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-2-1-forwarded-headers-trusted-ips&quot;&gt;3.2.1. Forwarded Headers (Trusted IPs)&lt;/h3&gt;
&lt;p&gt;Traefik acts as a reverse proxy in front of your applications. To ensure your apps see the real client IP (and not the internal Docker gateway IP), Traefik must correctly process the &lt;code&gt;X-Forwarded-For&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Without this configuration&lt;/strong&gt;, any visitor can spoof the &lt;code&gt;X-Forwarded-For&lt;/code&gt; header, bypassing IP-based rate limiting, abuse protection, or geo-blocking.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What do these entries in &lt;code&gt;traefik.yml&lt;/code&gt; mean?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;insecure: false&lt;/code&gt; — Traefik does not automatically trust all incoming &lt;code&gt;X-Forwarded-For&lt;/code&gt; headers. This is the default, but we set it explicitly for clarity.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trustedIPs&lt;/code&gt; — Traefik only accepts the forwarded header from these source IPs. For all other requests, Traefik overwrites the header with the actual sender IP.&lt;/li&gt;
&lt;li&gt;The four ranges cover the loopback interface (127.0.0.1) and all private network ranges (used for internal Docker communication).&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            UPSTREAM PROXIES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If you run a load balancer or CDN in front of Traefik, you must add its IP ranges as well. Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hetzner Load Balancer:&lt;/strong&gt; The private IPs of the LB within the same network (e.g., &lt;code&gt;10.0.0.0/8&lt;/code&gt; already covers this if the LB is in the same private network). Alternatively, explicitly add the public LB IP.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare:&lt;/strong&gt; Add the official Cloudflare IP ranges. See &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.cloudflare.com/ips/&quot;&gt;https://www.cloudflare.com/ips/&lt;/a&gt;. Traefik also offers the shorthand &lt;code&gt;cloudflare&lt;/code&gt; as a provider for this (undocumented, better to set the ranges explicitly).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS ALB / NLB:&lt;/strong&gt; The VPC subnet ranges of the load balancer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without the correct IPs, your application will see the load balancer’s IP instead of the client’s IP.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            NEVER USE INSECURE: TRUE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The setting &lt;code&gt;insecure: true&lt;/code&gt; causes Traefik to accept the &lt;code&gt;X-Forwarded-For&lt;/code&gt; header from &lt;strong&gt;any&lt;/strong&gt; source — even directly from the internet. This opens the door for IP spoofing and should never be used in production.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            PLUGIN NAMING CONVENTION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The plugin is defined here under the name &lt;code&gt;crowdsec-bouncer&lt;/code&gt;. You will often see the official CrowdSec documentation refer to it simply as &lt;code&gt;bouncer&lt;/code&gt;. Both work perfectly, as long as you are consistent when referencing it in your Docker labels later on.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-3-traefik-dynamic-configuration-dynamic-middlewares-yml&quot;&gt;3.3. Traefik Dynamic Configuration (&lt;code&gt;dynamic/middlewares.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file defines reusable middleware components.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee traefik/dynamic/middlewares.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;http:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  middlewares:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # 1. General security headers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    security-headers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      headers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        browserXssFilter: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        contentTypeNosniff: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        frameDeny: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        forceSTSHeader: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        stsIncludeSubdomains: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        stsPreload: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        stsSeconds: 31536000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # 2. Basic Auth for the dashboard&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    traefik-dashboard-auth:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      basicAuth:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        usersFile: &amp;quot;/etc/traefik/dynamic/.htpasswd&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-4-docker-compose-docker-compose-yml&quot;&gt;3.4. Docker Compose (&lt;code&gt;docker-compose.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This is the main file defining our services.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  traefik:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: traefik:v3.7.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ports:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;80:80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;443:443&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - --certificatesresolvers.tls_resolver.acme.email=${LETSENCRYPT_EMAIL}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - /var/run/docker.sock:/var/run/docker.sock:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./traefik.yml:/etc/traefik/traefik.yml:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./traefik/dynamic:/etc/traefik/dynamic:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./traefik/certs:/certs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./traefik/logs:/var/log/traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - TZ=${TZ}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.crowdsec-bouncer.plugin.crowdsec-bouncer.enabled=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.crowdsec-bouncer.plugin.crowdsec-bouncer.crowdsecMode=stream&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.crowdsec-bouncer.plugin.crowdsec-bouncer.crowdsecLapiHost=crowdsec:8080&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.crowdsec-bouncer.plugin.crowdsec-bouncer.crowdsecLapiKey=${CROWDSEC_BOUNCER_API_KEY}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_DASHBOARD_HOST}`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.dashboard.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.dashboard.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.dashboard.service=api@internal&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.dashboard.middlewares=traefik-dashboard-auth@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;quot;CMD&amp;quot;, &amp;quot;traefik&amp;quot;, &amp;quot;healthcheck&amp;quot;, &amp;quot;--ping&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      interval: 30s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      timeout: 10s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      retries: 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  crowdsec:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: crowdsecurity/crowdsec:v1.7.8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: crowdsec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - /var/run/docker.sock:/var/run/docker.sock:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./crowdsec/config:/etc/crowdsec:z&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./crowdsec/data:/var/lib/crowdsec/data:z&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./traefik/logs:/var/log/traefik:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - /var/log:/var/log/host/:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - TZ=${TZ}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - COLLECTIONS=${CROWDSEC_COLLECTIONS}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;quot;CMD&amp;quot;, &amp;quot;cscli&amp;quot;, &amp;quot;version&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      interval: 60s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      timeout: 15s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      retries: 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    name: proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DOCKER SOCKET SECURITY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Mounting &lt;code&gt;/var/run/docker.sock&lt;/code&gt; directly gives the container root-equivalent access to the Docker daemon. For a production-hardened setup, consider using a Docker Socket Proxy (like &lt;code&gt;tecnativa/docker-socket-proxy&lt;/code&gt;) to restrict Traefik to read-only access for essential API endpoints.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            CROWDSEC SCOPE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The Traefik bouncer protects HTTP(S) traffic that actually passes through Traefik. It does not protect SSH, SMTP, IMAP, TURN, Matrix federation, or other ports exposed directly on the host. For those, use service-specific hardening, firewall rules, Fail2Ban, or the CrowdSec firewall bouncer.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-5-create-dashboard-password&quot;&gt;3.5. Create Dashboard Password&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; htpasswd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik/dynamic/.htpasswd admin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-6-crowdsec-acquisition-configuration-crowdsec-config-acquis-yaml&quot;&gt;3.6. CrowdSec Acquisition Configuration (&lt;code&gt;crowdsec/config/acquis.yaml&lt;/code&gt;)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee crowdsec/config/acquis.yaml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;filenames:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  - /var/log/traefik/access.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  type: traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;filenames:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  - /var/log/host/auth.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  - /var/log/host/syslog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  type: syslog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;4-launch-and-verify-the-stack&quot;&gt;4. Launch and Verify the Stack&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create the external network:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; network create proxy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start the services:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;Upon first launch, Traefik will request a certificate from Let’s Encrypt. This may take a minute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate the Bouncer API Key:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec crowdsec cscli bouncers add traefik&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; raw&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            LAPI STARTUP TIME
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Upon the very first start, CrowdSec might take a few moments to initialize the Local API (LAPI). If you get a connection error, wait 10-20 seconds and try the command again.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Copy the long, alphanumeric string that is output.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;Update your &lt;code&gt;.env&lt;/code&gt; file:&lt;/strong&gt; Paste the copied key as the value for &lt;code&gt;CROWDSEC_BOUNCER_API_KEY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restart Traefik to apply the key:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --force-recreate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify the bouncer connection:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose exec crowdsec cscli bouncers list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;You should see the &lt;code&gt;traefik&lt;/code&gt; bouncer listed. You can now access your dashboard at &lt;code&gt;https://traefik.your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;5-adding-services-to-traefik&quot;&gt;5. Adding Services to Traefik&lt;/h2&gt;
&lt;p&gt;Here is how to expose other Docker services through Traefik, with and without CrowdSec protection.&lt;/p&gt;
&lt;h3 id=&quot;5-1-scenario-1-service-protected-by-crowdsec-standard&quot;&gt;5.1. Scenario 1: Service Protected by CrowdSec (Standard)&lt;/h3&gt;
&lt;p&gt;This is the recommended setup for most public-facing services. We’ll use WordPress as an example. Create a &lt;code&gt;docker-compose.yml&lt;/code&gt; in a separate directory (e.g., &lt;code&gt;/opt/containers/wordpress&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  wordpress&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; wordpress:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.wordpress.rule=Host(`blog.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.wordpress.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.wordpress.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.wordpress.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.wordpress.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  db&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mariadb:11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    restart&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; change-me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      MYSQL_DATABASE&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; wordpress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      MYSQL_USER&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; wordpress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      MYSQL_PASSWORD&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; supersecret&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; db_data:/var/lib/mysql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;networks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  proxy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    external&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  default&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  db_data&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key label is &lt;code&gt;traefik.http.routers.wordpress.middlewares=security-headers@file,crowdsec-bouncer@docker&lt;/code&gt;, which applies our security headers (from the file provider) and the CrowdSec bouncer (defined on the Traefik service via Docker labels).&lt;/p&gt;
&lt;h3 id=&quot;5-2-scenario-2-service-bypassing-crowdsec-special-case&quot;&gt;5.2. Scenario 2: Service Bypassing CrowdSec (Special Case)&lt;/h3&gt;
&lt;p&gt;Sometimes you need to expose a service without CrowdSec’s interference. Common reasons include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A public API that must not be blocked.&lt;/li&gt;
&lt;li&gt;A site heavily reliant on ad network traffic, where false positives could impact revenue.&lt;/li&gt;
&lt;li&gt;Internal tools that are already secured by other means.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To bypass CrowdSec, simply omit the &lt;code&gt;crowdsec-bouncer@docker&lt;/code&gt; middleware.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# In the labels for your service (e.g., an API)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.my-api.rule=Host(`api.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.my-api.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.my-api.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # --- Middlewares (Security ONLY) ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.my-api.middlewares=security-headers@file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.my-api.loadbalancer.server.port=3000&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            MAXIMUM FLEXIBILITY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;By applying middleware on a per-router basis instead of globally on the entrypoint, you gain complete control over which services are protected by CrowdSec and which are not.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;5-3-routing-multiple-sub-domains-to-one-service&quot;&gt;5.3. Routing Multiple (Sub)Domains to One Service&lt;/h3&gt;
&lt;p&gt;Sometimes one container should respond to more than one hostname (e.g., &lt;code&gt;example.com&lt;/code&gt; and &lt;code&gt;www.example.com&lt;/code&gt;, or multiple subdomains pointing to the same app). You have a few common options.&lt;/p&gt;
&lt;h4 id=&quot;option-a-multiple-explicit-hosts-in-one-router&quot;&gt;Option A: Multiple Explicit Hosts in One Router&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.rule=Host(`example.com`) || Host(`www.example.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.app.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;option-b-wildcard-pattern-matching-many-subdomains&quot;&gt;Option B: Wildcard / Pattern Matching (Many Subdomains)&lt;/h4&gt;
&lt;p&gt;Use this if you want to match &lt;em&gt;many&lt;/em&gt; subdomains dynamically.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.rule=HostRegexp(`[a-z0-9-]+\.example\.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.app.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            WILDCARD CERTIFICATES &amp; LET&#39;S ENCRYPT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;While &lt;code&gt;HostRegexp&lt;/code&gt; routes the traffic dynamically, the &lt;code&gt;httpChallenge&lt;/code&gt; configured earlier cannot issue a wildcard certificate (e.g., &lt;code&gt;*.example.com&lt;/code&gt;). Let’s Encrypt requires a &lt;strong&gt;DNS challenge&lt;/strong&gt; for wildcards. With &lt;code&gt;httpChallenge&lt;/code&gt;, Traefik will attempt to request individual certificates for every matched subdomain, which can quickly exhaust Let’s Encrypt rate limits.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id=&quot;option-c-multiple-routers-one-service-different-middleware-per-host&quot;&gt;Option C: Multiple Routers, One Service (Different Middleware per Host)&lt;/h4&gt;
&lt;p&gt;This is useful if one hostname should bypass CrowdSec while another one stays protected.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-main.rule=Host(`app.example.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-main.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-main.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-main.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-api.rule=Host(`api.example.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-api.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-api.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-api.middlewares=security-headers@file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.services.app.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-main.service=app&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.app-api.service=app&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;6-maintenance&quot;&gt;6. Maintenance&lt;/h2&gt;
&lt;h3 id=&quot;6-1-updating-pinned-versions&quot;&gt;6.1. Updating Pinned Versions&lt;/h3&gt;
&lt;p&gt;This guide pins production image and plugin versions. To update, change the tags in &lt;code&gt;docker-compose.yml&lt;/code&gt; and &lt;code&gt;traefik.yml&lt;/code&gt;, read the relevant release notes, then pull and recreate:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --remove-orphans&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not rely on &lt;code&gt;latest&lt;/code&gt; for a reverse proxy that terminates TLS for all services.&lt;/p&gt;
&lt;h3 id=&quot;6-2-migrating-acme-json&quot;&gt;6.2. Migrating &lt;code&gt;acme.json&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;When moving this stack to a new server, decide deliberately whether to migrate the existing ACME store:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copying &lt;code&gt;traefik/certs/acme.json&lt;/code&gt; preserves existing certificates and avoids unnecessary Let’s Encrypt reissuance during cutover.&lt;/li&gt;
&lt;li&gt;Starting with an empty &lt;code&gt;acme.json&lt;/code&gt; is clean, but can hit rate limits if many domains are reissued repeatedly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you copy it, preserve permissions:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown root:root traefik/certs/acme.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik/certs/acme.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;6-3-log-rotation-critical-for-production&quot;&gt;6.3. Log Rotation (Critical for Production)&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DON&#39;T SKIP THIS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This setup generates detailed JSON access logs for CrowdSec analysis. Without proper log rotation, Traefik logs alone can consume &lt;strong&gt;70+ GB&lt;/strong&gt; within weeks on a busy server. Docker container logs can add another 40+ GB. Configure rotation &lt;strong&gt;before&lt;/strong&gt; going to production.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id=&quot;docker-global-log-rotation&quot;&gt;Docker Global Log Rotation&lt;/h4&gt;
&lt;p&gt;Configure Docker to automatically rotate all container logs by editing &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee /etc/docker/daemon.json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;log-driver&amp;quot;: &amp;quot;json-file&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;log-opts&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;max-size&amp;quot;: &amp;quot;10m&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;max-file&amp;quot;: &amp;quot;3&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apply the changes:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; systemctl restart docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; info&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -A3&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Logging Driver&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            EXISTING CONTAINERS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This setting only applies to newly created containers. Existing containers keep their old logging configuration. Recreate them with &lt;code&gt;docker compose up -d --force-recreate&lt;/code&gt; to apply the new limits.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id=&quot;traefik-host-log-rotation&quot;&gt;Traefik Host Log Rotation&lt;/h4&gt;
&lt;p&gt;Since Traefik writes logs directly to the host filesystem, use &lt;code&gt;logrotate&lt;/code&gt;.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            PATH VERIFICATION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Ensure the path in the config below matches your &lt;strong&gt;host path&lt;/strong&gt; where the logs are stored. You can find it by running:
&lt;code&gt;docker inspect traefik --format &#39;{{range .Mounts}}{{.Source}}{{&quot;\n&quot;}}{{end}}&#39; | grep logs&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee /etc/logrotate.d/traefik&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/opt/containers/traefik-stack/traefik/logs/*.log {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  daily&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  rotate 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  compress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  delaycompress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  missingok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  notifempty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  copytruncate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  maxsize 50M&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;verify-log-rotation&quot;&gt;Verify Log Rotation&lt;/h4&gt;
&lt;p&gt;To ensure your rotation is working correctly and to troubleshoot issues, use these commands:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Debug: show which rules would apply without actually rotating&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; logrotate&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/logrotate.d/traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Force rotation: execute immediately&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; logrotate&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/logrotate.d/traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check rotation status: see when logs were last rotated&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cat /var/lib/logrotate/status&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;7-troubleshooting-disk-full&quot;&gt;7. Troubleshooting: Disk Full&lt;/h2&gt;
&lt;p&gt;If your server runs out of disk space, logs are usually the culprit. Here’s how to diagnose and fix it.&lt;/p&gt;
&lt;h3 id=&quot;7-1-identify-the-problem&quot;&gt;7.1. Identify the Problem&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Quick overview&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;df&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Find large directories&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;du&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h -d1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;du&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h -d1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;du&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h -d1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Docker-specific&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;du&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h -d1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var/lib/docker&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;du&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h -d1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var/lib/docker/containers&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Find large container logs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /var/lib/docker/containers&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;*-json.log&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -exec&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; du&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; {}&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check journald (usually not the problem)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --disk-usage&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;7-2-emergency-cleanup&quot;&gt;7.2. Emergency Cleanup&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            CAUTION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;These commands delete log data permanently. Only proceed if you don’t need the logs for debugging.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Truncate Docker container logs:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; find /var/lib/docker/containers&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;*-json.log&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -exec&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; truncate&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s 0&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; {}&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Clear Traefik logs:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/traefik-stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose down&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -rf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik/logs/&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After cleanup, &lt;strong&gt;immediately configure log rotation&lt;/strong&gt; as described in section 6.1 to prevent recurrence.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now have a modern, secure, and flexible reverse proxy setup. Traefik handles routing and TLS termination effortlessly, while CrowdSec provides a powerful, community-driven security layer. By managing middlewares on a per-service basis, you can tailor the level of protection to fit the exact needs of each application you deploy.&lt;/p&gt;
&lt;p&gt;As a next step, you might want to explore the &lt;strong&gt;AppSec (WAF)&lt;/strong&gt; capabilities of the CrowdSec Bouncer plugin, which adds application-level protection against advanced attacks like SQL injection and Cross-Site Scripting directly at the Traefik layer.&lt;/p&gt;
&lt;p&gt;To add a central login with TOTP or WebAuthn to browser-based services, continue with &lt;strong&gt;&lt;a href=&quot;../authelia-traefik-sso-2fa/&quot;&gt;Authelia with Docker Compose and Traefik: Lightweight SSO and 2FA&lt;/a&gt;&lt;/strong&gt;. It reuses the &lt;code&gt;proxy&lt;/code&gt; network, TLS resolver, security headers, and CrowdSec middleware from this stack.&lt;/p&gt;
&lt;a href=&quot;https://doc.traefik.io/traefik/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;TRAEFIK DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://docs.crowdsec.net/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🛡️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;CROWDSEC DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;../authelia-traefik-sso-2fa/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔐&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ADD AUTHELIA SSO + 2FA&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Dark/Light-Mode Switcher for Arch Linux + i3wm</title>
          <pubDate>Tue, 09 Jun 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/</link>
          <guid>https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/">&lt;p&gt;Welcome to this detailed guide showing you how to set up an effective Dark/Light-Mode switcher for your Arch Linux system with i3wm. In a world where most applications have their own theming logic, we will build an orchestration solution that controls many components simultaneously to create a consistent experience.&lt;/p&gt;
&lt;p&gt;We will integrate GTK, Qt, terminal, and even CLI applications into our theme switcher, all controlled by a single keypress.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-06-10&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Design and Robustness Pass:&lt;/strong&gt; WCAG-checked contrast fixes for NeoMutt and ikhal: neutral selection/status/search pairs, mail-state rows with adaptive backgrounds via a &lt;code&gt;reverse&lt;/code&gt; trick, per-calendar ANSI accents and a clearer color hierarchy in ikhal — accent slots in a shared semantic palette are foreground-only. Unified the Dracula ANSI palette across OSC, Xresources, and Alacritty. i3 focus switched to a signal-red border with &lt;code&gt;default_border pixel 3&lt;/code&gt;, urgent moved to orange. Polybar restart hardened (&lt;code&gt;enable-ipc&lt;/code&gt; plus verified fallback), fixing intermittently vanishing bars after a toggle. Claude Code’s truecolor theme is switched per mode; nheko stays on &lt;code&gt;theme=system&lt;/code&gt; (its built-in light theme hardcodes a dark Element-style sidebar, &lt;code&gt;#233649&lt;/code&gt; — only &lt;code&gt;system&lt;/code&gt; derives it from the Qt palette) and is stopped/restarted automatically per toggle because it persists settings on exit and mixes on live palette switches — the fresh window reappears in place on its old workspace via i3 layout-restore swallow placeholders (&lt;code&gt;restart_app_in_place&lt;/code&gt;); tray applets are restarted toggle-proof, the light mode uses an icon-theme variant with dark panel icons (Papirus ships white panel icons by design), and the Nextcloud and KeePassXC tray icons switched to mode-independent colorful variants. NeoMutt’s cursor row moved to its own background pair (markers must never share one), and sonicradio settled on one constant theme whose built-in dark/light profiles are both high-contrast and survive its config write-back. Root-caused a class of “GUI relaunch crashes silently”: &lt;code&gt;darkman.service&lt;/code&gt; starts before the display manager exports &lt;code&gt;DISPLAY&lt;/code&gt;/&lt;code&gt;XAUTHORITY&lt;/code&gt; — the X-environment import in Step 9 is now documented as required, plus a fallback in the hooks.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-06-09&lt;/td&gt;&lt;td&gt;&lt;strong&gt;TUI Live-Reload Strategies:&lt;/strong&gt; NeoMutt and ikhal converted to semantic 16-color palettes with &lt;code&gt;SIGWINCH&lt;/code&gt; redraw, so running sessions repaint live when the hooks change the terminal palette via OSC; &lt;code&gt;jellyfin-tui&lt;/code&gt; keeps a stable &lt;code&gt;Mode Switcher&lt;/code&gt; theme rewritten in the live-watched &lt;code&gt;config.yaml&lt;/code&gt;, plus an after-exit preference rewrite and high-contrast palettes. Fixes from testing real sessions: NeoMutt DirectColor and regex pitfalls, Dunst live reload, Rofi theme switching, Xresources &lt;code&gt;-load&lt;/code&gt; instead of &lt;code&gt;-merge&lt;/code&gt;, targeted urxvt/Alacritty OSC recoloring, Polybar tray preservation, and stronger Light-mode contrast.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-06-04&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Technical Review:&lt;/strong&gt; Hardened portal, Alacritty, Qt, Polybar, Chromium, and hook-script guidance after implementation review.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-05-04&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Comprehensive guide for Dark/Light-Mode switching on Arch Linux and i3wm.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;architectural-overview&quot;&gt;Architectural Overview&lt;/h2&gt;
&lt;p&gt;i3wm itself does not provide global theme management. Styling is handled by various components such as GTK, Qt, Xresources, and individual applications. Our solution is based on an &lt;strong&gt;orchestrator architecture&lt;/strong&gt; that uses &lt;code&gt;darkman&lt;/code&gt; as the central control unit.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;darkman&lt;/code&gt; performs two main tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It executes your customized hook scripts, which adapt specific applications and environments.&lt;/li&gt;
&lt;li&gt;It propagates the dark mode status via the XDG-Desktop-Portal to modern applications (e.g., Firefox, Thunderbird). The portal signal is live; whether the visible app chrome also repaints live depends on the application.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$mod+Shift+d  →  darkman toggle  →  Hook Scripts  →  Individual Apps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                       │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                       └──► XDG-Portal (Firefox, Thunderbird, etc. via Signal)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;quickstart-copy-paste&quot;&gt;Quickstart (Copy &amp;amp; Paste)&lt;/h2&gt;
&lt;p&gt;If you want the shortest path to the core setup — GTK config + XDG portal + i3 + Alacritty controlled by &lt;code&gt;$mod+Shift+d&lt;/code&gt; — use this Quickstart as the bootstrap. It prepares the required packages, portal configuration, theme directories, terminal theme files, and i3 binding. The visible switching behavior still depends on the i3 theme files, the Alacritty import line, and the hook scripts from the later steps.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. Install prerequisites&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; darkman xdg-desktop-portal xdg-desktop-portal-gtk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;               jq ruby libnotify dunst alacritty xorg-xrdb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dracula-gtk-theme&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;   # or fall back to Adwaita-dark (handled by hook)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Create directory layout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/share/dark-mode.d&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;         ~/.local/share/light-mode.d&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;         ~/.config/themes/{dracula,solarized-light}&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;         ~/.config/alacritty&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;         ~/.config/xdg-desktop-portal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. Tell xdg-desktop-portal to use darkman as the Settings backend.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    REQUIRED since xdg-desktop-portal 1.17.0 — without this, Firefox &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    other portal-aware apps will not see darkman&amp;#39;s color-scheme.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    default=gtk keeps the GTK portal as fallback for file choosers and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    other portal interfaces that darkman does not implement.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/xdg-desktop-portal/portals.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[preferred]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;default=gtk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;org.freedesktop.impl.portal.Settings=darkman&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 4. Pull terminal theme files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://raw.githubusercontent.com/dracula/alacritty/master/dracula.toml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;     -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/alacritty.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://raw.githubusercontent.com/alacritty/alacritty-theme/master/themes/solarized_light.toml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;     -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/solarized-light/alacritty.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 5. Wire up i3 (idempotent — safe to run twice)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;bindsym &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\$&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;mod+Shift+d exec --no-startup-id darkman toggle&amp;quot; ~/.config/i3/config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;bindsym $mod+Shift+d exec --no-startup-id darkman toggle&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/i3/config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;include ~/.config/i3/theme.conf&amp;quot; ~/.config/i3/config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;include ~/.config/i3/theme.conf&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/i3/config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reload&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 6. Enable the service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; enable&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --now&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; darkman.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; restart xdg-desktop-portal.service&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 7. Quick smoke test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    Note: these only have a *visible* effect after you create the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    hook scripts in Steps 7 &amp;amp; 8. Until then darkman just flips an&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    internal flag — nothing recolors yet.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;darkman&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;      # current mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;darkman&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; toggle&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;   # switch without using the keybinding&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create the i3 theme stubs from &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-4-split-i3-config&quot;&gt;Step 4&lt;/a&gt;, import the generated Alacritty theme file as shown in &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-10-obtain-theme-files&quot;&gt;Step 10&lt;/a&gt;, and create the hook scripts from &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-7-the-dark-mode-hook-script&quot;&gt;Step 7&lt;/a&gt; and &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-8-the-light-mode-hook-script&quot;&gt;Step 8&lt;/a&gt;. After that, &lt;code&gt;$mod+Shift+d&lt;/code&gt; should give you a working basic switch.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Expected result after Quickstart + Step 4 + Step 7/8 + Alacritty import:&lt;/strong&gt; Pressing &lt;code&gt;$mod+Shift+d&lt;/code&gt; (or running &lt;code&gt;darkman toggle&lt;/code&gt;) should recolor i3 borders, switch the Alacritty theme without restarting the terminal, and update the XDG portal color-scheme for Firefox/Thunderbird. Firefox normally uses &lt;code&gt;widget.use-xdg-desktop-portal.settings = 2&lt;/code&gt; (“auto”); set it to &lt;code&gt;1&lt;/code&gt; only if auto-detection does not pick up the portal on your system. Full Firefox chrome repainting can still require an app restart. If any of the core checks fail, see the &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#reality-check-verify-persistence&quot;&gt;Reality Check&lt;/a&gt; section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;recommended-approach-set-up-step-by-step&quot;&gt;Recommended Approach: Set up Step-by-Step&lt;/h2&gt;
&lt;p&gt;To avoid frustration and facilitate troubleshooting, you should approach the setup in phases. This way, you’ll always know which component is responsible for problems.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Phase 1 — Basic:&lt;/strong&gt; &lt;code&gt;darkman&lt;/code&gt; + GTK config + XDG portal + i3 + Alacritty. These components are reliable and cover the majority of the switcher architecture.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 2 — Extension:&lt;/strong&gt; Polybar + VSCodium + neomutt. This requires a bit more configuration, but the functionality is stable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 3 — Problem Children:&lt;/strong&gt; Qt apps such as nheko, KeePassXC when not set to Automatic, Chromium, generic GTK apps such as Thunar, Firefox chrome repainting, and urxvt live-reload. These applications can present app-specific challenges and should be tested separately.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Follow this tutorial linearly and test the functionality after each phase before moving on to the next.&lt;/p&gt;
&lt;h2 id=&quot;theme-choice-dracula-solarized-light&quot;&gt;Theme Choice: Dracula ↔ Solarized Light&lt;/h2&gt;
&lt;p&gt;For dark mode, we will use &lt;strong&gt;Dracula&lt;/strong&gt;, a popular and well-supported theme. For the light mode counterpart, several options are available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solarized Light:&lt;/strong&gt; A classic with well-documented color palettes for many tools, known for its good readability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Catppuccin Latte:&lt;/strong&gt; A modern alternative that aesthetically complements Catppuccin Mocha (if you decide to replace Dracula later).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Light:&lt;/strong&gt; A pragmatic choice, as many editor themes and browser extensions are available for it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide will use the &lt;strong&gt;Dracula ↔ Solarized Light&lt;/strong&gt; pair.&lt;/p&gt;
&lt;h2 id=&quot;migrating-from-a-hand-themed-setup&quot;&gt;Migrating from a hand-themed setup&lt;/h2&gt;
&lt;p&gt;If you’ve already painstakingly themed each application by hand, read this section before running any of the hook scripts. The hooks are designed for a setup built &lt;em&gt;with&lt;/em&gt; darkman in mind — applied to an existing setup, they will overwrite or symlink-replace several files without asking.&lt;/p&gt;
&lt;h3 id=&quot;what-the-hooks-will-update-in-place&quot;&gt;What the hooks will update in place&lt;/h3&gt;
&lt;p&gt;These files are changed on every toggle, but the hook examples below update only the relevant keys and preserve unrelated local settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.config/gtk-3.0/settings.ini&lt;/code&gt; and &lt;code&gt;~/.config/gtk-4.0/settings.ini&lt;/code&gt; — &lt;code&gt;gtk-theme-name&lt;/code&gt;, &lt;code&gt;gtk-icon-theme-name&lt;/code&gt;, and &lt;code&gt;gtk-application-prefer-dark-theme&lt;/code&gt; are created or updated. Existing font, cursor, Xft, and other keys are preserved.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/qt5ct/qt5ct.conf&lt;/code&gt;, &lt;code&gt;~/.config/qt6ct/qt6ct.conf&lt;/code&gt; — &lt;code&gt;color_scheme_path&lt;/code&gt;, &lt;code&gt;custom_palette&lt;/code&gt;, and optionally &lt;code&gt;icon_theme&lt;/code&gt; are created or updated. The rest of the file is preserved.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/VSCodium/User/settings.json&lt;/code&gt; — only the &lt;code&gt;workbench.colorTheme&lt;/code&gt; key is updated via &lt;code&gt;jq&lt;/code&gt;. &lt;strong&gt;Caveat:&lt;/strong&gt; &lt;code&gt;jq&lt;/code&gt; requires strict JSON. If your settings file contains JSONC-style comments or trailing commas, the hook will skip the change rather than rewrite the file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/khal/config&lt;/code&gt; — &lt;code&gt;[view] theme&lt;/code&gt;, &lt;code&gt;[highlight_days]&lt;/code&gt;, and semantic ANSI &lt;code&gt;[palette]&lt;/code&gt; keys are updated. The section-aware helper is important here; a global string replacement can accidentally overwrite unrelated keys with the same name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/dunst/dunstrc&lt;/code&gt; — only theme color keys such as &lt;code&gt;frame_color&lt;/code&gt;, &lt;code&gt;format&lt;/code&gt;, &lt;code&gt;background&lt;/code&gt;, and &lt;code&gt;foreground&lt;/code&gt; are updated, then Dunst is reloaded with &lt;code&gt;dunstctl reload&lt;/code&gt;. Existing notification rules and sound scripts are preserved.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/jellyfin-tui/config.yaml&lt;/code&gt;, &lt;code&gt;~/.local/share/jellyfin-tui/preferences/*.json&lt;/code&gt;, and &lt;code&gt;~/.config/sonicRadio/config.json&lt;/code&gt; — only theme-related values are changed. &lt;code&gt;jellyfin-tui&lt;/code&gt; can repaint live when it is already using the stable &lt;code&gt;Mode Switcher&lt;/code&gt; theme; NeoMutt and ikhal can repaint live after they have loaded the semantic ANSI palette once. Other running TUI instances may still keep their current in-memory theme until restart or in-app theme selection.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-the-hooks-will-replace-via-symlink-non-destructive-but-pathing-changes&quot;&gt;What the hooks will replace via symlink (non-destructive but pathing changes)&lt;/h3&gt;
&lt;p&gt;These paths become symlinks pointing into &lt;code&gt;~/.config/themes/&amp;lt;theme&amp;gt;/&lt;/code&gt;. If a real file exists at the path, the symlink replaces it (the original file stays where it was, but is no longer reachable through the original path):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.Xresources&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/i3/theme.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/polybar/colors.ini&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/neomutt/colors&lt;/code&gt; or, in mutt-wizard style setups, &lt;code&gt;~/.config/mutt/theme.muttrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/nvim/colorscheme.vim&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;~/.config/alacritty/theme.toml&lt;/code&gt; is handled differently: the hooks rewrite it as a regular file. In practice this is more reliable for Alacritty live reload than switching the target of a symlink.&lt;/p&gt;
&lt;h3 id=&quot;what-is-changed-system-wide-via-gsettings&quot;&gt;What is changed system-wide via gsettings&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;org.gnome.desktop.interface gtk-theme&lt;/code&gt; and &lt;code&gt;color-scheme&lt;/code&gt; — affects every GTK app on your system that reads gsettings, regardless of whether you intended to theme it through darkman.&lt;/p&gt;
&lt;h3 id=&quot;what-is-not-touched&quot;&gt;What is NOT touched&lt;/h3&gt;
&lt;p&gt;Your main configuration files (&lt;code&gt;~/.config/i3/config&lt;/code&gt;, &lt;code&gt;~/.config/alacritty/alacritty.toml&lt;/code&gt;, your Polybar bar layout, your &lt;code&gt;.muttrc&lt;/code&gt;, your Neovim init, your shell rc files, Firefox profiles) are only &lt;em&gt;referenced&lt;/em&gt; via &lt;code&gt;include&lt;/code&gt;/&lt;code&gt;import&lt;/code&gt;/&lt;code&gt;source&lt;/code&gt; lines. They stay where they are. Chromium is intentionally treated as restart-only and is not changed by the default hooks.&lt;/p&gt;
&lt;p&gt;One important exception to watch for in existing setups: remove hardcoded theme environment variables such as &lt;code&gt;export GTK_THEME=Adwaita:dark&lt;/code&gt; from &lt;code&gt;.profile&lt;/code&gt;, &lt;code&gt;.xprofile&lt;/code&gt;, &lt;code&gt;.zprofile&lt;/code&gt;, or display-manager startup scripts. They can override the hook result for newly started GTK applications and make Light mode appear broken.&lt;/p&gt;
&lt;h3 id=&quot;recommended-snapshot-before-the-first-toggle&quot;&gt;Recommended: snapshot before the first toggle&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/theme-switcher-backup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; path&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ~/.config/gtk-3.0&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ~/.config/gtk-4.0&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ~/.config/qt5ct&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ~/.config/qt6ct&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ~/.Xresources&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ~/.config/VSCodium/User/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$path&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$path&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; ~/theme-switcher-backup/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the first toggle, diff what changed:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;diff&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/theme-switcher-backup/gtk-3.0 ~/.config/gtk-3.0&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you find that a setting still needs to switch with the theme, &lt;strong&gt;teach the hooks about that key explicitly&lt;/strong&gt; — open the hook scripts in &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-7-the-dark-mode-hook-script&quot;&gt;Step 7&lt;/a&gt; and &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-8-the-light-mode-hook-script&quot;&gt;Step 8&lt;/a&gt; and add another &lt;code&gt;set_ini_key&lt;/code&gt; call for GTK/Qt-style INI files or another focused &lt;code&gt;jq&lt;/code&gt; update for JSON files. Extend the hook deliberately instead of replacing whole application configs.&lt;/p&gt;
&lt;h2 id=&quot;step-1-install-prerequisites&quot;&gt;Step 1: Install Prerequisites&lt;/h2&gt;
&lt;h3 id=&quot;darkman-and-portal-infrastructure&quot;&gt;&lt;code&gt;darkman&lt;/code&gt; and Portal Infrastructure&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; darkman xdg-desktop-portal xdg-desktop-portal-gtk jq ruby libnotify dunst&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; xorg-xrdb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; enable&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --now&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; darkman.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;jq&lt;/code&gt; is needed for patching JSON settings; &lt;code&gt;ruby&lt;/code&gt; is used for YAML-aware &lt;code&gt;jellyfin-tui&lt;/code&gt; theme updates.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libnotify&lt;/code&gt; enables notifications via &lt;code&gt;notify-send&lt;/code&gt;; &lt;code&gt;dunst&lt;/code&gt; is the notification daemon reloaded by the hooks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xorg-xrdb&lt;/code&gt; provides &lt;code&gt;xrdb&lt;/code&gt; for applying Xresources.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;configure-xdg-desktop-portal-to-use-darkman-required&quot;&gt;Configure xdg-desktop-portal to use darkman (REQUIRED)&lt;/h3&gt;
&lt;p&gt;This is the single most overlooked step in dark-mode setups. Since &lt;code&gt;xdg-desktop-portal 1.17.0&lt;/code&gt;, the portal must be told &lt;em&gt;which&lt;/em&gt; backend implements the Settings interface — otherwise Firefox, Thunderbird, and other portal-aware apps will never see darkman’s color-scheme value, no matter how correctly darkman itself is configured.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;~/.config/xdg-desktop-portal/portals.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/xdg-desktop-portal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/xdg-desktop-portal/portals.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[preferred]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;default=gtk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;org.freedesktop.impl.portal.Settings=darkman&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;default=gtk&lt;/code&gt; line matters: &lt;code&gt;darkman&lt;/code&gt; only implements the Settings portal. Without a default backend, a user-level &lt;code&gt;portals.conf&lt;/code&gt; can accidentally disable other portal interfaces such as file choosers.&lt;/p&gt;
&lt;p&gt;You can verify the portal really hands darkman’s value to clients with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gdbus&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; call&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --session \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --dest&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; org.freedesktop.portal.Desktop&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --object-path&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /org/freedesktop/portal/desktop&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --method&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; org.freedesktop.portal.Settings.ReadOne&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  org.freedesktop.appearance color-scheme&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should return a GVariant containing &lt;code&gt;1&lt;/code&gt; (dark) or &lt;code&gt;2&lt;/code&gt; (light), for example &lt;code&gt;(&amp;lt;uint32 1&amp;gt;,)&lt;/code&gt;. If it returns &lt;code&gt;0&lt;/code&gt; (“no preference”) or fails, restart &lt;code&gt;xdg-desktop-portal.service&lt;/code&gt; and verify that your user-level &lt;code&gt;portals.conf&lt;/code&gt; is being read.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; restart xdg-desktop-portal.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Firefox-side counterpart:&lt;/strong&gt; Current Firefox builds use &lt;code&gt;widget.use-xdg-desktop-portal.settings = 2&lt;/code&gt; as “auto”. That usually works for the Settings portal. If Firefox does not pick up the portal even though the &lt;code&gt;gdbus&lt;/code&gt; check is correct, set this preference to &lt;code&gt;1&lt;/code&gt; to force portal usage. This can still require restarting Firefox and does not guarantee that every browser chrome element repaints live.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For dotfile-managed systems, the forced setting can be made persistent in the active Firefox profile:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;// ~/.mozilla/firefox/&amp;lt;profile&amp;gt;/user.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;user_pref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;widget.use-xdg-desktop-portal.settings&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;gtk-theme&quot;&gt;GTK Theme&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Dracula&lt;/code&gt; is not in the official Arch repository. You will need an AUR helper like &lt;code&gt;yay&lt;/code&gt; or &lt;code&gt;paru&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dracula-gtk-theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# or: paru -S dracula-gtk-theme&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you prefer not to use an AUR helper, the setup will automatically fall back to &lt;code&gt;Adwaita-dark&lt;/code&gt; and &lt;code&gt;Adwaita&lt;/code&gt; respectively (see hook script).&lt;/p&gt;
&lt;h3 id=&quot;qt-control-for-phase-3&quot;&gt;Qt Control (for Phase 3)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; qt5ct qt6ct kvantum&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;i3-keybinding&quot;&gt;i3 Keybinding&lt;/h3&gt;
&lt;p&gt;Add the following keybinding to your i3 configuration file &lt;code&gt;~/.config/i3/config&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bindsym $mod+Shift+d exec --no-startup-id darkman toggle&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;step-2-create-directory-structure&quot;&gt;Step 2: Create Directory Structure&lt;/h2&gt;
&lt;p&gt;A clean directory structure is crucial for maintainability:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/share/dark-mode.d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/share/light-mode.d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/{dracula,solarized-light}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/qt5ct/colors ~/.config/qt6ct/colors&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;~/.config/themes/&lt;/code&gt; directory, theme-specific files for each application will be stored. The hook scripts will then create symlinks to most currently desired theme files. Alacritty is the exception: its imported theme file is rewritten as a regular file to make live reload more reliable.&lt;/p&gt;
&lt;h2 id=&quot;step-3-prepare-qt-apps-keepassxc-nheko&quot;&gt;Step 3: Prepare Qt Apps (KeePassXC, nheko)&lt;/h2&gt;
&lt;p&gt;Qt applications do not automatically follow GTK configuration or the XDG-Portal. You usually need to set the &lt;code&gt;QT_QPA_PLATFORMTHEME&lt;/code&gt; environment variable before Qt applications are started.&lt;/p&gt;
&lt;p&gt;Where to put the variable depends on how you start X:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Display managers such as LightDM, LXDM, SDDM, and GDM usually source &lt;code&gt;~/.xprofile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;startx&lt;/code&gt;/&lt;code&gt;xinit&lt;/code&gt; setups only get &lt;code&gt;~/.xprofile&lt;/code&gt; if your &lt;code&gt;~/.xinitrc&lt;/code&gt; sources it before &lt;code&gt;exec i3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/environment.d/&lt;/code&gt; is read by &lt;code&gt;systemd --user&lt;/code&gt;, but it does not automatically update the environment of an already-started X session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For an i3 + X11 setup, use one global baseline first:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ~/.xprofile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;/span&gt;&lt;span&gt; QT_QPA_PLATFORMTHEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;qt5ct:qt6ct&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you use &lt;code&gt;startx&lt;/code&gt;, make sure &lt;code&gt;~/.xinitrc&lt;/code&gt; contains this before &lt;code&gt;exec i3&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.xprofile ] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.xprofile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Qt6 caveat:&lt;/strong&gt; If Qt6 apps ignore theming (e.g., KeePassXC remains unstyled), test the app with &lt;code&gt;qt6ct&lt;/code&gt; explicitly:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;QT_QPA_PLATFORMTHEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;qt6ct&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; keepassxc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On current Arch Qt packages, the combined &lt;code&gt;qt5ct:qt6ct&lt;/code&gt; value lets Qt5 and Qt6 applications pick their matching platform theme plugin. If an individual app still ignores it, use a per-app wrapper or desktop file for that application.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For KeePassXC specifically, set &lt;strong&gt;View → Theme → Automatic&lt;/strong&gt; once inside the application. On a portal-aware setup this allows KeePassXC to follow the dark/light switch live; a hardcoded &lt;code&gt;ApplicationTheme=dark&lt;/code&gt; in &lt;code&gt;~/.config/keepassxc/keepassxc.ini&lt;/code&gt; will override the system value and make Light mode look broken.&lt;/p&gt;
&lt;p&gt;The tray icon is a separate setting with the same trap: the &lt;em&gt;monochrome&lt;/em&gt; variants (&lt;code&gt;TrayIconAppearance=monochrome-dark&lt;/code&gt;/&lt;code&gt;monochrome-light&lt;/code&gt;) are fixed to one color and disappear on one of the two bar backgrounds. The hooks set &lt;code&gt;TrayIconAppearance=colorful&lt;/code&gt;, which is readable in both modes — it takes effect on the next KeePassXC start (the hooks never restart KeePassXC automatically, since that would lock your database).&lt;/p&gt;
&lt;h3 id=&quot;last-resort-fallback-per-app-wrapper&quot;&gt;Last-resort fallback: per-app wrapper&lt;/h3&gt;
&lt;p&gt;If neither global setup gets a stubborn Qt6 app to pick up the theme, set the variable just for that one app:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;QT_QPA_PLATFORMTHEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;qt6ct&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; keepassxc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can wrap this in a small shell script and place it in &lt;code&gt;~/.local/bin/&lt;/code&gt;, or make a desktop file with the env-var prepended in &lt;code&gt;Exec=&lt;/code&gt;. Inelegant, but reliable when the global escalation chain fails.&lt;/p&gt;
&lt;h3 id=&quot;obtain-qt-color-schemes&quot;&gt;Obtain Qt Color Schemes&lt;/h3&gt;
&lt;p&gt;Qt color schemes are stored as &lt;code&gt;.conf&lt;/code&gt; files under &lt;strong&gt;&lt;code&gt;~/.config/qt5ct/colors/&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;~/.config/qt6ct/colors/&lt;/code&gt;&lt;/strong&gt;. Do not store them under &lt;code&gt;/usr/share/qt5ct/colors/&lt;/code&gt;, as these directories are reserved for system defaults and can be overwritten by Pacman updates.&lt;/p&gt;
&lt;p&gt;For Dracula, an official Qt5ct color scheme exists in the Dracula project:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://raw.githubusercontent.com/dracula/qt5/master/Dracula.conf&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;     -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/qt5ct/colors/Dracula.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/qt5ct/colors/Dracula.conf ~/.config/qt6ct/colors/Dracula.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Solarized Light, &lt;strong&gt;no official Qt5ct color scheme exists&lt;/strong&gt;. The most reliable approach is to create one once via the GUI:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;qt5ct&lt;/code&gt; from a terminal.&lt;/li&gt;
&lt;li&gt;Tab “Style” → next to “Color scheme” click “Edit color scheme” → “Create”.&lt;/li&gt;
&lt;li&gt;Set Window Background &lt;code&gt;#fdf6e3&lt;/code&gt;, Window Text &lt;code&gt;#586e75&lt;/code&gt;, Base &lt;code&gt;#fdf6e3&lt;/code&gt;, Highlight &lt;code&gt;#268bd2&lt;/code&gt;, etc. – the eight Solarized base values are documented at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://ethanschoonover.com/solarized&quot;&gt;ethanschoonover.com/solarized&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Save as &lt;code&gt;SolarizedLight.conf&lt;/code&gt; under &lt;code&gt;~/.config/qt5ct/colors/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy the file to &lt;code&gt;~/.config/qt6ct/colors/SolarizedLight.conf&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why not use a third-party Solarized Qt scheme?&lt;/strong&gt; Various community ports exist, but their quality and maintenance vary, and the &lt;code&gt;qt5ct&lt;/code&gt; &lt;code&gt;.conf&lt;/code&gt; format is fairly strict. A one-time GUI creation gives you a result that exactly matches your other Solarized apps, without surprises.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;step-4-split-i3-config&quot;&gt;Step 4: Split i3 Config&lt;/h2&gt;
&lt;p&gt;The i3 configuration cannot be recolored at runtime. You must switch it and reload.&lt;/p&gt;
&lt;h3 id=&quot;option-a-include-file-recommended-from-i3-4-20&quot;&gt;Option A: include file (recommended, from i3 4.20)&lt;/h3&gt;
&lt;p&gt;Add the following line to &lt;code&gt;~/.config/i3/config&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;include ~/.config/i3/theme.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create two theme-specific configuration files. Minimal working examples:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Dracula i3 theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/i3-theme.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# class                 border  bground text    indicator child_border&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.focused          #ff5555 #44475a #f8f8f2 #f1fa8c   #ff5555&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.focused_inactive #44475a #44475a #f8f8f2 #44475a   #44475a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.unfocused        #282a36 #282a36 #bfbfbf #282a36   #282a36&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.urgent           #ffb86c #ffb86c #282a36 #ffb86c   #ffb86c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.placeholder      #282a36 #282a36 #f8f8f2 #282a36   #282a36&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.background       #282a36&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Solarized Light i3 theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/solarized-light/i3-theme.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# class                 border  bground text    indicator child_border&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.focused          #dc322f #eee8d5 #073642 #875f00   #dc322f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.focused_inactive #93a1a1 #eee8d5 #586e75 #93a1a1   #93a1a1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.unfocused        #fdf6e3 #fdf6e3 #93a1a1 #fdf6e3   #fdf6e3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.urgent           #cb4b16 #cb4b16 #fdf6e3 #cb4b16   #cb4b16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.placeholder      #fdf6e3 #fdf6e3 #586e75 #fdf6e3   #fdf6e3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;client.background       #fdf6e3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The hook script will then symlink the correct file to &lt;code&gt;~/.config/i3/theme.conf&lt;/code&gt; and execute &lt;code&gt;i3-msg reload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The focused border is deliberately a strong signal red (&lt;code&gt;#ff5555&lt;/code&gt; / &lt;code&gt;#dc322f&lt;/code&gt;): with muted slate or blue tones it is genuinely hard to tell which window has focus, in both modes. Urgent windows move to orange so the two states stay distinguishable. Pair this with a visible border width in your main config — with &lt;code&gt;default_border pixel 1&lt;/code&gt; even a red border is easy to miss:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;default_border pixel 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;option-b-symlink-the-entire-config&quot;&gt;Option B: Symlink the entire config&lt;/h3&gt;
&lt;p&gt;If you prefer not to use the &lt;code&gt;include&lt;/code&gt; directive, you can symlink the entire i3 configuration file. This is less flexible but also works.&lt;/p&gt;
&lt;h2 id=&quot;step-5-integrate-polybar&quot;&gt;Step 5: Integrate Polybar&lt;/h2&gt;
&lt;p&gt;Polybar loads its configuration at startup. There are two ways to restart Polybar:&lt;/p&gt;
&lt;h3 id=&quot;option-1-polybar-msg-cmd-restart-clean-from-polybar-3-6&quot;&gt;Option 1: &lt;code&gt;polybar-msg cmd restart&lt;/code&gt; (clean, from Polybar 3.6)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;polybar-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cmd restart&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This requires &lt;code&gt;enable-ipc = true&lt;/code&gt; in &lt;strong&gt;every&lt;/strong&gt; &lt;code&gt;[bar/...]&lt;/code&gt; section. Without it, &lt;code&gt;polybar-msg&lt;/code&gt; fails and the hooks silently fall back to the kill-and-relaunch path on every toggle — which is exactly the path with intermittent failure modes (see below).&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[bar/mybar]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;enable-ipc&lt;/span&gt;&lt;span&gt; = true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;option-2-pkill-launch-script-universal&quot;&gt;Option 2: &lt;code&gt;pkill&lt;/code&gt; + Launch Script (universal)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pkill&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;~&lt;/span&gt;&lt;span&gt;/.config/polybar/launch.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;minimal-theme-files&quot;&gt;Minimal theme files&lt;/h3&gt;
&lt;p&gt;You’ll already have a working Polybar configuration from your existing setup. Depending on the age of the setup, it may be &lt;code&gt;~/.config/polybar/config&lt;/code&gt;, &lt;code&gt;~/.config/polybar/config.ini&lt;/code&gt;, or started with an explicit &lt;code&gt;-c&lt;/code&gt; path. The safest approach is to keep that bar layout intact, extract only the colors into theme-specific files, and include the active palette.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Dracula Polybar palette&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/polybar.ini&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[colors]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;background = #282a36&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;background-alt = #44475a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;foreground = #f8f8f2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;foreground-alt = #6272a4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;primary = #bd93f9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;secondary = #8be9fd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;alert = #ff5555&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;disabled = #6272a4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Solarized Light Polybar palette&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/solarized-light/polybar.ini&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[colors]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;background = #fdf6e3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;background-alt = #eee8d5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;foreground = #586e75&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;foreground-alt = #93a1a1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;primary = #268bd2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;secondary = #2aa198&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;alert = #dc322f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;disabled = #93a1a1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your main Polybar config, reference the colors via:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;include-file&lt;/span&gt;&lt;span&gt; = ~/.config/polybar/colors.ini&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then remove or replace your old &lt;code&gt;[colors]&lt;/code&gt; section, so the included file becomes the single source of color values. The hook script below will symlink &lt;code&gt;~/.config/polybar/colors.ini&lt;/code&gt; to one of the two palette files. If your setup deliberately keeps colors and bar layout in one file, you can instead maintain two full Polybar config files — but then adjust the hook paths accordingly. Do not blindly symlink &lt;code&gt;config.ini&lt;/code&gt; on systems where Polybar actually reads &lt;code&gt;~/.config/polybar/config&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also review your &lt;code&gt;launch.sh&lt;/code&gt;: it should only start bars that are actually defined and whose monitors are connected. If you use the legacy Polybar systray, keep &lt;code&gt;tray-position = right&lt;/code&gt; on exactly one active bar and leave secondary bars at &lt;code&gt;tray-position = none&lt;/code&gt;. Do not accidentally replace an existing tray-enabled bar with &lt;code&gt;none&lt;/code&gt;, or the small app/status icons will disappear after the next Polybar restart. When a hook starts Polybar from a service context, a detached launch such as &lt;code&gt;setsid -f polybar mybar1 ...&lt;/code&gt; is more reliable than relying on interactive-shell &lt;code&gt;disown&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One more tray pitfall: the &lt;strong&gt;icons&lt;/strong&gt; inside the tray are drawn by the applets themselves (XEmbed), not by Polybar, and GTK applets load their icon theme once at startup. After a mode switch they keep the previous light/dark icon set — white icons from a dark icon theme become nearly invisible on a light bar. Plain i3 setups usually run no XSettings daemon that could propagate the change, so the hooks below simply restart the relevant applets (&lt;code&gt;nm-applet&lt;/code&gt;, &lt;code&gt;pasystray&lt;/code&gt;, &lt;code&gt;flameshot&lt;/code&gt;); adjust the list to whatever actually sits in your tray.&lt;/p&gt;
&lt;p&gt;Restarting alone is not enough if the icon theme itself has no light-bar variant. Panel/tray icons inside an icon theme have &lt;strong&gt;fixed colors&lt;/strong&gt;: Papirus, for example, ships near-white (&lt;code&gt;#dfdfdf&lt;/code&gt;) panel icons &lt;em&gt;by design&lt;/em&gt; in both &lt;code&gt;Papirus&lt;/code&gt; and &lt;code&gt;Papirus-Dark&lt;/code&gt; — readable only on dark bars. For a light bar you must switch to the &lt;code&gt;Papirus-Light&lt;/code&gt; variant (dark &lt;code&gt;#444444&lt;/code&gt; panel icons), so the hook’s icon-theme variable has to differ per mode (for example &lt;code&gt;Papirus-Dark&lt;/code&gt; in the dark hook, &lt;code&gt;Papirus-Light&lt;/code&gt; in the light hook). And apps with &lt;strong&gt;bundled monochrome tray icons&lt;/strong&gt; ignore the icon theme entirely: the Nextcloud client’s mono icon assumes a dark bar, so the hooks set &lt;code&gt;monoIcons=false&lt;/code&gt; in &lt;code&gt;nextcloud.cfg&lt;/code&gt; — the colorful brand icon is readable in both modes and needs no per-mode restart.&lt;/p&gt;
&lt;h2 id=&quot;step-6-chromium-flags&quot;&gt;Step 6: Chromium Flags&lt;/h2&gt;
&lt;p&gt;Chromium does not react to theme changes at runtime. It’s important to &lt;strong&gt;clearly separate&lt;/strong&gt; two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI-Dark-Mode:&lt;/strong&gt; Affects the browser interface (toolbar, tabs, menus).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Webpage-Force-Dark:&lt;/strong&gt; Forces a dark mode for every webpage. However, this can distort images, diagrams, and carefully designed pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;optional-fixed-dark-ui-on-next-start&quot;&gt;Optional: fixed dark UI on next start&lt;/h3&gt;
&lt;p&gt;Chromium’s launcher reads &lt;code&gt;~/.config/chromium-flags.conf&lt;/code&gt;, but these flags apply only when Chromium starts. A permanently configured &lt;code&gt;--force-dark-mode&lt;/code&gt; is therefore not a true light/dark toggle: it keeps Chromium dark even after the rest of the desktop switches back to light mode.&lt;/p&gt;
&lt;p&gt;If you want a fixed dark Chromium UI, create the file &lt;code&gt;~/.config/chromium-flags.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--force-dark-mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--gtk-version=4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--gtk-version=4&lt;/code&gt; asks Chromium to use its GTK4 integration path on builds that support it. Test it on your version; Chromium command-line flags change over time.&lt;/p&gt;
&lt;h3 id=&quot;optional-additionally-force-dark-content-for-webpages&quot;&gt;Optional: Additionally force dark content for webpages&lt;/h3&gt;
&lt;p&gt;If you want to force dark mode for webpage content as well, add:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--enable-features=WebContentsForceDark&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; This flag name has changed multiple times across Chromium versions (&lt;code&gt;WebContentsForceDark&lt;/code&gt;, &lt;code&gt;ForceWebContentsDarkMode&lt;/code&gt;, or only via &lt;code&gt;chrome://flags&lt;/code&gt;). If it doesn’t work, check &lt;code&gt;chrome://flags&lt;/code&gt; for “Force Dark Mode for Web Contents” and enable it there. The recommendation remains: only enable if you’re comfortable with potential content distortion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A true live toggle is not practical here without a browser restart. For that reason, the hook scripts below leave Chromium alone by default.&lt;/p&gt;
&lt;h2 id=&quot;step-7-the-dark-mode-hook-script&quot;&gt;Step 7: The Dark-Mode Hook Script&lt;/h2&gt;
&lt;p&gt;This script will be executed when &lt;code&gt;darkman&lt;/code&gt; switches to dark mode.
Create the file &lt;code&gt;~/.local/share/dark-mode.d/apply-theme&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on hook directory layout:&lt;/strong&gt; This guide uses &lt;code&gt;~/.local/share/dark-mode.d/&lt;/code&gt; and &lt;code&gt;~/.local/share/light-mode.d/&lt;/code&gt;, which the &lt;code&gt;darkman(1)&lt;/code&gt; manpage describes as the &lt;em&gt;legacy&lt;/em&gt; format (kept for backwards compatibility). The current format is a single &lt;code&gt;~/.local/share/darkman/&lt;/code&gt; directory with one script that receives the mode as &lt;code&gt;$1&lt;/code&gt;. Both formats work; the split-directory layout is used here because it makes the dark and light scripts easy to read side-by-side. If you want the modern single-script style, consolidate the two scripts and branch on &lt;code&gt;case &quot;$1&quot; in dark|light) ... esac&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Robustness: undefined vars are errors, but individual app errors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# should not abort the entire hook.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;trap&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;echo &amp;quot;Hook error in: $BASH_COMMAND&amp;quot; &amp;gt;&amp;amp;2&amp;#39; ERR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# darkman.service can start before the display manager has imported the X&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# environment into the systemd user scope; without DISPLAY/XAUTHORITY every&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# GUI applet relaunched by this hook crashes on startup and xrdb fails.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# (See Step 9 for the permanent session-side fix.)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;DISPLAY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || export&lt;/span&gt;&lt;span&gt; DISPLAY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;:0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;XAUTHORITY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; xauth_candidate&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;XDG_RUNTIME_DIR&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-/&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;id -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)}/lyxauth&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.Xauthority&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$xauth_candidate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; export&lt;/span&gt;&lt;span&gt; XAUTHORITY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$xauth_candidate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Session variables from ~/.xprofile are not visible inside the service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# either; without the platform theme, relaunched Qt apps (nheko) skip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# qt5ct/qt6ct entirely and fall back to unthemed Qt defaults.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;/span&gt;&lt;span&gt; QT_QPA_PLATFORMTHEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;QT_QPA_PLATFORMTHEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;qt5ct&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;/span&gt;&lt;span&gt;qt6ct&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/themes/dracula&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GTK_THEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Dracula&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Official Dracula ANSI values — keep these identical to the Xresources and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Alacritty theme files, or live-recolored and freshly started terminals will&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# show two different palettes side by side.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DRACULA_ANSI_OSC&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;$&amp;#39;\033]4;0;#21222c\007\033]4;1;#ff5555\007\033]4;2;#50fa7b\007\033]4;3;#f1fa8c\007\033]4;4;#bd93f9\007\033]4;5;#ff79c6\007\033]4;6;#8be9fd\007\033]4;7;#f8f8f2\007\033]4;8;#6272a4\007\033]4;9;#ff6e6e\007\033]4;10;#69ff94\007\033]4;11;#ffffa5\007\033]4;12;#d6acff\007\033]4;13;#ff92df\007\033]4;14;#a4ffff\007\033]4;15;#ffffff\007&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; config_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$2&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$3&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$4&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;[%s]\n&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    awk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; section=&amp;quot;&lt;/span&gt;&lt;span&gt;$section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; key=&amp;quot;&lt;/span&gt;&lt;span&gt;$key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; value=&amp;quot;&lt;/span&gt;&lt;span&gt;$value&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        BEGIN { in_section=0; section_found=0; key_done=0 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        $0 == &amp;quot;[&amp;quot; section &amp;quot;]&amp;quot; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            in_section=1; section_found=1; print; next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        /^[[:space:]]*\[/ {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if (in_section &amp;amp;&amp;amp; !key_done) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                key_done=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            in_section=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        in_section &amp;amp;&amp;amp; $0 ~ &amp;quot;^[[:space:]]*&amp;quot; key &amp;quot;[[:space:]]*=&amp;quot; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if (!key_done) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                key_done=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        { print }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        END {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if (!section_found) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print &amp;quot;[&amp;quot; section &amp;quot;]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            } else if (in_section &amp;amp;&amp;amp; !key_done) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;write_alacritty_theme&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty/theme.toml.XXXXXX&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0644&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/alacritty.toml&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    mv&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty/theme.toml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    touch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty/alacritty.toml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_dunst_theme&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/dunst/dunstrc&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; global frame_color &amp;#39;&amp;quot;#bd93f9&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; global separator_color &amp;#39;&amp;quot;#44475a&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; global format &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;span foreground=&amp;#39;#f8f8f2&amp;#39;&amp;gt;&amp;lt;b&amp;gt;%s %p&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\\\\&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;n%b&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;/^%b&amp;quot;$/d&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_low background &amp;#39;&amp;quot;#282a36&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_low foreground &amp;#39;&amp;quot;#f8f8f2&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_normal background &amp;#39;&amp;quot;#282a36&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_normal foreground &amp;#39;&amp;quot;#f8f8f2&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_critical background &amp;#39;&amp;quot;#ff5555&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_critical foreground &amp;#39;&amp;quot;#f8f8f2&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_critical frame_color &amp;#39;&amp;quot;#ff5555&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dunstctl&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; dunstctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reload &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;recolor_child_ttys&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; terminal_comm&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; bg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$2&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; fg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$3&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; cursor&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$4&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; palette&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;${5&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; tty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tty&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp; -w&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/dev/&lt;/span&gt;&lt;span&gt;$tty&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;\033]708;%s\007\033]11;%s\007\033]10;%s\007\033]12;%s\007&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span&gt;$bg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$bg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$fg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$cursor&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$palette&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;%s&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$palette&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/dev/&lt;/span&gt;&lt;span&gt;$tty&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        ps&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -eo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pid=,ppid=,tty=,comm=&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; terminal_comm=&amp;quot;&lt;/span&gt;&lt;span&gt;$terminal_comm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                pid[NR]=$1; ppid[NR]=$2; tty[NR]=$3; comm[NR]=$4;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                parent[$1]=$2;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                if ($4 == terminal_comm) terminal[$1]=1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            END {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                for (i=1; i&amp;lt;=NR; i++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    p=ppid[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    while (p &amp;amp;&amp;amp; p != &amp;quot;1&amp;quot;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                        if (p in terminal) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                            if (tty[i] ~ /^pts\//) print tty[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                            break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                        p=parent[p];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;redraw_tui_apps&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pgrep&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; kill -WINCH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; neomutt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; kill -WINCH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;(^|[[:space:]])(/usr/bin/)?ikhal([[:space:]]|$)|(^|[[:space:]])khal[[:space:]]+interactive([[:space:]]|$)&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Restart a GUI app so its new window reappears exactly where the old one&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# lived, on any workspace. Uses i3&amp;#39;s native layout-restore mechanism: a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# placeholder container with swallow criteria is appended to the app&amp;#39;s old&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# workspace, and i3 materializes the next matching window directly inside&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# it — no focus-dependent placement, no post-hoc moving. Apps that were&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# not running are left closed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_app_in_place&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; proc&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$2&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; ws focused layout mark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    mark&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;restore_${&lt;/span&gt;&lt;span&gt;proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ws&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ws&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;i3-msg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; get_tree&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; c &amp;quot;&lt;/span&gt;&lt;span&gt;$class&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            recurse(.nodes[]?, .floating_nodes[]?)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | select(.type? == &amp;quot;workspace&amp;quot;) | . as $ws&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | recurse(.nodes[]?, .floating_nodes[]?)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | select((.window_properties.class? // &amp;quot;&amp;quot;) == $c)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | $ws.name&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -9 -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ws&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        layout&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --suffix=.json&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{&amp;quot;marks&amp;quot;:[&amp;quot;%s&amp;quot;],&amp;quot;swallows&amp;quot;:[{&amp;quot;class&amp;quot;:&amp;quot;^%s$&amp;quot;}]}\n&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$mark&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$class&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        focused&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;i3-msg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; get_workspaces&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.[] | select(.focused) | .name&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unmark &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$mark&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ws&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$focused&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;append_layout &lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;workspace --no-auto-back-and-forth &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$ws&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;; append_layout &lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;; workspace --no-auto-back-and-forth &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$focused&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Remove the empty placeholder if the app fails to come back.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 25&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;[con_mark=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$mark&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;] kill&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Fallback if dracula-gtk-theme is not installed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if !&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d&lt;/span&gt;&lt;span&gt; /usr/share/themes/Dracula &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|| -d ~&lt;/span&gt;&lt;span&gt;/.themes/Dracula ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GTK_THEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Adwaita-dark&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── GTK 3 / GTK 4 ──────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Update only theme-related keys; preserve font, cursor, Xft and other local settings.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; gtk_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/gtk-3.0/settings.ini ~/.config/gtk-4.0/settings.ini&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$gtk_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; Settings gtk-theme-name &amp;quot;&lt;/span&gt;&lt;span&gt;$GTK_THEME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$gtk_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; Settings gtk-icon-theme-name Adwaita&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$gtk_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; Settings gtk-application-prefer-dark-theme&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Also via gsettings (for apps that read this)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gsettings&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; set org.gnome.desktop.interface gtk-theme &amp;quot;&lt;/span&gt;&lt;span&gt;$GTK_THEME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gsettings&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; set org.gnome.desktop.interface color-scheme &amp;#39;prefer-dark&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Qt5 / Qt6 ──────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Redirect color scheme paths in user config, not /usr/share.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt5ct/qt5ct.conf&amp;quot; Appearance color_scheme_path &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt5ct/colors/Dracula.conf&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt5ct/qt5ct.conf&amp;quot; Appearance custom_palette&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt6ct/qt6ct.conf&amp;quot; Appearance color_scheme_path &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt6ct/colors/Dracula.conf&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt6ct/qt6ct.conf&amp;quot; Appearance custom_palette&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Nextcloud client: the monochrome tray icon guesses light-on-dark and is&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# unreadable on a light bar; the colorful brand icon works in both modes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/Nextcloud/nextcloud.cfg ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/Nextcloud/nextcloud.cfg General monoIcons&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# KeePassXC follows the portal/system switch live when its in-app theme is &amp;quot;Automatic&amp;quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/keepassxc/keepassxc.ini ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/keepassxc/keepassxc.ini GUI ApplicationTheme auto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # The monochrome tray variants are FIXED light or dark and vanish on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # one of the two bars; the colorful icon is readable in both modes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Applied on the next KeePassXC start (no auto-restart: open database).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/keepassxc/keepassxc.ini GUI TrayIconAppearance colorful&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# nheko: keep theme=system. Its built-in light theme hardcodes a DARK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sidebar (#233649, Element-style) — only theme=system derives the sidebar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# and scrollbars from the Qt palette, which qt6ct supplies per mode. A live&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# palette switch leaves a running instance mixed, so restart it in place.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# theme=system is also what nheko writes back on exit, so the value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# survives its settings persistence without ordering tricks.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/nheko/nheko.conf ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/nheko/nheko.conf user theme system&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    restart_app_in_place&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nheko nheko&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── khal / ikhal ───────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/khal/config ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config view theme dark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config view frame width&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days method fg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days multiple brown&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Days with events from exactly two calendars show both colors as&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # half-and-half; three or more fall back to the &amp;quot;multiple&amp;quot; color.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days multiple_on_overflow True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Empty color keeps per-calendar day colors in the month view; the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # [palette] overrides below remap them to adaptive ANSI accents.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days color &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette header &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette footer &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;line header&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;alt header&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette bright &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette list &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;list focused&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette edit &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;edit focus&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette button &amp;quot;black, light gray, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;button focused&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;reveal focus&amp;quot; &amp;quot;white, black, standout&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;today focus&amp;quot; &amp;quot;white, black, standout&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette today &amp;quot;black, light gray, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;date header&amp;quot; &amp;quot;light red, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;date header focused&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;date header selected&amp;quot; &amp;quot;white, black, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette dayname &amp;quot;dark cyan, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette monthname &amp;quot;dark magenta, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette weeknumber_right &amp;quot;dark gray, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette alert &amp;quot;white, dark red, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette mark &amp;quot;white, dark gray, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette frame &amp;quot;dark gray, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;frame focus&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;frame focus color&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;frame focus top&amp;quot; &amp;quot;dark magenta, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette eventcolumn &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;eventcolumn focus&amp;quot; &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette calendar &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Default like khal&amp;#39;s built-in themes: a color here washes over every&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # plain day whenever the calendar column holds focus.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;calendar focus&amp;quot; &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette editbx &amp;quot;white, black, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette editcp &amp;quot;black, light gray, standout&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette popupbg &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette popupper &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette caption &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Per-calendar accents for month-view day numbers and event-list rows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # (both share the &amp;quot;calendar &amp;lt;name&amp;gt;&amp;quot; attributes, ikhal merges the config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # palette last): ANSI names track the terminal palette live, unlike&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # static RGB values from vdir `color` files. The attribute names must&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # match the discovered calendar names from `khal printcalendars`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;calendar personal&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;calendar work&amp;quot; &amp;quot;dark magenta, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Xresources / urxvt ─────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/Xresources&amp;quot; ~/.Xresources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; xrdb&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; xrdb&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -load&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.Xresources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Recolor only PTSes whose process ancestry belongs to the terminal.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# This changes Background/Foreground/Cursor and the 16-color ANSI palette&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# where the terminal supports OSC 4.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;RECOLOR_URXVT_PTS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;1&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    recolor_child_ttys&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;urxvt&amp;quot; &amp;quot;#282a36&amp;quot; &amp;quot;#f8f8f2&amp;quot; &amp;quot;#f8f8f2&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$DRACULA_ANSI_OSC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;RECOLOR_ALACRITTY_PTS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;1&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    recolor_child_ttys&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;alacritty&amp;quot; &amp;quot;#282a36&amp;quot; &amp;quot;#f8f8f2&amp;quot; &amp;quot;#f8f8f2&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$DRACULA_ANSI_OSC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;redraw_tui_apps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Alacritty ──────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;write_alacritty_theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Alacritty reloads automatically with live_config_reload=true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── i3 Theme ───────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/i3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/i3-theme.conf&amp;quot; ~/.config/i3/theme.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reload&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Polybar ────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/polybar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/polybar.ini&amp;quot; ~/.config/polybar/colors.ini&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# IPC restart first (needs enable-ipc=true per bar); fall back to a kill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# that waits until the old instances are really gone, then verify the bars&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# came up — polybar&amp;#39;s monitor detection can fail transiently right after&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# an i3 reload, which can otherwise leave the desktop without any bar.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_polybar&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar-msg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; polybar-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cmd restart&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1 2 3 4 5 6 7 8 9 10&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -x ~&lt;/span&gt;&lt;span&gt;/.config/polybar/launch.sh ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/polybar/launch.sh&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/polybar/launch.sh&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_polybar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Fixed list of the applets that belong in this machine&amp;#39;s tray. Tray icons&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# are drawn by the applets (XEmbed) with the GTK icon theme they loaded at&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# startup, so they must be restarted to match the new mode. Two pitfalls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# shape this function: XEmbed applets exit immediately when they dock into&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# a tray that is still re-initializing after the Polybar restart (hence&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# the delay and the safety net), and rapid consecutive toggles can kill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# applets a previous hook run just started (hence &amp;quot;ensure running&amp;quot; with a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# fixed list instead of &amp;quot;only restart what was running&amp;quot;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TRAY_APPS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;nm-applet pasystray flameshot&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_tray_apps&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; $TRAY_APPS;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; $TRAY_APPS;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Safety net: relaunch anything that died docking too early.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; $TRAY_APPS;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_tray_apps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Rofi ───────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Rofi reads its theme on startup; existing menus are transient.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/rofi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/rofi.rasi&amp;quot; ~/.config/rofi/theme.rasi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── neomutt ────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/neomutt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/mutt-colors&amp;quot; ~/.config/neomutt/colors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Existing sessions repaint live after they have loaded this ANSI palette once.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# mutt-wizard style setups often use ~/.config/mutt/muttrc instead.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add `source ~/.config/mutt/theme.muttrc` there, then let the hook manage:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d ~&lt;/span&gt;&lt;span&gt;/.config/mutt ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/mutt-colors&amp;quot; ~/.config/mutt/theme.muttrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── jellyfin-tui ───────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_preference&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; theme&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.local/share/jellyfin-tui/preferences&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; pref&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/.local/share/jellyfin-tui/preferences/*.json&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; theme &amp;quot;&lt;/span&gt;&lt;span&gt;$theme&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;.theme = $theme&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_config_theme&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/jellyfin-tui/config.yaml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ruby&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ruby&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; - &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$mode&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;RUBY&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;require &amp;quot;yaml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;path, mode = ARGV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cfg = YAML.load_file(path) || {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;dark = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;base&amp;quot; =&amp;gt; &amp;quot;Dark&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;background&amp;quot; =&amp;gt; &amp;quot;#282a36&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground&amp;quot; =&amp;gt; &amp;quot;#f8f8f2&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_secondary&amp;quot; =&amp;gt; &amp;quot;#d7d8e8&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_dim&amp;quot; =&amp;gt; &amp;quot;#a7abc4&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_disabled&amp;quot; =&amp;gt; &amp;quot;#6f758f&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;section_title&amp;quot; =&amp;gt; &amp;quot;#bd93f9&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;accent&amp;quot; =&amp;gt; &amp;quot;#8be9fd&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border&amp;quot; =&amp;gt; &amp;quot;#4f5268&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border_focused&amp;quot; =&amp;gt; &amp;quot;#bd93f9&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_background&amp;quot; =&amp;gt; &amp;quot;#44475a&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_foreground&amp;quot; =&amp;gt; &amp;quot;#f8f8f2&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_background&amp;quot; =&amp;gt; &amp;quot;#343746&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#f8f8f2&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_thumb&amp;quot; =&amp;gt; &amp;quot;#c6c8d6&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_track&amp;quot; =&amp;gt; &amp;quot;#44475a&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_fill&amp;quot; =&amp;gt; &amp;quot;#ffb86c&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_track&amp;quot; =&amp;gt; &amp;quot;#44475a&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_active_foreground&amp;quot; =&amp;gt; &amp;quot;#bd93f9&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#7b819d&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_background&amp;quot; =&amp;gt; &amp;quot;#343746&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_foreground&amp;quot; =&amp;gt; &amp;quot;#8be9fd&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;light = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;base&amp;quot; =&amp;gt; &amp;quot;Light&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;background&amp;quot; =&amp;gt; &amp;quot;#fdf6e3&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground&amp;quot; =&amp;gt; &amp;quot;#073642&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_secondary&amp;quot; =&amp;gt; &amp;quot;#25464d&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_dim&amp;quot; =&amp;gt; &amp;quot;#405f66&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_disabled&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;section_title&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;accent&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border_focused&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_background&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_foreground&amp;quot; =&amp;gt; &amp;quot;#fdf6e3&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_background&amp;quot; =&amp;gt; &amp;quot;#d7ebe8&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#073642&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_thumb&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_track&amp;quot; =&amp;gt; &amp;quot;#eee8d5&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_fill&amp;quot; =&amp;gt; &amp;quot;#875f00&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_track&amp;quot; =&amp;gt; &amp;quot;#d6cab0&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_active_foreground&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_background&amp;quot; =&amp;gt; &amp;quot;#eee8d5&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_foreground&amp;quot; =&amp;gt; &amp;quot;#073642&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;palette = mode == &amp;quot;light&amp;quot; ? light : dark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;managed_names = [&amp;quot;Mode Switcher&amp;quot;, &amp;quot;Dracula High Contrast&amp;quot;, &amp;quot;Solarized Light High Contrast&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;themes = cfg[&amp;quot;themes&amp;quot;].is_a?(Array) ? cfg[&amp;quot;themes&amp;quot;] : []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;unmanaged = themes.reject { |theme| theme.is_a?(Hash) &amp;amp;&amp;amp; managed_names.include?(theme[&amp;quot;name&amp;quot;]) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cfg[&amp;quot;auto_color&amp;quot;] = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cfg[&amp;quot;themes&amp;quot;] = managed_names.map { |name| { &amp;quot;name&amp;quot; =&amp;gt; name }.merge(palette) } + unmanaged&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;content = YAML.dump(cfg)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;if !File.exist?(path) || File.read(path) != content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mode_bits = File.exist?(path) ? File.stat(path).mode &amp;amp; 0o777 : 0o600&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  tmp = &amp;quot;#{path}.tmp.#{$$}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  File.write(tmp, content)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  File.chmod(mode_bits, tmp)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  File.rename(tmp, path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;RUBY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# jellyfin-tui live-reloads config.yaml, but not its preferences file.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Keep one stable selected theme and rewrite that theme&amp;#39;s colors per mode.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_preference&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Mode Switcher&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_config_theme&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;dark&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jellyfin-tui&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jellyfin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;tui&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;/&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;dev&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        set_jellyfin_tui_preference&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Mode Switcher&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── sonicradio ─────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Every built-in theme ships separate dark and light profiles, picked from&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# the terminal background at startup. A constant high-contrast theme works&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# for both modes and survives sonicradio&amp;#39;s config write-back on exit.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/sonicRadio/config.json ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.theme = 4&amp;#39; ~/.config/sonicRadio/config.json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; ~/.config/sonicRadio/config.json&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── VSCodium ───────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Patch settings.json. VSCodium usually reacts live via file watcher,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# in rare cases a &amp;quot;Reload Window&amp;quot; (Ctrl+Shift+P) is needed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/VSCodium/User/settings.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.&amp;quot;workbench.colorTheme&amp;quot; = &amp;quot;Dracula&amp;quot;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Claude Code ────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Claude Code paints its UI with truecolor values from its own theme and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ignores the terminal palette. Running sessions keep their theme until&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# restarted (or changed in-session via /config).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.claude/settings.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.theme = &amp;quot;dark&amp;quot;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Vim/Neovim (if used) ───────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/nvim&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/nvim-colorscheme.vim&amp;quot; ~/.config/nvim/colorscheme.vim&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Firefox / Thunderbird ──────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Nothing to do in the hook: the portal value is updated by darkman.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Firefox default &amp;quot;auto&amp;quot; is usually enough; force&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# widget.use-xdg-desktop-portal.settings = 1 only if auto does not work.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Full browser UI repainting may still require a Firefox restart.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Chromium ───────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Does not react live; flags in ~/.config/chromium-flags.conf take effect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# on next start. See Step 6.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── User Notification ──────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_dunst_theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;notify-send&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; weather-clear-night &amp;quot;Theme&amp;quot; &amp;quot;Dark Mode activated (Dracula)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Dark mode activated (Dracula)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the script executable:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +x ~/.local/share/dark-mode.d/apply-theme&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;step-8-the-light-mode-hook-script&quot;&gt;Step 8: The Light-Mode Hook Script&lt;/h2&gt;
&lt;p&gt;This script will be executed when &lt;code&gt;darkman&lt;/code&gt; switches to light mode.
Create the file &lt;code&gt;~/.local/share/light-mode.d/apply-theme&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;trap&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;echo &amp;quot;Hook error in: $BASH_COMMAND&amp;quot; &amp;gt;&amp;amp;2&amp;#39; ERR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# darkman.service can start before the display manager has imported the X&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# environment into the systemd user scope; without DISPLAY/XAUTHORITY every&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# GUI applet relaunched by this hook crashes on startup and xrdb fails.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# (See Step 9 for the permanent session-side fix.)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;DISPLAY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || export&lt;/span&gt;&lt;span&gt; DISPLAY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;:0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;XAUTHORITY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; xauth_candidate&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;XDG_RUNTIME_DIR&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-/&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;id -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)}/lyxauth&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.Xauthority&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$xauth_candidate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; export&lt;/span&gt;&lt;span&gt; XAUTHORITY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$xauth_candidate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Session variables from ~/.xprofile are not visible inside the service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# either; without the platform theme, relaunched Qt apps (nheko) skip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# qt5ct/qt6ct entirely and fall back to unthemed Qt defaults.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;/span&gt;&lt;span&gt; QT_QPA_PLATFORMTHEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;QT_QPA_PLATFORMTHEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;qt5ct&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;/span&gt;&lt;span&gt;qt6ct&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/themes/solarized-light&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GTK_THEME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Adwaita&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SOLARIZED_LIGHT_ANSI_OSC&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;$&amp;#39;\033]4;0;#073642\007\033]4;1;#dc322f\007\033]4;2;#5f8700\007\033]4;3;#875f00\007\033]4;4;#005f87\007\033]4;5;#af005f\007\033]4;6;#006c6b\007\033]4;7;#eee8d5\007\033]4;8;#002b36\007\033]4;9;#cb4b16\007\033]4;10;#586e00\007\033]4;11;#6c5a00\007\033]4;12;#00629d\007\033]4;13;#6c71c4\007\033]4;14;#00736f\007\033]4;15;#fdf6e3\007&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; config_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$2&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$3&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$4&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;[%s]\n&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    awk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; section=&amp;quot;&lt;/span&gt;&lt;span&gt;$section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; key=&amp;quot;&lt;/span&gt;&lt;span&gt;$key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; value=&amp;quot;&lt;/span&gt;&lt;span&gt;$value&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        BEGIN { in_section=0; section_found=0; key_done=0 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        $0 == &amp;quot;[&amp;quot; section &amp;quot;]&amp;quot; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            in_section=1; section_found=1; print; next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        /^[[:space:]]*\[/ {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if (in_section &amp;amp;&amp;amp; !key_done) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                key_done=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            in_section=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        in_section &amp;amp;&amp;amp; $0 ~ &amp;quot;^[[:space:]]*&amp;quot; key &amp;quot;[[:space:]]*=&amp;quot; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if (!key_done) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                key_done=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        { print }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        END {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            if (!section_found) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print &amp;quot;[&amp;quot; section &amp;quot;]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            } else if (in_section &amp;amp;&amp;amp; !key_done) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                print key &amp;quot;=&amp;quot; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$config_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;write_alacritty_theme&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty/theme.toml.XXXXXX&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m 0644&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/alacritty.toml&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    mv&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty/theme.toml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    touch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/alacritty/alacritty.toml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;recolor_child_ttys&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; terminal_comm&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; bg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$2&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; fg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$3&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; cursor&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$4&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; palette&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;${5&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; tty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tty&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp; -w&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/dev/&lt;/span&gt;&lt;span&gt;$tty&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;\033]708;%s\007\033]11;%s\007\033]10;%s\007\033]12;%s\007&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span&gt;$bg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$bg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$fg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$cursor&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$palette&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;%s&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$palette&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/dev/&lt;/span&gt;&lt;span&gt;$tty&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        ps&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -eo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pid=,ppid=,tty=,comm=&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; terminal_comm=&amp;quot;&lt;/span&gt;&lt;span&gt;$terminal_comm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                pid[NR]=$1; ppid[NR]=$2; tty[NR]=$3; comm[NR]=$4;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                parent[$1]=$2;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                if ($4 == terminal_comm) terminal[$1]=1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            END {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                for (i=1; i&amp;lt;=NR; i++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    p=ppid[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    while (p &amp;amp;&amp;amp; p != &amp;quot;1&amp;quot;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                        if (p in terminal) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                            if (tty[i] ~ /^pts\//) print tty[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                            break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                        p=parent[p];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;redraw_tui_apps&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pgrep&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; kill -WINCH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; neomutt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; kill -WINCH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;(^|[[:space:]])(/usr/bin/)?ikhal([[:space:]]|$)|(^|[[:space:]])khal[[:space:]]+interactive([[:space:]]|$)&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Restart a GUI app so its new window reappears exactly where the old one&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# lived, on any workspace. Uses i3&amp;#39;s native layout-restore mechanism: a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# placeholder container with swallow criteria is appended to the app&amp;#39;s old&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# workspace, and i3 materializes the next matching window directly inside&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# it — no focus-dependent placement, no post-hoc moving. Apps that were&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# not running are left closed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_app_in_place&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; proc&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$2&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; ws focused layout mark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    mark&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;restore_${&lt;/span&gt;&lt;span&gt;proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ws&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ws&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;i3-msg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; get_tree&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; c &amp;quot;&lt;/span&gt;&lt;span&gt;$class&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            recurse(.nodes[]?, .floating_nodes[]?)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | select(.type? == &amp;quot;workspace&amp;quot;) | . as $ws&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | recurse(.nodes[]?, .floating_nodes[]?)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | select((.window_properties.class? // &amp;quot;&amp;quot;) == $c)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            | $ws.name&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -9 -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ws&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        layout&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --suffix=.json&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{&amp;quot;marks&amp;quot;:[&amp;quot;%s&amp;quot;],&amp;quot;swallows&amp;quot;:[{&amp;quot;class&amp;quot;:&amp;quot;^%s$&amp;quot;}]}\n&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$mark&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$class&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        focused&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;i3-msg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; get_workspaces&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.[] | select(.focused) | .name&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unmark &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$mark&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ws&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$focused&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;append_layout &lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;workspace --no-auto-back-and-forth &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$ws&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;; append_layout &lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;; workspace --no-auto-back-and-forth &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$focused&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$layout&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Remove the empty placeholder if the app fails to come back.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 25&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;[con_mark=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span&gt;$mark&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;] kill&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$proc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_dunst_theme&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/dunst/dunstrc&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; global frame_color &amp;#39;&amp;quot;#005f87&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; global separator_color &amp;#39;&amp;quot;#93a1a1&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; global format &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;span foreground=&amp;#39;#073642&amp;#39;&amp;gt;&amp;lt;b&amp;gt;%s %p&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\\\\&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;n%b&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;/^%b&amp;quot;$/d&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_low background &amp;#39;&amp;quot;#fdf6e3&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_low foreground &amp;#39;&amp;quot;#073642&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_normal background &amp;#39;&amp;quot;#fdf6e3&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_normal foreground &amp;#39;&amp;quot;#073642&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_critical background &amp;#39;&amp;quot;#dc322f&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_critical foreground &amp;#39;&amp;quot;#fdf6e3&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; urgency_critical frame_color &amp;#39;&amp;quot;#dc322f&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dunstctl&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; dunstctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reload &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── GTK 3 / GTK 4 ──────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Update only theme-related keys; preserve font, cursor, Xft and other local settings.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; gtk_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/gtk-3.0/settings.ini ~/.config/gtk-4.0/settings.ini&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$gtk_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; Settings gtk-theme-name &amp;quot;&lt;/span&gt;&lt;span&gt;$GTK_THEME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$gtk_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; Settings gtk-icon-theme-name Adwaita&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$gtk_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; Settings gtk-application-prefer-dark-theme&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gsettings&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; set org.gnome.desktop.interface gtk-theme &amp;quot;&lt;/span&gt;&lt;span&gt;$GTK_THEME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gsettings&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; set org.gnome.desktop.interface color-scheme &amp;#39;prefer-light&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Qt5 / Qt6 ──────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt5ct/qt5ct.conf&amp;quot; Appearance color_scheme_path &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt5ct/colors/SolarizedLight.conf&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt5ct/qt5ct.conf&amp;quot; Appearance custom_palette&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt6ct/qt6ct.conf&amp;quot; Appearance color_scheme_path &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt6ct/colors/SolarizedLight.conf&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/qt6ct/qt6ct.conf&amp;quot; Appearance custom_palette&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Nextcloud client: the monochrome tray icon guesses light-on-dark and is&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# unreadable on a light bar; the colorful brand icon works in both modes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/Nextcloud/nextcloud.cfg ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/Nextcloud/nextcloud.cfg General monoIcons&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# KeePassXC follows the portal/system switch live when its in-app theme is &amp;quot;Automatic&amp;quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/keepassxc/keepassxc.ini ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/keepassxc/keepassxc.ini GUI ApplicationTheme auto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # The monochrome tray variants are FIXED light or dark and vanish on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # one of the two bars; the colorful icon is readable in both modes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Applied on the next KeePassXC start (no auto-restart: open database).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/keepassxc/keepassxc.ini GUI TrayIconAppearance colorful&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# nheko: keep theme=system. Its built-in light theme hardcodes a DARK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sidebar (#233649, Element-style) — only theme=system derives the sidebar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# and scrollbars from the Qt palette, which qt6ct supplies per mode. A live&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# palette switch leaves a running instance mixed, so restart it in place.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# theme=system is also what nheko writes back on exit, so the value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# survives its settings persistence without ordering tricks.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/nheko/nheko.conf ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/nheko/nheko.conf user theme system&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    restart_app_in_place&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nheko nheko&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── khal / ikhal ───────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/khal/config ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config view theme light&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config view frame width&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days method fg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days multiple brown&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Days with events from exactly two calendars show both colors as&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # half-and-half; three or more fall back to the &amp;quot;multiple&amp;quot; color.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days multiple_on_overflow True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Empty color keeps per-calendar day colors in the month view; the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # [palette] overrides below remap them to adaptive ANSI accents.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config highlight_days color &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette header &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette footer &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;line header&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;alt header&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette bright &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette list &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;list focused&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette edit &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;edit focus&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette button &amp;quot;black, light gray, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;button focused&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;reveal focus&amp;quot; &amp;quot;white, black, standout&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;today focus&amp;quot; &amp;quot;white, black, standout&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette today &amp;quot;black, light gray, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;date header&amp;quot; &amp;quot;light red, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;date header focused&amp;quot; &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;date header selected&amp;quot; &amp;quot;white, black, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette dayname &amp;quot;dark cyan, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette monthname &amp;quot;dark magenta, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette weeknumber_right &amp;quot;dark gray, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette alert &amp;quot;white, dark red, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette mark &amp;quot;white, dark gray, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette frame &amp;quot;dark gray, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;frame focus&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;frame focus color&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;frame focus top&amp;quot; &amp;quot;dark magenta, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette eventcolumn &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;eventcolumn focus&amp;quot; &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette calendar &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Default like khal&amp;#39;s built-in themes: a color here washes over every&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # plain day whenever the calendar column holds focus.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;calendar focus&amp;quot; &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette editbx &amp;quot;white, black, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette editcp &amp;quot;black, light gray, standout&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette popupbg &amp;quot;&amp;#39;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette popupper &amp;quot;white, black, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette caption &amp;quot;dark blue, &amp;#39;&amp;#39;, bold&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Per-calendar accents for month-view day numbers and event-list rows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # (both share the &amp;quot;calendar &amp;lt;name&amp;gt;&amp;quot; attributes, ikhal merges the config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # palette last): ANSI names track the terminal palette live, unlike&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # static RGB values from vdir `color` files. The attribute names must&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # match the discovered calendar names from `khal printcalendars`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;calendar personal&amp;quot; &amp;quot;dark blue, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/khal/config palette &amp;quot;calendar work&amp;quot; &amp;quot;dark magenta, &amp;#39;&amp;#39;, &amp;#39;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Xresources / urxvt ─────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/Xresources&amp;quot; ~/.Xresources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; xrdb&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; xrdb&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -load&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.Xresources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Recolor only PTSes whose process ancestry belongs to the terminal.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# This changes Background/Foreground/Cursor and the 16-color ANSI palette&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# where the terminal supports OSC 4.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;RECOLOR_URXVT_PTS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;1&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    recolor_child_ttys&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;urxvt&amp;quot; &amp;quot;#fdf6e3&amp;quot; &amp;quot;#073642&amp;quot; &amp;quot;#586e75&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$SOLARIZED_LIGHT_ANSI_OSC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;RECOLOR_ALACRITTY_PTS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;1&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    recolor_child_ttys&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;alacritty&amp;quot; &amp;quot;#fdf6e3&amp;quot; &amp;quot;#073642&amp;quot; &amp;quot;#586e75&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$SOLARIZED_LIGHT_ANSI_OSC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;redraw_tui_apps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Alacritty ──────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;write_alacritty_theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── i3 ─────────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/i3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/i3-theme.conf&amp;quot; ~/.config/i3/theme.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i3-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reload&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Polybar ────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/polybar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/polybar.ini&amp;quot; ~/.config/polybar/colors.ini&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# IPC restart first (needs enable-ipc=true per bar); fall back to a kill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# that waits until the old instances are really gone, then verify the bars&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# came up — polybar&amp;#39;s monitor detection can fail transiently right after&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# an i3 reload, which can otherwise leave the desktop without any bar.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_polybar&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar-msg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; polybar-msg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cmd restart&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1 2 3 4 5 6 7 8 9 10&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -x ~&lt;/span&gt;&lt;span&gt;/.config/polybar/launch.sh ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/polybar/launch.sh&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; polybar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/polybar/launch.sh&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_polybar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Fixed list of the applets that belong in this machine&amp;#39;s tray. Tray icons&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# are drawn by the applets (XEmbed) with the GTK icon theme they loaded at&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# startup, so they must be restarted to match the new mode. Two pitfalls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# shape this function: XEmbed applets exit immediately when they dock into&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# a tray that is still re-initializing after the Polybar restart (hence&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# the delay and the safety net), and rapid consecutive toggles can kill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# applets a previous hook run just started (hence &amp;quot;ensure running&amp;quot; with a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# fixed list instead of &amp;quot;only restart what was running&amp;quot;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TRAY_APPS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;nm-applet pasystray flameshot&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_tray_apps&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; $TRAY_APPS;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pkill&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; $TRAY_APPS;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Safety net: relaunch anything that died docking too early.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; $TRAY_APPS;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setsid&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$app&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;restart_tray_apps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Rofi ───────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Rofi reads its theme on startup; existing menus are transient.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/rofi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/rofi.rasi&amp;quot; ~/.config/rofi/theme.rasi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── neomutt ────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/neomutt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/mutt-colors&amp;quot; ~/.config/neomutt/colors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d ~&lt;/span&gt;&lt;span&gt;/.config/mutt ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/mutt-colors&amp;quot; ~/.config/mutt/theme.muttrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── jellyfin-tui ───────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_preference&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; theme&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.local/share/jellyfin-tui/preferences&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; pref&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/.local/share/jellyfin-tui/preferences/*.json&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        jq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --arg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; theme &amp;quot;&lt;/span&gt;&lt;span&gt;$theme&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;.theme = $theme&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_config_theme&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/jellyfin-tui/config.yaml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ruby&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1 || return&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ruby&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; - &amp;quot;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$mode&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;RUBY&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;require &amp;quot;yaml&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;path, mode = ARGV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cfg = YAML.load_file(path) || {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;dark = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;base&amp;quot; =&amp;gt; &amp;quot;Dark&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;background&amp;quot; =&amp;gt; &amp;quot;#282a36&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground&amp;quot; =&amp;gt; &amp;quot;#f8f8f2&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_secondary&amp;quot; =&amp;gt; &amp;quot;#d7d8e8&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_dim&amp;quot; =&amp;gt; &amp;quot;#a7abc4&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_disabled&amp;quot; =&amp;gt; &amp;quot;#6f758f&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;section_title&amp;quot; =&amp;gt; &amp;quot;#bd93f9&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;accent&amp;quot; =&amp;gt; &amp;quot;#8be9fd&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border&amp;quot; =&amp;gt; &amp;quot;#4f5268&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border_focused&amp;quot; =&amp;gt; &amp;quot;#bd93f9&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_background&amp;quot; =&amp;gt; &amp;quot;#44475a&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_foreground&amp;quot; =&amp;gt; &amp;quot;#f8f8f2&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_background&amp;quot; =&amp;gt; &amp;quot;#343746&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#f8f8f2&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_thumb&amp;quot; =&amp;gt; &amp;quot;#c6c8d6&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_track&amp;quot; =&amp;gt; &amp;quot;#44475a&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_fill&amp;quot; =&amp;gt; &amp;quot;#ffb86c&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_track&amp;quot; =&amp;gt; &amp;quot;#44475a&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_active_foreground&amp;quot; =&amp;gt; &amp;quot;#bd93f9&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#7b819d&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_background&amp;quot; =&amp;gt; &amp;quot;#343746&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_foreground&amp;quot; =&amp;gt; &amp;quot;#8be9fd&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;light = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;base&amp;quot; =&amp;gt; &amp;quot;Light&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;background&amp;quot; =&amp;gt; &amp;quot;#fdf6e3&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground&amp;quot; =&amp;gt; &amp;quot;#073642&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_secondary&amp;quot; =&amp;gt; &amp;quot;#25464d&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_dim&amp;quot; =&amp;gt; &amp;quot;#405f66&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;foreground_disabled&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;section_title&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;accent&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;border_focused&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_background&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_active_foreground&amp;quot; =&amp;gt; &amp;quot;#fdf6e3&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_background&amp;quot; =&amp;gt; &amp;quot;#d7ebe8&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;selected_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#073642&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_thumb&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;scrollbar_track&amp;quot; =&amp;gt; &amp;quot;#eee8d5&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_fill&amp;quot; =&amp;gt; &amp;quot;#875f00&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;progress_track&amp;quot; =&amp;gt; &amp;quot;#d6cab0&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_active_foreground&amp;quot; =&amp;gt; &amp;quot;#005f87&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;tab_inactive_foreground&amp;quot; =&amp;gt; &amp;quot;#586e75&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_background&amp;quot; =&amp;gt; &amp;quot;#eee8d5&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;quot;album_header_foreground&amp;quot; =&amp;gt; &amp;quot;#073642&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;palette = mode == &amp;quot;light&amp;quot; ? light : dark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;managed_names = [&amp;quot;Mode Switcher&amp;quot;, &amp;quot;Dracula High Contrast&amp;quot;, &amp;quot;Solarized Light High Contrast&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;themes = cfg[&amp;quot;themes&amp;quot;].is_a?(Array) ? cfg[&amp;quot;themes&amp;quot;] : []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;unmanaged = themes.reject { |theme| theme.is_a?(Hash) &amp;amp;&amp;amp; managed_names.include?(theme[&amp;quot;name&amp;quot;]) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cfg[&amp;quot;auto_color&amp;quot;] = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cfg[&amp;quot;themes&amp;quot;] = managed_names.map { |name| { &amp;quot;name&amp;quot; =&amp;gt; name }.merge(palette) } + unmanaged&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;content = YAML.dump(cfg)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;if !File.exist?(path) || File.read(path) != content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mode_bits = File.exist?(path) ? File.stat(path).mode &amp;amp; 0o777 : 0o600&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  tmp = &amp;quot;#{path}.tmp.#{$$}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  File.write(tmp, content)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  File.chmod(mode_bits, tmp)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  File.rename(tmp, path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;RUBY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# jellyfin-tui live-reloads config.yaml, but not its preferences file.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Keep one stable selected theme and rewrite that theme&amp;#39;s colors per mode.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_preference&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Mode Switcher&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_jellyfin_tui_config_theme&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;light&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jellyfin-tui&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pgrep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jellyfin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;tui&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;/&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;dev&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        set_jellyfin_tui_preference&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Mode Switcher&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── sonicradio ─────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Every built-in theme ships separate dark and light profiles, picked from&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# the terminal background at startup. A constant high-contrast theme works&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# for both modes and survives sonicradio&amp;#39;s config write-back on exit.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f ~&lt;/span&gt;&lt;span&gt;/.config/sonicRadio/config.json ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.theme = 4&amp;#39; ~/.config/sonicRadio/config.json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; ~/.config/sonicRadio/config.json&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── VSCodium ───────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.config/VSCodium/User/settings.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.&amp;quot;workbench.colorTheme&amp;quot; = &amp;quot;Solarized Light&amp;quot;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Claude Code ────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/.claude/settings.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.theme = &amp;quot;light&amp;quot;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$CLAUDE_SETTINGS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── Neovim ─────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/nvim&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$THEME_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/nvim-colorscheme.vim&amp;quot; ~/.config/nvim/colorscheme.vim&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ─── User Notification ──────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_dunst_theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;notify-send&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; weather-clear &amp;quot;Theme&amp;quot; &amp;quot;Light Mode activated (Solarized Light)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Light mode activated (Solarized Light)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the script executable:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +x ~/.local/share/light-mode.d/apply-theme&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;step-9-initial-state-and-persistence-on-login&quot;&gt;Step 9: Initial State and Persistence on Login&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;darkman&lt;/code&gt; is designed as a user service that &lt;strong&gt;persists its own state&lt;/strong&gt;. The service typically remembers the last mode after a restart and executes the corresponding hooks at startup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important — no hardcoded &lt;code&gt;darkman set&lt;/code&gt; calls in &lt;code&gt;.xprofile&lt;/code&gt;!&lt;/strong&gt;
It might be tempting to write &lt;code&gt;darkman set dark&lt;/code&gt; in &lt;code&gt;.xprofile&lt;/code&gt; to “always start with Dark mode.” However, this is counterproductive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It overwrites the last manual toggle on every login.&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;completely disables auto-switching based on sunrise/sunset&lt;/strong&gt;, if you enable it later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just let the service run.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;reality-check-verify-persistence&quot;&gt;Reality Check: Verify Persistence&lt;/h3&gt;
&lt;p&gt;In practice, reliable persistence depends on the interplay between the user service, login manager, and XDG state directory. &lt;strong&gt;Do not blindly trust it – check it after the first login cycle&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# What does darkman currently think?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;darkman&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; get&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Was the service started cleanly at login and did it trigger hooks?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; darkman.service&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -b&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;darkman get&lt;/code&gt; returns a different mode than expected, or if the hook scripts were not executed at login, you have a persistence problem (see next section).&lt;/p&gt;
&lt;h3 id=&quot;if-persistence-is-unreliable&quot;&gt;If Persistence is Unreliable&lt;/h3&gt;
&lt;p&gt;Some possible countermeasures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure &lt;code&gt;darkman.service&lt;/code&gt; is truly enabled: &lt;code&gt;systemctl --user is-enabled darkman.service&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In TTY login + &lt;code&gt;startx&lt;/code&gt; setups, source &lt;code&gt;~/.xprofile&lt;/code&gt; from &lt;code&gt;~/.xinitrc&lt;/code&gt; before &lt;code&gt;exec i3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Import X session variables into the user service manager — treat this as required, not optional.&lt;/strong&gt; &lt;code&gt;darkman.service&lt;/code&gt; usually starts before the display manager has exported &lt;code&gt;DISPLAY&lt;/code&gt;/&lt;code&gt;XAUTHORITY&lt;/code&gt;, and a long-running service keeps the environment it started with forever. The symptoms are sneaky: OSC recoloring, Polybar IPC, and config rewrites all work without X, so the switcher &lt;em&gt;looks&lt;/em&gt; fine — but &lt;code&gt;xrdb&lt;/code&gt; fails and &lt;strong&gt;every GUI process the hooks relaunch (tray applets, nheko) crashes instantly&lt;/strong&gt; with “could not connect to display”. Put this in &lt;code&gt;~/.xinitrc&lt;/code&gt; (or your session startup) before &lt;code&gt;exec i3&lt;/code&gt;:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dbus-update-activation-environment&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --systemd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; DISPLAY XAUTHORITY XDG_CURRENT_DESKTOP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; import-environment DISPLAY XAUTHORITY XDG_CURRENT_DESKTOP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; try-restart darkman.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;The &lt;code&gt;try-restart&lt;/code&gt; makes darkman re-run the current mode’s hook with the freshly imported environment, which also repairs the failed X calls from its too-early boot start. The hook scripts above additionally carry a &lt;code&gt;DISPLAY&lt;/code&gt;/&lt;code&gt;XAUTHORITY&lt;/code&gt; fallback as a second line of defense.&lt;/li&gt;
&lt;li&gt;If hooks run too early and cannot reach X/i3, do not add &lt;code&gt;darkman set ...&lt;/code&gt; to &lt;code&gt;.xprofile&lt;/code&gt;. Fix the environment import above and restart the user service once:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; restart darkman.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;optional-auto-switching-based-on-sunrise-sunset&quot;&gt;Optional: Auto-Switching Based on Sunrise/Sunset&lt;/h3&gt;
&lt;p&gt;If &lt;code&gt;darkman&lt;/code&gt; should automatically switch based on time of day, create the file &lt;code&gt;~/.config/darkman/config.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;lat&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 48.2082&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;lng&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 16.3738&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;usegeoclue&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(The coordinates provided here are for Vienna – adjust them to your location.)&lt;/p&gt;
&lt;p&gt;The service calculates sunrise and sunset times from this and automatically triggers the hooks.&lt;/p&gt;
&lt;h3 id=&quot;if-you-really-need-a-default-value-on-the-very-first-start&quot;&gt;If you really need a default value on the very first start&lt;/h3&gt;
&lt;p&gt;If you’ve just installed &lt;code&gt;darkman&lt;/code&gt; and want a defined initial state for the very first toggle, perform this &lt;strong&gt;manually once&lt;/strong&gt; in the shell:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;darkman&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; set dark&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;— not in &lt;code&gt;.xprofile&lt;/code&gt;. From the next login onwards, the service will remember.&lt;/p&gt;
&lt;h2 id=&quot;step-10-obtain-theme-files&quot;&gt;Step 10: Obtain Theme Files&lt;/h2&gt;
&lt;p&gt;For each application, place a dark and a light variant in &lt;code&gt;~/.config/themes/&amp;lt;theme&amp;gt;/&lt;/code&gt;. The following commands cover most cases. You can paste these directly:&lt;/p&gt;
&lt;h3 id=&quot;alacritty&quot;&gt;Alacritty&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://raw.githubusercontent.com/dracula/alacritty/master/dracula.toml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;     -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/alacritty.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://raw.githubusercontent.com/alacritty/alacritty-theme/master/themes/solarized_light.toml&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;     -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/solarized-light/alacritty.toml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The upstream Solarized Light terminal palette is faithful to the original scheme, but several TUI applications render blue/cyan/yellow text too lightly on &lt;code&gt;#fdf6e3&lt;/code&gt;. For a terminal-focused setup, use this high-contrast variant instead of the raw upstream light file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/solarized-light/alacritty.toml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Colors (Solarized Light High Contrast)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[colors.primary]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;background = &amp;#39;#fdf6e3&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;foreground = &amp;#39;#073642&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[colors.normal]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;black   = &amp;#39;#073642&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;red     = &amp;#39;#dc322f&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;green   = &amp;#39;#5f8700&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;yellow  = &amp;#39;#875f00&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;blue    = &amp;#39;#005f87&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;magenta = &amp;#39;#af005f&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cyan    = &amp;#39;#006c6b&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;white   = &amp;#39;#eee8d5&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[colors.bright]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;black   = &amp;#39;#002b36&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;red     = &amp;#39;#cb4b16&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;green   = &amp;#39;#586e00&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;yellow  = &amp;#39;#6c5a00&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;blue    = &amp;#39;#00629d&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;magenta = &amp;#39;#6c71c4&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;cyan    = &amp;#39;#00736f&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;white   = &amp;#39;#fdf6e3&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your main &lt;code&gt;~/.config/alacritty/alacritty.toml&lt;/code&gt;, import the generated theme file the hook rewrites and confirm live-reload is on. Live-reload defaults to enabled in current Alacritty versions, but being explicit avoids confusion if a future upstream change flips the default:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;general&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import = [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;~/.config/alacritty/theme.toml&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;live_config_reload =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;   # default; explicit for clarity&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TOML note:&lt;/strong&gt; Since Alacritty 0.14, &lt;code&gt;import&lt;/code&gt;, &lt;code&gt;working_directory&lt;/code&gt;, &lt;code&gt;live_config_reload&lt;/code&gt;, and &lt;code&gt;ipc_socket&lt;/code&gt; live under &lt;code&gt;[general]&lt;/code&gt;. If you run an older Alacritty, check &lt;code&gt;man 5 alacritty&lt;/code&gt; for your version before copying this block.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;xresources-urxvt&quot;&gt;Xresources / urxvt&lt;/h3&gt;
&lt;p&gt;The upstream &lt;code&gt;dracula/xresources&lt;/code&gt; file uses a slightly different ANSI variant (pure black &lt;code&gt;#000000&lt;/code&gt;, muted whites &lt;code&gt;#bfbfbf&lt;/code&gt;/&lt;code&gt;#e6e6e6&lt;/code&gt;) than the official Dracula Alacritty theme. If the OSC nudge, the Xresources, and the Alacritty file disagree, a live-recolored terminal and a freshly started one will show two different palettes side by side. Write a flat file with the official values instead:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/Xresources&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! Dracula — flat, aligned with the official Alacritty palette&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.foreground: #f8f8f2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.background: #282a36&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*cursorColor: #f8f8f2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color0:  #21222c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color8:  #6272a4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color1:  #ff5555&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color9:  #ff6e6e&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color2:  #50fa7b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color10: #69ff94&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color3:  #f1fa8c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color11: #ffffa5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color4:  #bd93f9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color12: #d6acff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color5:  #ff79c6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color13: #ff92df&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color6:  #8be9fd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color14: #a4ffff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color7:  #f8f8f2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*.color15: #ffffff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Solarized Light, the upstream &lt;code&gt;solarized/xresources&lt;/code&gt; file uses C preprocessor &lt;code&gt;#define&lt;/code&gt; statements. Many display managers and login flows invoke &lt;code&gt;xrdb&lt;/code&gt; with &lt;code&gt;-nocpp&lt;/code&gt;, which means those defines are not expanded and color entries that depend on them can fail to load as intended. To avoid this entirely, write a flat (preprocessor-free) version directly:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/solarized-light/Xresources&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! Solarized Light — flat, no #define preprocessing required&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*background:            #fdf6e3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*foreground:            #073642&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;URxvt.foreground:       #073642&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;URxvt*foreground:       #073642&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*fadeColor:             #fdf6e3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*cursorColor:           #586e75&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*pointerColorBackground:#93a1a1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*pointerColorForeground:#586e75&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! black&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color0:  #073642&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color8:  #002b36&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! red&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color1:  #dc322f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color9:  #cb4b16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! green&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color2:  #5f8700&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color10: #586e00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! yellow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color3:  #875f00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color11: #6c5a00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! blue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color4:  #005f87&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color12: #00629d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! magenta&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color5:  #af005f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color13: #6c71c4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! cyan&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color6:  #006c6b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color14: #00736f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;! white&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color7:  #eee8d5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;*color15: #fdf6e3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The values above keep the Solarized Light background and base colors but deliberately darken several accent colors. This is less purist than the canonical palette, but it is much more readable for TUIs such as neomutt, ikhal, sonicradio, and other apps that rely heavily on ANSI blue/cyan/yellow.&lt;/p&gt;
&lt;p&gt;The hook uses &lt;code&gt;xrdb -load&lt;/code&gt;, not &lt;code&gt;xrdb -merge&lt;/code&gt;, because this setup manages &lt;code&gt;.Xresources&lt;/code&gt; as a complete theme file. &lt;code&gt;-merge&lt;/code&gt; keeps old keys that are absent in the new file; in practice that can leave stale urxvt values from the previous mode in the live Xresources database.&lt;/p&gt;
&lt;h3 id=&quot;polybar&quot;&gt;Polybar&lt;/h3&gt;
&lt;p&gt;See &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-5-integrate-polybar&quot;&gt;Step 5&lt;/a&gt; — minimal Dracula and Solarized Light palettes are inlined there. Copy them into &lt;code&gt;~/.config/themes/&amp;lt;theme&amp;gt;/polybar.ini&lt;/code&gt; if you haven’t already, then include &lt;code&gt;~/.config/polybar/colors.ini&lt;/code&gt; from your real Polybar config.&lt;/p&gt;
&lt;h3 id=&quot;rofi&quot;&gt;Rofi&lt;/h3&gt;
&lt;p&gt;Rofi reads its theme file when the menu starts. Point your main config at a stable user theme path once:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@theme &amp;quot;~/.config/rofi/theme.rasi&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create &lt;code&gt;~/.config/themes/dracula/rofi.rasi&lt;/code&gt; and &lt;code&gt;~/.config/themes/solarized-light/rofi.rasi&lt;/code&gt;; the hooks above switch &lt;code&gt;~/.config/rofi/theme.rasi&lt;/code&gt; to the active file. This affects the next Rofi invocation. A menu that is already open will not repaint live.&lt;/p&gt;
&lt;h3 id=&quot;neomutt&quot;&gt;neomutt&lt;/h3&gt;
&lt;p&gt;Use terminal-palette colors for NeoMutt unless you have deliberately configured a DirectColor terminfo entry. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://neomutt.org/guide/configuration&quot;&gt;official NeoMutt configuration guide&lt;/a&gt; allows hexadecimal &lt;code&gt;#RRGGBB&lt;/code&gt; colors only when &lt;code&gt;$color_directcolor&lt;/code&gt; is set, and that option must be active before any &lt;code&gt;color&lt;/code&gt; commands are read. On many i3/Alacritty systems &lt;code&gt;COLORTERM=truecolor&lt;/code&gt; is not enough for NeoMutt: &lt;code&gt;infocmp &quot;$TERM&quot;&lt;/code&gt; may show 256 colors but no &lt;code&gt;Tc&lt;/code&gt;/&lt;code&gt;RGB&lt;/code&gt; DirectColor capability, which makes HEX colors fail with “color not supported by terminal”.&lt;/p&gt;
&lt;p&gt;For live repainting, use the &lt;strong&gt;same semantic ANSI color file&lt;/strong&gt; in both theme directories. NeoMutt keeps the same &lt;code&gt;color0&lt;/code&gt;-&lt;code&gt;color15&lt;/code&gt; attributes in memory; the hooks change what those terminal color slots mean:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula ~/.config/themes/solarized-light&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/mutt-colors&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Semantic ANSI NeoMutt palette for the mode switcher.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_author *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_collapsed *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_date *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_flags *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_label *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_number *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_size *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_subject *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_tag *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor index_tags *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor body *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor header *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;uncolor status *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color normal              default default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Never reuse one background pair for two different row markers: the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# cursor must stay visible on top of unread rows (color15/color8).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color indicator           color0  color7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color status              color15 color8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color tree                color4  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color error               color15 color1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color message             color2  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color prompt              color2  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color options             color4  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color progress            color0  color7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color signature           color8  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color attachment          color2  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color search              reverse color5 default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color markers             color1  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color tilde               color8  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color hdrdefault          color6  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_background  default default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_divider     color8  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_flagged     color3  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_highlight   color15 color8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_indicator   color15 color8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_new         color4  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_ordinary    default default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_spool_file  default default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color sidebar_unread      color2  default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color header              color4 default &amp;quot;^Subject:.*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color body                color4 default &amp;quot;[[:alnum:]_.+%-]+@[[:alnum:].-]+&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color body                color3 default &amp;quot;(https?|ftp)://[[:alnum:].,/%~_:?&amp;amp;=#,+-]+&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color body                color6 default &amp;quot;(^|[[:space:]])\\*[^[:space:]]+\\*([[:space:]]|$)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color body                color6 default &amp;quot;(^|[[:space:]])_[^[:space:]]+_([[:space:]]|$)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color body                color6 default &amp;quot;(^|[[:space:]])/[^[:space:]]+/([[:space:]]|$)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color quoted              color4 default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color quoted1             color6 default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color quoted2             color2 default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color quoted3             color5 default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color quoted4             color1 default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# State rows with visible backgrounds that work on both terminal palettes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# &amp;quot;reverse colorN default&amp;quot; renders an accent background whose text takes the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# terminal&amp;#39;s default background color — the contrast is identical to using&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# the accent as a foreground, so it stays readable in both modes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index               color5  default &amp;quot;~Q&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index               color8  default &amp;quot;~v&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index               color15 color8  &amp;quot;~U&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index               reverse color6 default &amp;quot;~T&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index               reverse color3 default &amp;quot;~F&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index               reverse color1 default &amp;quot;~D&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Column accents only on rows without a state background, so state rows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# stay uniform blocks instead of getting default-background holes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index_author        color5 default &amp;quot;!(~U|~T|~F|~D)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index_date          color2 default &amp;quot;!(~U|~T|~F|~D)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index_flags         color4 default &amp;quot;!(~U|~T|~F|~D)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index_number        color4 default &amp;quot;!(~U|~T|~F|~D)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;color index_size          color3 default &amp;quot;!(~U|~T|~F|~D)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/mutt-colors ~/.config/themes/solarized-light/mutt-colors&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;indicator&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, and &lt;code&gt;sidebar_highlight&lt;/code&gt; rules deliberately stay on the neutral slots (&lt;code&gt;color0&lt;/code&gt;, &lt;code&gt;color7&lt;/code&gt;, &lt;code&gt;color8&lt;/code&gt;, &lt;code&gt;color15&lt;/code&gt;). Accent slots are bright pastels in Dracula but dark tones in the Solarized Light High Contrast palette, so an accent background fails in one of the two modes: &lt;code&gt;color15&lt;/code&gt; on a &lt;code&gt;color4&lt;/code&gt; background reads as near-white on light purple in Dracula (about 1.9:1 contrast), and &lt;code&gt;color0&lt;/code&gt; on &lt;code&gt;color3&lt;/code&gt; as dark slate on dark yellow in Solarized Light (about 2.3:1). The neutral pairs stay above 4.5:1 in both palettes.&lt;/p&gt;
&lt;p&gt;A second design rule matters as soon as rows get background highlighting: &lt;strong&gt;never reuse one background pair for two different marker types.&lt;/strong&gt; If the cursor (&lt;code&gt;indicator&lt;/code&gt;) and unread rows shared &lt;code&gt;color15&lt;/code&gt;/&lt;code&gt;color8&lt;/code&gt;, the cursor would become invisible while sitting on unread mail. That is why the palette above splits them: cursor = bright &lt;code&gt;color0&lt;/code&gt;/&lt;code&gt;color7&lt;/code&gt; bar, unread = calm &lt;code&gt;color15&lt;/code&gt;/&lt;code&gt;color8&lt;/code&gt; block, search = magenta via &lt;code&gt;reverse color5&lt;/code&gt; — each marker owns its background.&lt;/p&gt;
&lt;p&gt;The mail-state rows still get colored backgrounds, just through a different mechanism: &lt;code&gt;reverse colorN default&lt;/code&gt; makes NeoMutt render the row in reverse video, which displays the accent as the background and the terminal’s default &lt;em&gt;background&lt;/em&gt; color as the text. The resulting contrast is mathematically identical to the accent used as a foreground on the default background — and that combination is readable in both modes by definition, otherwise the accent would be useless as a text color. This yields tagged = cyan/teal block, flagged = gold block, deleted = red block, while unread mail uses the explicit neutral &lt;code&gt;color15&lt;/code&gt;/&lt;code&gt;color8&lt;/code&gt; pair as a calmer highlight. The per-column accents are restricted to &lt;code&gt;!(~U|~T|~F|~D)&lt;/code&gt; because an &lt;code&gt;index_author&lt;/code&gt; rule with a &lt;code&gt;default&lt;/code&gt; background would otherwise punch holes into the state rows.&lt;/p&gt;
&lt;p&gt;If your setup comes from &lt;code&gt;mutt-wizard&lt;/code&gt;, your main config is often &lt;code&gt;~/.config/mutt/muttrc&lt;/code&gt;, not &lt;code&gt;~/.config/neomutt/&lt;/code&gt;. In that case add this once:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source ~/.config/mutt/theme.muttrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and let the hooks switch &lt;code&gt;~/.config/mutt/theme.muttrc&lt;/code&gt; instead of &lt;code&gt;~/.config/neomutt/colors&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If a NeoMutt instance is already running with an older 256-color or HEX theme loaded, it needs one manual reload once. Press &lt;code&gt;:&lt;/code&gt; to open NeoMutt’s command prompt, then run:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source ~/.config/mutt/theme.muttrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, further Dark/Light switches can repaint via the terminal OSC palette and the hook’s &lt;code&gt;SIGWINCH&lt;/code&gt; redraw nudge. If you maintain your own color files, start them with &lt;code&gt;uncolor index *&lt;/code&gt;, &lt;code&gt;uncolor body *&lt;/code&gt;, &lt;code&gt;uncolor header *&lt;/code&gt;, and any other list-style color objects you use. Otherwise old dark rules and new light rules can stack together after a manual &lt;code&gt;:source&lt;/code&gt;. Also keep body regexes POSIX-safe: use classes such as &lt;code&gt;[[:alnum:]_.+%-]&lt;/code&gt;, and place &lt;code&gt;-&lt;/code&gt; at the end of a character class. Ambiguous ranges can make NeoMutt abort with errors such as “invalid endpoint in range expression”.&lt;/p&gt;
&lt;h3 id=&quot;khal-ikhal&quot;&gt;khal / ikhal&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ikhal&lt;/code&gt; loads its Urwid palette once at startup. It does not watch &lt;code&gt;~/.config/khal/config&lt;/code&gt; for theme changes, so rewriting &lt;code&gt;[palette]&lt;/code&gt; alone does not repaint an already running instance. The live strategy is the same as NeoMutt: use only ANSI color names and let the terminal palette change underneath.&lt;/p&gt;
&lt;p&gt;Do not use &lt;code&gt;dark blue&lt;/code&gt; as a large focused background. In the Dracula terminal palette it intentionally maps to purple, which looks good as an accent but turns the focused mini-calendar into a purple block. Keep &lt;code&gt;dark blue&lt;/code&gt; for foreground accents and use neutral &lt;code&gt;black&lt;/code&gt; or empty backgrounds for broad focus surfaces.&lt;/p&gt;
&lt;p&gt;The same rule applies to every accent slot. &lt;code&gt;dark cyan&lt;/code&gt; and &lt;code&gt;dark green&lt;/code&gt; map to dark teal/olive in the Solarized Light High Contrast palette but to bright pastels in Dracula, so as backgrounds they fail in exactly one of the two modes: &lt;code&gt;button = black, dark cyan&lt;/code&gt; drops to about 2.1:1 contrast in Light mode, and &lt;code&gt;mark = white, dark green&lt;/code&gt; to about 1.1:1 in Dracula. Treat ANSI slots 1–6 and 9–14 as foreground-only and build backgrounds from &lt;code&gt;black&lt;/code&gt;, &lt;code&gt;dark gray&lt;/code&gt;, &lt;code&gt;light gray&lt;/code&gt;, and &lt;code&gt;white&lt;/code&gt; — that is why the palette below uses &lt;code&gt;button = black, light gray&lt;/code&gt; and &lt;code&gt;mark = white, dark gray&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The hooks above still set &lt;code&gt;[view] theme&lt;/code&gt; for next starts, but the visible custom palette stays semantic and identical in both modes:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[view]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;theme&lt;/span&gt;&lt;span&gt; = light&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;frame&lt;/span&gt;&lt;span&gt; = width&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[highlight_days]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;method&lt;/span&gt;&lt;span&gt; = fg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;multiple&lt;/span&gt;&lt;span&gt; = brown&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# two-calendar days show both colors half-and-half; three or more&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# fall back to the &amp;quot;multiple&amp;quot; color&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;multiple_on_overflow&lt;/span&gt;&lt;span&gt; = True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# empty: per-calendar day colors via the palette overrides below&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;color&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[palette]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;header&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;footer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;line &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;header&lt;/span&gt;&lt;span&gt; = dark blue, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;alt &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;header&lt;/span&gt;&lt;span&gt; = dark blue, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;bright&lt;/span&gt;&lt;span&gt; = dark blue, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;list&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;list &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focused&lt;/span&gt;&lt;span&gt; = white, black, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;edit&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;edit &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focus&lt;/span&gt;&lt;span&gt; = white, black, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;button&lt;/span&gt;&lt;span&gt; = black, light gray, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;button &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focused&lt;/span&gt;&lt;span&gt; = white, black, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;reveal &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focus&lt;/span&gt;&lt;span&gt; = white, black, standout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;today &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focus&lt;/span&gt;&lt;span&gt; = white, black, standout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;today&lt;/span&gt;&lt;span&gt; = black, light gray, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;date &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;header&lt;/span&gt;&lt;span&gt; = light red, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;date header &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focused&lt;/span&gt;&lt;span&gt; = white, black, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;date header &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;selected&lt;/span&gt;&lt;span&gt; = white, black, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;dayname&lt;/span&gt;&lt;span&gt; = dark cyan, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;monthname&lt;/span&gt;&lt;span&gt; = dark magenta, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;weeknumber_right&lt;/span&gt;&lt;span&gt; = dark gray, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alert&lt;/span&gt;&lt;span&gt; = white, dark red, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;mark&lt;/span&gt;&lt;span&gt; = white, dark gray, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;frame&lt;/span&gt;&lt;span&gt; = dark gray, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;frame &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focus&lt;/span&gt;&lt;span&gt; = dark blue, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;frame focus &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;color&lt;/span&gt;&lt;span&gt; = dark blue, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;frame focus &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;top&lt;/span&gt;&lt;span&gt; = dark magenta, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;eventcolumn&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;eventcolumn &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focus&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;calendar&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;calendar &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;focus&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;editbx&lt;/span&gt;&lt;span&gt; = white, black, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;editcp&lt;/span&gt;&lt;span&gt; = black, light gray, standout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;popupbg&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;popupper&lt;/span&gt;&lt;span&gt; = white, black, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;caption&lt;/span&gt;&lt;span&gt; = dark blue, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, bold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;calendar &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;personal&lt;/span&gt;&lt;span&gt; = dark blue, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;calendar &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;work&lt;/span&gt;&lt;span&gt; = dark magenta, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;event-days-and-calendar-colors&quot;&gt;Event days and calendar colors&lt;/h3&gt;
&lt;p&gt;If your calendars come from a CalDAV server and &lt;code&gt;vdirsyncer&lt;/code&gt; syncs &lt;code&gt;metadata = [&quot;color&quot;]&lt;/code&gt;, each vdir carries an RGB color file (for example &lt;code&gt;#1c57ec&lt;/code&gt;). Those static RGB values cannot adapt to a mode switch: a dark blue that reads fine on a light background drops below 3:1 contrast on a dark one. Worse, in &lt;code&gt;type = discover&lt;/code&gt; setups the vdir color takes precedence over any &lt;code&gt;color&lt;/code&gt; value in the khal config, so you cannot neutralize it there — and editing the vdir files is not an option either, because metasync would push the change back to your server.&lt;/p&gt;
&lt;p&gt;The escape hatch is the palette merge order: ikhal builds its palette from the theme, then appends the generated per-calendar and highlight attributes, and merges the config &lt;code&gt;[palette]&lt;/code&gt; section &lt;strong&gt;last&lt;/strong&gt; — config entries win. So define one &lt;code&gt;calendar &amp;lt;name&amp;gt; = dark blue, &#39;&#39;, &#39;&#39;&lt;/code&gt; entry per calendar to remap its color to an ANSI name that tracks the terminal palette live. Month-view day numbers and event-list rows share these &lt;code&gt;calendar &amp;lt;name&amp;gt;&lt;/code&gt; attributes, which means both stay color-coded per calendar &lt;em&gt;and&lt;/em&gt; readable in both modes. The attribute names must match the &lt;em&gt;discovered&lt;/em&gt; calendar names — check &lt;code&gt;khal printcalendars&lt;/code&gt;, since &lt;code&gt;type = discover&lt;/code&gt; setups often append suffixes (&lt;code&gt;personal&lt;/code&gt; becomes &lt;code&gt;personal1&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Two refinements round off the month view: &lt;code&gt;multiple_on_overflow = True&lt;/code&gt; renders days with events from exactly two calendars as half-and-half two-color cells, and the de-emphasized &lt;code&gt;weeknumber_right&lt;/code&gt;/&lt;code&gt;frame&lt;/code&gt; (dark gray) plus the &lt;code&gt;dark magenta&lt;/code&gt; month column give the calendar a color hierarchy instead of uniform cyan.&lt;/p&gt;
&lt;p&gt;If you wonder whether there are ready-made color tables for exactly this: khal ships two built-in themes (&lt;code&gt;dark&lt;/code&gt; and &lt;code&gt;light&lt;/code&gt; in &lt;code&gt;khal/ui/colors.py&lt;/code&gt;), which &lt;code&gt;[view] theme&lt;/code&gt; selects and our &lt;code&gt;[palette]&lt;/code&gt; section refines. They are worth reading as a reference for which attribute does what, but they assume a terminal with pure black/white defaults rather than a theme-switched palette — that is why this setup overrides them with semantic ANSI values. Two lessons from the built-ins are baked into the palette above: &lt;code&gt;calendar focus&lt;/code&gt; stays at &lt;code&gt;&#39;&#39;, &#39;&#39;, &#39;&#39;&lt;/code&gt; (khal’s own default — any color there washes over &lt;strong&gt;every&lt;/strong&gt; plain day whenever the calendar column holds focus), and structural accents like &lt;code&gt;date header&lt;/code&gt; follow the built-ins’ use of &lt;code&gt;light red&lt;/code&gt;, which stays distinct from all per-calendar accent colors.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Alternative: uniform background blocks.&lt;/strong&gt; If you prefer one clearly visible block over per-calendar colors, set &lt;code&gt;[highlight_days] color&lt;/code&gt; to any non-empty value (for example &lt;code&gt;dark gray&lt;/code&gt;) and override the generated attribute with &lt;code&gt;highlight_days_color = white, dark gray, &#39;&#39;&lt;/code&gt; in &lt;code&gt;[palette]&lt;/code&gt;. Every event day then renders as white on slate (&lt;code&gt;#6272a4&lt;/code&gt;) in Dracula and cream on dark slate (&lt;code&gt;#002b36&lt;/code&gt;) in Solarized Light — distinct from the &lt;code&gt;today&lt;/code&gt; block in both modes. Note that this drops the per-calendar distinction in the month view; the shared-attribute coupling means truly per-calendar &lt;em&gt;background&lt;/em&gt; blocks would also turn every event-list row into a colored block.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All overrides use only ANSI color names, so they repaint live with the OSC palette switch — no ikhal restart needed beyond the usual one-time migration.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;&#39;&#39;&lt;/code&gt; for empty/default foreground, background, or mono fields. &lt;code&gt;default&lt;/code&gt; is not a valid &lt;code&gt;khal&lt;/code&gt; palette color name and will make &lt;code&gt;khal&lt;/code&gt; reject the config. Existing &lt;code&gt;ikhal&lt;/code&gt; sessions that loaded an older HEX palette need one restart; after that the hook’s OSC palette update plus &lt;code&gt;SIGWINCH&lt;/code&gt; redraw is enough for normal mode switches.&lt;/p&gt;
&lt;h3 id=&quot;jellyfin-tui&quot;&gt;jellyfin-tui&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;jellyfin-tui&lt;/code&gt; has two separate pieces of theme state:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.config/jellyfin-tui/config.yaml&lt;/code&gt; contains the custom theme definitions and is watched by the running app.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.local/share/jellyfin-tui/preferences/*.json&lt;/code&gt; stores the selected theme name and is best treated as a next-start setting.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That means the reliable live strategy is &lt;strong&gt;not&lt;/strong&gt; to switch between two selected theme names. Keep the selected theme stable, for example &lt;code&gt;Mode Switcher&lt;/code&gt;, and let the hooks rewrite that theme’s colors in &lt;code&gt;config.yaml&lt;/code&gt;. The running app will then repaint from its config watcher, while the preferences file only needs to stay pointed at the stable theme name.&lt;/p&gt;
&lt;p&gt;Create a starting theme in &lt;code&gt;~/.config/jellyfin-tui/config.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;auto_color&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;themes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Mode Switcher&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  base&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Dark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  background&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#282a36&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  foreground&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#f8f8f2&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  foreground_secondary&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#d7d8e8&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  foreground_dim&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#a7abc4&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  foreground_disabled&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#6f758f&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  section_title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#bd93f9&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  accent&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#8be9fd&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  border&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#4f5268&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  border_focused&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#bd93f9&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  selected_active_background&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#44475a&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  selected_active_foreground&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#f8f8f2&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  selected_inactive_background&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#343746&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  selected_inactive_foreground&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#f8f8f2&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  scrollbar_thumb&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#c6c8d6&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  scrollbar_track&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#44475a&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  progress_fill&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#ffb86c&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  progress_track&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#44475a&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  tab_active_foreground&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#bd93f9&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  tab_inactive_foreground&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#7b819d&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  album_header_background&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#343746&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  album_header_foreground&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;#8be9fd&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Select that theme once in every existing preference file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; pref&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/share/jellyfin-tui/preferences/*.json&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.theme = &amp;quot;Mode Switcher&amp;quot;&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /tmp/jellyfin-tui-pref.json&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /tmp/jellyfin-tui-pref.json &amp;quot;&lt;/span&gt;&lt;span&gt;$pref&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The hook examples above use &lt;code&gt;ruby&lt;/code&gt; to update YAML without string surgery. They also update the legacy names &lt;code&gt;Dracula High Contrast&lt;/code&gt; and &lt;code&gt;Solarized Light High Contrast&lt;/code&gt; to the same current palette, which helps during migration if a running instance still has one of those names loaded in memory. If the app is currently on a built-in theme, select &lt;code&gt;Mode Switcher&lt;/code&gt; once in the app or restart it once; after that, mode changes can be picked up from &lt;code&gt;config.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;sonicradio&quot;&gt;sonicradio&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sonicradio&lt;/code&gt; is a Bubble Tea/Lipgloss application with built-in themes stored as numeric IDs in &lt;code&gt;~/.config/sonicRadio/config.json&lt;/code&gt;. A look at its &lt;code&gt;ui/theme.go&lt;/code&gt; reveals the right strategy: &lt;strong&gt;every theme ships a separate dark and light color profile&lt;/strong&gt;, and the app picks the profile from the terminal background at startup. So instead of switching theme IDs per mode, set one constant theme whose two profiles are both high-contrast — in the tested setup ID 4 (“Mono Yellow”: near-black text and an amber selection bar on light terminals, amber-on-dark in dark mode):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;jq&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.theme = 4&amp;#39; ~/.config/sonicRadio/config.json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /tmp/sonicradio.json&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; mv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /tmp/sonicradio.json ~/.config/sonicRadio/config.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The constant value has a second benefit: sonicradio persists its config on exit, which would overwrite a per-mode value — a constant one survives. The duo-tone themes (IDs 0–3) are poor choices here: their pale selection backgrounds (for example lavender &lt;code&gt;#D4DAF7&lt;/code&gt;) almost disappear on a light terminal. A live terminal switch still leaves a running instance on the old profile (pale dark-profile text on a now-light background); restart it once after toggling.&lt;/p&gt;
&lt;h3 id=&quot;dunst&quot;&gt;Dunst&lt;/h3&gt;
&lt;p&gt;Dunst is not affected by GTK, Qt, or the XDG color-scheme portal. It reads &lt;code&gt;~/.config/dunst/dunstrc&lt;/code&gt;, so the hook should update only the color keys you actually want to switch and then reload the running daemon:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/dunst/dunstrc global frame_color &amp;#39;&amp;quot;#005f87&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/dunst/dunstrc global separator_color &amp;#39;&amp;quot;#93a1a1&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/dunst/dunstrc global format &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;span foreground=&amp;#39;#073642&amp;#39;&amp;gt;&amp;lt;b&amp;gt;%s %p&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\\\\&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;n%b&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/dunst/dunstrc urgency_normal background &amp;#39;&amp;quot;#fdf6e3&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;set_ini_key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/dunst/dunstrc urgency_normal foreground &amp;#39;&amp;quot;#073642&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dunstctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reload ~/.config/dunst/dunstrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The double escaping before &lt;code&gt;n&lt;/code&gt; is intentional: the file should contain a literal &lt;code&gt;\n&lt;/code&gt; inside the quoted Dunst format string, not a physical newline that breaks the next config line.&lt;/p&gt;
&lt;h3 id=&quot;vscodium&quot;&gt;VSCodium&lt;/h3&gt;
&lt;p&gt;VSCodium (like VS Code) ships with &lt;strong&gt;Solarized Light&lt;/strong&gt; and &lt;strong&gt;Solarized Dark&lt;/strong&gt; as built-in themes — no extension required. Dracula, however, must be installed separately:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;codium&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --install-extension&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dracula-theme.theme-dracula&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The hook scripts already set the correct theme name via &lt;code&gt;jq&lt;/code&gt;. If your VSCodium uses a different binary name (e.g., &lt;code&gt;vscodium&lt;/code&gt;), adjust the command accordingly.&lt;/p&gt;
&lt;h3 id=&quot;claude-code&quot;&gt;Claude Code&lt;/h3&gt;
&lt;p&gt;Claude Code renders its terminal UI with truecolor values from its own &lt;code&gt;theme&lt;/code&gt; setting and ignores the terminal’s ANSI palette entirely — on a light terminal with the app still on &lt;code&gt;&quot;theme&quot;: &quot;dark&quot;&lt;/code&gt;, dim text and diff views become nearly invisible. The hooks patch &lt;code&gt;~/.claude/settings.json&lt;/code&gt; (&lt;code&gt;.theme = &quot;dark&quot;&lt;/code&gt; / &lt;code&gt;&quot;light&quot;&lt;/code&gt;) via &lt;code&gt;jq&lt;/code&gt;. New sessions pick the matching theme up automatically; already running sessions keep their theme until restarted or changed in-session via &lt;code&gt;/config&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;nheko&quot;&gt;nheko&lt;/h3&gt;
&lt;p&gt;nheko needs three insights at once, all confirmed against &lt;code&gt;src/ui/Theme.cpp&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Do not use &lt;code&gt;theme=light&lt;/code&gt; if you expect a fully light window.&lt;/strong&gt; nheko’s built-in light theme &lt;em&gt;hardcodes a dark Element-style sidebar&lt;/em&gt; (&lt;code&gt;sidebarBackground = #233649&lt;/code&gt;) — the dark rail and scrollbar tones you might mistake for dark-mode leftovers are upstream design. Only &lt;code&gt;theme=system&lt;/code&gt; derives &lt;code&gt;sidebarBackground&lt;/code&gt; and the scrollbars from the Qt palette (&lt;code&gt;p.window().color()&lt;/code&gt;), which qt6ct supplies correctly per mode. So the hooks keep &lt;code&gt;theme=system&lt;/code&gt; and rely on a complete qt5ct/qt6ct color scheme.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A live palette switch always leaves a running instance mixed&lt;/strong&gt; — parts of the QML UI cache their colors. A restart is unavoidable, so the hooks do it automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nheko persists its in-memory settings on exit&lt;/strong&gt;, just like &lt;code&gt;jellyfin-tui&lt;/code&gt;: quitting it right after a config write restores the old value. The only reliable order is: stop the running instance, wait until it has saved and quit, write the config, start it fresh — exactly what the hook block does. A nheko that was not running is left closed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The cost is a brief reconnect of the Matrix client per mode switch; remove the restart part of the block if you prefer switching nheko manually. Two traps follow from the restart itself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hooks run inside &lt;code&gt;darkman.service&lt;/code&gt;, which does not see &lt;code&gt;~/.xprofile&lt;/code&gt; — without the &lt;code&gt;QT_QPA_PLATFORMTHEME&lt;/code&gt; export from the hook header, a hook-restarted nheko silently skips qt6ct and renders with unthemed Qt defaults.&lt;/li&gt;
&lt;li&gt;A restarted app is a &lt;strong&gt;new window&lt;/strong&gt;, and i3 places new windows on the currently focused workspace — the old position died with the old window. The root-level fix is i3’s own session-restore mechanism: &lt;code&gt;restart_app_in_place&lt;/code&gt; (defined with the other hook helpers) appends a placeholder container with swallow criteria to the app’s old workspace via &lt;code&gt;append_layout&lt;/code&gt;, and i3 materializes the next matching window directly inside it — on whatever workspace the app happened to live, with no capture-and-move-back scripting. Two implementation notes: i3 returns &lt;code&gt;success&lt;/code&gt; even when a criteria matches nothing (scripted post-hoc moves fail &lt;em&gt;silently&lt;/em&gt;), and a watchdog removes the placeholder if the app fails to come back. If you instead keep an app on one fixed workspace anyway, a declarative &lt;code&gt;assign [class=&quot;...&quot;] number N&lt;/code&gt; rule is the simpler alternative.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;gtk-and-qt&quot;&gt;GTK and Qt&lt;/h3&gt;
&lt;p&gt;GTK Dracula via AUR (&lt;code&gt;yay -S dracula-gtk-theme&lt;/code&gt;); Adwaita is shipped by default. Qt color schemes: see &lt;a href=&quot;https://criticalbasics.xyz/posts/i3-dark-light-mode-switcher/#step-3-prepare-qt-apps-keepassxc-nheko&quot;&gt;Step 3&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;neovim&quot;&gt;Neovim&lt;/h3&gt;
&lt;p&gt;The hook scripts manage &lt;code&gt;~/.config/nvim/colorscheme.vim&lt;/code&gt;. This only has an effect if your Neovim config sources that file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ~&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt;/.config/&lt;/span&gt;&lt;span&gt;nvim/&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;colorscheme&lt;/span&gt;&lt;span&gt;.vim&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create theme-specific files, for example:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/dracula/nvim-colorscheme.vim&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;set background=dark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;colorscheme dracula&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/themes/solarized-light/nvim-colorscheme.vim&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;set background=light&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;colorscheme solarized&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adjust the &lt;code&gt;colorscheme&lt;/code&gt; names to match the plugins actually installed in your Neovim setup.&lt;/p&gt;
&lt;h3 id=&quot;reference-table&quot;&gt;Reference table&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;App&lt;/th&gt;&lt;th&gt;File&lt;/th&gt;&lt;th&gt;Source&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;GTK&lt;/td&gt;&lt;td&gt;Theme via AUR/Pacman&lt;/td&gt;&lt;td&gt;&lt;code&gt;dracula-gtk-theme&lt;/code&gt;, Adwaita is default&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Xresources/urxvt&lt;/td&gt;&lt;td&gt;&lt;code&gt;Xresources&lt;/code&gt;&lt;/td&gt;&lt;td&gt;local flat files aligned with the Alacritty palettes (Step 10)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Alacritty&lt;/td&gt;&lt;td&gt;&lt;code&gt;alacritty.toml&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;dracula/alacritty&lt;/code&gt;, &lt;code&gt;alacritty/alacritty-theme&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;i3&lt;/td&gt;&lt;td&gt;&lt;code&gt;i3-theme.conf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;inlined examples in Step 4&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Polybar&lt;/td&gt;&lt;td&gt;&lt;code&gt;polybar.ini&lt;/code&gt; → &lt;code&gt;~/.config/polybar/colors.ini&lt;/code&gt;&lt;/td&gt;&lt;td&gt;inlined examples in Step 5&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rofi&lt;/td&gt;&lt;td&gt;&lt;code&gt;rofi.rasi&lt;/code&gt; → &lt;code&gt;~/.config/rofi/theme.rasi&lt;/code&gt;&lt;/td&gt;&lt;td&gt;local &lt;code&gt;.rasi&lt;/code&gt; files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;neomutt&lt;/td&gt;&lt;td&gt;&lt;code&gt;mutt-colors&lt;/code&gt;&lt;/td&gt;&lt;td&gt;local semantic 16-color palette&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;khal / ikhal&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/khal/config&lt;/code&gt;&lt;/td&gt;&lt;td&gt;local semantic ANSI palette&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;jellyfin-tui&lt;/td&gt;&lt;td&gt;&lt;code&gt;config.yaml&lt;/code&gt;, preferences JSON&lt;/td&gt;&lt;td&gt;live-reloaded custom &lt;code&gt;Mode Switcher&lt;/code&gt; theme&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sonicradio&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/sonicRadio/config.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;built-in numeric themes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Dunst&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/dunst/dunstrc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;local color keys, reload via &lt;code&gt;dunstctl reload&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;KeePassXC&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/keepassxc/keepassxc.ini&lt;/code&gt;&lt;/td&gt;&lt;td&gt;set app theme to Automatic&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;VSCodium&lt;/td&gt;&lt;td&gt;built-in / Extension&lt;/td&gt;&lt;td&gt;Solarized built-in, “Dracula Official” via marketplace&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Claude Code&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.claude/settings.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;built-in &lt;code&gt;dark&lt;/code&gt;/&lt;code&gt;light&lt;/code&gt; truecolor themes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;nheko&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/nheko/nheko.conf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;built-in themes via &lt;code&gt;[user] theme&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qt5ct/qt6ct&lt;/td&gt;&lt;td&gt;&lt;code&gt;*.conf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;dracula/qt5&lt;/code&gt;, Solarized via qt5ct GUI&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;You can find Dracula themes collected at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://draculatheme.com&quot;&gt;https://draculatheme.com&lt;/a&gt; – Solarized at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://ethanschoonover.com/solarized&quot;&gt;https://ethanschoonover.com/solarized&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;caveats-and-honest-expectations&quot;&gt;Caveats and Honest Expectations&lt;/h2&gt;
&lt;p&gt;What &lt;strong&gt;switches live&lt;/strong&gt; (without restart):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alacritty (with &lt;code&gt;live_config_reload = true&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;i3 (after &lt;code&gt;reload&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Polybar (after restart)&lt;/li&gt;
&lt;li&gt;Rofi on the next menu invocation, because Rofi reads &lt;code&gt;theme.rasi&lt;/code&gt; at startup&lt;/li&gt;
&lt;li&gt;VSCodium (mostly, via file watcher on settings.json)&lt;/li&gt;
&lt;li&gt;KeePassXC if &lt;strong&gt;View → Theme → Automatic&lt;/strong&gt; is selected&lt;/li&gt;
&lt;li&gt;Dunst notifications after the hook updates &lt;code&gt;dunstrc&lt;/code&gt; and runs &lt;code&gt;dunstctl reload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jellyfin-tui&lt;/code&gt;, if it is already using the stable &lt;code&gt;Mode Switcher&lt;/code&gt; custom theme; the hooks rewrite that theme in &lt;code&gt;config.yaml&lt;/code&gt;, which the app watches.&lt;/li&gt;
&lt;li&gt;NeoMutt and ikhal after they have loaded the semantic ANSI palette once; the hook changes the terminal’s 16-color palette and sends &lt;code&gt;SIGWINCH&lt;/code&gt; for redraw.&lt;/li&gt;
&lt;li&gt;The XDG portal color-scheme value consumed by portal-aware apps&lt;/li&gt;
&lt;li&gt;Terminal foreground/background/cursor nudges for running urxvt/Alacritty windows via OSC sequences&lt;/li&gt;
&lt;li&gt;Tray applet icons, because the hooks restart the applets (&lt;code&gt;nm-applet&lt;/code&gt;, &lt;code&gt;pasystray&lt;/code&gt;, &lt;code&gt;flameshot&lt;/code&gt;) with the freshly switched GTK icon theme&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What &lt;strong&gt;requires an app restart&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Firefox/Thunderbird chrome can require a restart even when the portal signal itself updates live. Web content using &lt;code&gt;prefers-color-scheme&lt;/code&gt; is usually more likely to follow than the full browser UI.&lt;/li&gt;
&lt;li&gt;Generic GTK apps in plain i3 setups, such as Thunar, may read the new theme only on next start unless an XSettings/settings daemon propagates changes.&lt;/li&gt;
&lt;li&gt;nheko and other Qt apps that keep their own in-memory palette. The hooks handle nheko by restarting it automatically (stop, wait for its settings write-back on exit, keep &lt;code&gt;theme=system&lt;/code&gt;, start fresh) — note that nheko’s built-in light theme deliberately uses a dark sidebar, so &lt;code&gt;theme=system&lt;/code&gt; plus a complete qt6ct palette is the only fully light/dark-consistent configuration.&lt;/li&gt;
&lt;li&gt;Claude Code: the hooks switch its truecolor theme in &lt;code&gt;~/.claude/settings.json&lt;/code&gt;; new sessions match automatically, running sessions keep the old theme until restart or an in-session &lt;code&gt;/config&lt;/code&gt; change.&lt;/li&gt;
&lt;li&gt;GIMP, LibreOffice (own theme logic)&lt;/li&gt;
&lt;li&gt;urxvt terminals still do not fully reload arbitrary Xresources live. The included PTS escape-sequence trick updates running urxvt Background/Foreground/Cursor and the 16-color ANSI palette, but font/resource changes and app-internal colors still require a restart or app-level reload.&lt;/li&gt;
&lt;li&gt;Terminal apps with their own theme state, such as sonicradio, usually need restart or an app-internal theme change. &lt;code&gt;jellyfin-tui&lt;/code&gt; is the exception when the stable &lt;code&gt;Mode Switcher&lt;/code&gt; strategy above is used; NeoMutt and ikhal are the exception when the semantic ANSI palette strategy above is used.&lt;/li&gt;
&lt;li&gt;Bubble Tea/Lipgloss/termenv apps can briefly use the old AdaptiveColor branch after a live terminal theme change. The Alacritty OSC nudge reduces this, but a running TUI can still repaint one step late.&lt;/li&gt;
&lt;li&gt;Chromium (flags file takes effect on start)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What &lt;strong&gt;needs to be configured manually&lt;/strong&gt; within the app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LibreOffice: set Light/Dark once in &lt;code&gt;Tools → Options → Application Colors&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;GIMP: has its own theme system under &lt;code&gt;Preferences → Theme&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;KeePassXC: set &lt;code&gt;View → Theme → Automatic&lt;/code&gt; once; hardcoded &lt;code&gt;dark&lt;/code&gt; or &lt;code&gt;light&lt;/code&gt; overrides the portal&lt;/li&gt;
&lt;li&gt;Inkscape: follows GTK, but restart required&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;tips&quot;&gt;Tips&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Geo-based Auto-Switching:&lt;/strong&gt; &lt;code&gt;darkman&lt;/code&gt; can do this automatically based on sunrise/sunset – see Step 9.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugging:&lt;/strong&gt; &lt;code&gt;journalctl --user -u darkman.service -f&lt;/code&gt; shows if hooks are being executed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manual Hook Testing:&lt;/strong&gt; Execute &lt;code&gt;~/.local/share/dark-mode.d/apply-theme&lt;/code&gt; directly to see errors in isolation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terminal OSC Nudges:&lt;/strong&gt; The hook enables targeted urxvt and Alacritty PTS recoloring plus OSC 4 ANSI-palette updates by default. Set &lt;code&gt;RECOLOR_URXVT_PTS=0&lt;/code&gt; or &lt;code&gt;RECOLOR_ALACRITTY_PTS=0&lt;/code&gt; when running the hook if you want to disable these partial live updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency Across Multiple Machines:&lt;/strong&gt; Version &lt;code&gt;~/.config/themes/&lt;/code&gt;, &lt;code&gt;~/.local/share/dark-mode.d/&lt;/code&gt;, &lt;code&gt;~/.local/share/light-mode.d/&lt;/code&gt;, and &lt;code&gt;~/.config/qt5ct/colors/&lt;/code&gt; in your dotfiles repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;extension-ideas&quot;&gt;Extension Ideas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;base16-Framework&lt;/strong&gt; instead of Dracula/Solarized: Generate a unified scheme for hundreds of apps from a single palette (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/chriskempson/base16&quot;&gt;https://github.com/chriskempson/base16&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-Workspace-Themes&lt;/strong&gt;: Theoretically possible via i3-IPC, but rarely practical.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Polybar Module&lt;/strong&gt; with current theme status as an indicator.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;The implemented architecture is:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;darkman (Trigger + Portal + Persistence)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── Hooks → GTK, Qt, Xresources, App Configs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── Live-Reload: i3, Polybar, Alacritty, XDG portal signal, VSCodium&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── Accepted: Some apps require restart&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You switch with &lt;code&gt;$mod+Shift+d&lt;/code&gt;. Most apps react immediately, some require a restart – this is the current state of Linux desktop reality, not a flaw in your setup.&lt;/p&gt;
&lt;p&gt;When setting up for the first time, it’s worthwhile to follow the phased strategy from the beginning of the tutorial: first the basics (GTK config, XDG portal, i3, Alacritty), then extensions, and finally the “problem children.” This way, you can more easily identify the cause of problems if they arise.&lt;/p&gt;
&lt;a href=&quot;https://wiki.archlinux.org/title/Dark_mode_theme_switching&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ARCH WIKI: DARK MODE THEME SWITCHING&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://gitlab.com/WhyNotHugo/darkman&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;💻&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;DARKMAN PROJECT ON GITLAB&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Server Security Audit Script for Debian/Ubuntu</title>
          <pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/server-security-audit-script/</link>
          <guid>https://criticalbasics.xyz/posts/server-security-audit-script/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/server-security-audit-script/">&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-05-04&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Full audit script with comprehensive explanations.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;introduction-to-the-server-security-audit-script&quot;&gt;Introduction to the Server Security Audit Script&lt;/h2&gt;
&lt;p&gt;When you provision a new server, especially in a cloud environment using tools like cloud-init, it’s crucial to verify that all intended security measures have been correctly applied. Manual checks can be time-consuming and error-prone. This Bash script automates a significant portion of this auditing process, providing a quick overview of your server’s security posture on Debian or Ubuntu-based systems.&lt;/p&gt;
&lt;p&gt;This script is designed to be run with root privileges and will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Check System Fundamentals:&lt;/strong&gt; Hostname, timezone, kernel, pending updates, and reboot status.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit User &amp;amp; Authentication:&lt;/strong&gt; Verify the existence and &lt;code&gt;sudo&lt;/code&gt; privileges of a dedicated admin user, check root password status, and identify accounts with UID 0 or empty passwords.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Harden SSH:&lt;/strong&gt; Scrutinize your SSH daemon’s configuration for best practices like disabled root login, password authentication, X11 forwarding, and the use of strong key algorithms. It also checks for the presence of SSH keys for your admin user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Firewall Configuration (UFW):&lt;/strong&gt; Confirm UFW’s active status, default policies, specific rule sets (e.g., rate-limiting for SSH), and log redirection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intrusion Prevention (Fail2Ban):&lt;/strong&gt; Validate that Fail2Ban is running, its SSH jail is active, and it’s monitoring the correct SSH port.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Updates:&lt;/strong&gt; Ensure &lt;code&gt;unattended-upgrades&lt;/code&gt; is installed and configured to keep your system patched.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker Security:&lt;/strong&gt; If Docker is installed, it checks daemon status, Docker Compose presence, user group membership, and critically, Docker’s log rotation settings and network configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log Rotation:&lt;/strong&gt; Verify persistent journaling and &lt;code&gt;logrotate&lt;/code&gt; configurations for Traefik and UFW logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network &amp;amp; Open Ports:&lt;/strong&gt; List actively listening ports and check for known insecure legacy services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filesystem Security:&lt;/strong&gt; Scan for world-writable files in critical directories and report disk usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end, it provides a summary of &lt;code&gt;PASS&lt;/code&gt;, &lt;code&gt;WARN&lt;/code&gt;, and &lt;code&gt;FAIL&lt;/code&gt; counts, giving you an immediate understanding of areas needing attention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why is this important?&lt;/strong&gt;
Even with cloud-init or automated provisioning, misconfigurations can occur. This script acts as your second line of defense, ensuring that your server adheres to a baseline of security best practices before it goes into production.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;how-to-use-the-script&quot;&gt;How to Use the Script&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Save the script:&lt;/strong&gt; Copy the entire script content into a file, for example, &lt;code&gt;server-audit.sh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make it executable:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +x server-audit.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run with &lt;code&gt;sudo&lt;/code&gt;:&lt;/strong&gt; The script requires root privileges to access system configurations and logs.&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./server-audit.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review the output:&lt;/strong&gt; Pay close attention to &lt;code&gt;[FAIL]&lt;/code&gt; and &lt;code&gt;[WARN]&lt;/code&gt; messages, which indicate potential security vulnerabilities or areas for improvement.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;the-server-security-audit-script&quot;&gt;The Server Security Audit Script&lt;/h2&gt;
&lt;p&gt;Here is the complete script. You can customize the &lt;code&gt;ADMIN_USER&lt;/code&gt; variable at the beginning to match your dedicated administrative username.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Server Security Audit Script&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Checks if the cloud-init setup has been correctly applied and if current&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# security standards are met.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Usage: sudo bash server-audit.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Colors &amp;amp; Symbols --------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GREEN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;\033[0;32m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RED&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;\033[0;31m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;YELLOW&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;\033[0;33m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CYAN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;\033[0;36m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;\033[1m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;\033[0m&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PASS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;GREEN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}PASS${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FAIL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;RED&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}FAIL${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WARN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;YELLOW&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}WARN${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;${&lt;/span&gt;&lt;span&gt;CYAN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}INFO${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pass_count&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fail_count&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;warn_count&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_pass&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  [${&lt;/span&gt;&lt;span&gt;PASS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}]  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;; ((pass_count&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_fail&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  [${&lt;/span&gt;&lt;span&gt;FAIL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}]  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;; ((fail_count&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_warn&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  [${&lt;/span&gt;&lt;span&gt;WARN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}]  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;; ((warn_count&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_info&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  [${&lt;/span&gt;&lt;span&gt;INFO&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}]  &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;\n${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}=== &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ===${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Root Check --------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[ $EUID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -ne&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;RED&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}This script must be run with sudo.${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;delightfuldude&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # &amp;lt;--- CUSTOMIZE THIS TO YOUR ADMIN USERNAME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;============================================================&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  Server Security Audit - $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;+%Y-%m-%d %H:%M:%S&amp;#39;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;============================================================&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. SYSTEM FUNDAMENTALS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;1. System Fundamentals&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Hostname&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CURRENT_HOSTNAME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hostnamectl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --static&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; hostname&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$CURRENT_HOSTNAME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$CURRENT_HOSTNAME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Hostname set: ${&lt;/span&gt;&lt;span&gt;CURRENT_HOSTNAME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Hostname is still on default&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Timezone&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CURRENT_TZ&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;timedatectl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; show&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Timezone&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --value&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cat&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/timezone&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unknown&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$CURRENT_TZ&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Europe/Berlin&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Timezone: ${&lt;/span&gt;&lt;span&gt;CURRENT_TZ&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Timezone is ${&lt;/span&gt;&lt;span&gt;CURRENT_TZ&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} (expected: Europe/Berlin)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Kernel &amp;amp; OS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;OS: $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; PRETTY_NAME /etc/os-release&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d= -f2&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;quot;&amp;#39;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Kernel: $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;uname&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Uptime&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Uptime: $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;uptime&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Pending Updates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UPDATES&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;apt&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; list&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --upgradable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; upgradable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$UPDATES&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No pending package updates&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;UPDATES&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} package update(s) available&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Reboot required?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /var/run/reboot-required ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;System reboot required&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No reboot required&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. USER &amp;amp; AUTHENTICATION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2. User &amp;amp; Authentication&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Admin user exists&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;User &amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; exists&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;User &amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; does NOT exist&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# sudo group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; groups&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -qw&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sudo&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; is in the sudo group&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; is NOT in the sudo group&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# NOPASSWD in sudoers (accepted for cloud-init without password)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;NOPASSWD&amp;quot; /etc/sudoers /etc/sudoers.d/&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^#&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; has NOPASSWD (intended, as cloud-init doesn&amp;#39;t set a password)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No NOPASSWD for &amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; - sudo requires password&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Root password (should be locked or random, not empty)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ROOT_PW_STATUS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;passwd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ROOT_PW_STATUS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt;    L&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Root account is locked&amp;quot;&lt;/span&gt;&lt;span&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt;    P&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Root has a password set (randomized by cloud-init)&amp;quot;&lt;/span&gt;&lt;span&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt;    NP&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Root has NO password!&amp;quot;&lt;/span&gt;&lt;span&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    *)&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Root password status: ${&lt;/span&gt;&lt;span&gt;ROOT_PW_STATUS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;esac&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Accounts with empty password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EMPTY_PW&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;awk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -F:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;($2 == &amp;quot;&amp;quot; ) { print $1 }&amp;#39; /etc/shadow&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$EMPTY_PW&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No accounts with empty password&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Accounts with empty password: ${&lt;/span&gt;&lt;span&gt;EMPTY_PW&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# UID-0 accounts (only root should have UID 0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ROOT_ACCOUNTS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;awk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -F:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;($3 == 0) { print $1 }&amp;#39; /etc/passwd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ROOT_ACCOUNTS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;root&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Only &amp;#39;root&amp;#39; has UID 0&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Multiple accounts with UID 0: ${&lt;/span&gt;&lt;span&gt;ROOT_ACCOUNTS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. SSH HARDENING&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;3. SSH Hardening&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Read effective SSH configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sshd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Cannot read SSH configuration (sshd -T failed)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Port&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^port &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;22&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH port changed: ${&lt;/span&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH is running on default port 22&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Root Login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ROOT_LOGIN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^permitrootlogin &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ROOT_LOGIN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;no&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Root login disabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Root login is &amp;#39;${&lt;/span&gt;&lt;span&gt;ROOT_LOGIN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; (should be &amp;#39;no&amp;#39;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Password Auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    PW_AUTH&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^passwordauthentication &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$PW_AUTH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;no&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Password authentication disabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Password authentication is enabled!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Pubkey Auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    PUBKEY_AUTH&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^pubkeyauthentication &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$PUBKEY_AUTH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;yes&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Public-key authentication enabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Public-key authentication is disabled!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # MaxAuthTries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MAX_AUTH&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^maxauthtries &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$MAX_AUTH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -le&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;MaxAuthTries: ${&lt;/span&gt;&lt;span&gt;MAX_AUTH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;MaxAuthTries is ${&lt;/span&gt;&lt;span&gt;MAX_AUTH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} (recommended: &amp;lt;=3)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # LoginGraceTime&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GRACE_TIME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^logingracetime &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$GRACE_TIME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -le&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 60&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;LoginGraceTime: ${&lt;/span&gt;&lt;span&gt;GRACE_TIME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}s&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;LoginGraceTime is ${&lt;/span&gt;&lt;span&gt;GRACE_TIME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}s (recommended: &amp;lt;=60)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # X11Forwarding&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    X11&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^x11forwarding &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$X11&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;no&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;X11Forwarding disabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;X11Forwarding is enabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # TCP Forwarding&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TCP_FWD&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^allowtcpforwarding &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$TCP_FWD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;no&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;TCP-Forwarding disabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;TCP-Forwarding is enabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Agent Forwarding&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AGENT_FWD&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^allowagentforwarding &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$AGENT_FWD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;no&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Agent-Forwarding disabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Agent-Forwarding is enabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # AllowUsers set&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ALLOW_USERS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^allowusers &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{$1=&amp;quot;&amp;quot;; print $0}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; xargs&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ALLOW_USERS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;AllowUsers restricted to: ${&lt;/span&gt;&lt;span&gt;ALLOW_USERS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;AllowUsers is not set (all users can use SSH)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Check if insecure Key Algorithms are accepted&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ACCEPTED_ALGOS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSHD_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^pubkeyacceptedalgorithms &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{$1=&amp;quot;&amp;quot;; print $0}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; xargs&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ACCEPTED_ALGOS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ACCEPTED_ALGOS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -qw&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;ssh-rsa&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;ssh-rsa (SHA-1) is still allowed - use rsa-sha2-* only!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Only modern Key Algorithms allowed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Allowed Algorithms: ${&lt;/span&gt;&lt;span&gt;ACCEPTED_ALGOS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;PubkeyAcceptedAlgorithms: System Default (SHA-1 blocked since OpenSSH 8.8)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# SSH Key present for Admin User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ADMIN_HOME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;eval&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; echo ~&amp;quot;&lt;/span&gt;&lt;span&gt;$ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;ADMIN_HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/.ssh/authorized_keys&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    KEY_COUNT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^ssh-&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;ADMIN_HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/.ssh/authorized_keys&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$KEY_COUNT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -gt&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;KEY_COUNT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} SSH key(s) stored for &amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; line&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            KEY_TYPE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$line&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            KEY_COMMENT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$line&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $3}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            KEY_BITS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh-keygen&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -l -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/stdin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$line&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  Key: ${&lt;/span&gt;&lt;span&gt;KEY_TYPE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} ${&lt;/span&gt;&lt;span&gt;KEY_BITS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;?} bit (${&lt;/span&gt;&lt;span&gt;KEY_COMMENT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;no comment&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;})&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        done &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^ssh-&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;ADMIN_HOME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/.ssh/authorized_keys&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No SSH keys in authorized_keys!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No authorized_keys file for &amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39;!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SSH_VERSION&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -V&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH Version: ${&lt;/span&gt;&lt;span&gt;SSH_VERSION&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 4. FIREWALL (UFW)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;4. Firewall (UFW)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# SSH_PORT for later use (if sshd -T failed)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;${SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;8496}&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Fallback to a common custom port&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    UFW_STATUS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ufw&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$UFW_STATUS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Status: active&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;UFW is active&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Default Policies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        UFW_VERBOSE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ufw&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status verbose&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$UFW_VERBOSE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;deny (incoming)&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default policy incoming: deny&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default policy incoming is NOT deny!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$UFW_VERBOSE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;allow (outgoing)&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default policy outgoing: allow&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default policy outgoing is not &amp;#39;allow&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # List open ports&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Active rules:&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        ufw&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status numbered&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^\[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; | while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rule&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;         ${&lt;/span&gt;&lt;span&gt;rule&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # SSH port with rate-limit?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$UFW_STATUS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}.*LIMIT&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH port ${&lt;/span&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} has Rate-Limiting&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        elif&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$UFW_STATUS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH port ${&lt;/span&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} is open, but WITHOUT Rate-Limiting&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH port ${&lt;/span&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} is not explicitly in UFW&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;UFW is NOT active&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # UFW Logging Redirect (VNC Console fix)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /etc/rsyslog.d/20-ufw.conf ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;UFW logs are redirected to /var/log/ufw.log (console remains clean)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;UFW logs not redirected - VNC console will be flooded with [UFW BLOCK]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;UFW is not installed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 5. FAIL2BAN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;5. Fail2Ban&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fail2ban-client&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; is-active&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fail2ban&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Fail2Ban is running&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # SSH Jail active?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; fail2ban-client&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status sshd&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH Jail is active&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            F2B_STATUS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fail2ban-client&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status sshd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            BANNED&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$F2B_STATUS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Currently banned&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $NF}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            TOTAL_BANNED&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$F2B_STATUS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Total banned&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $NF}&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Currently banned: ${&lt;/span&gt;&lt;span&gt;BANNED&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}, Total banned: ${&lt;/span&gt;&lt;span&gt;TOTAL_BANNED&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SSH Jail is NOT active&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Check configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        F2B_PORT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^port&amp;quot; /etc/fail2ban/jail.local&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $NF}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$F2B_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Fail2Ban monitors correct SSH port (${&lt;/span&gt;&lt;span&gt;F2B_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;})&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        elif&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$F2B_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Fail2Ban monitors port ${&lt;/span&gt;&lt;span&gt;F2B_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}, SSH runs on ${&lt;/span&gt;&lt;span&gt;SSH_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Fail2Ban is installed, but NOT active&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Fail2Ban is not installed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 6. AUTOMATIC UPDATES&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;6. Automatic Updates&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; dpkg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; unattended-upgrades&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unattended-upgrades is installed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /etc/apt/apt.conf.d/20auto-upgrades ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Unattended-Upgrade &amp;quot;1&amp;quot;&amp;#39; /etc/apt/apt.conf.d/20auto-upgrades&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Automatic upgrades are enabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;20auto-upgrades exists, but upgrades appear disabled&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;20auto-upgrades configuration is missing&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unattended-upgrades is not installed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 7. DOCKER&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;7. Docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker is installed: $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --version&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; is-active&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker daemon is running&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker daemon is not active&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Docker Compose&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose version&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/dev/null;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker Compose: $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose version&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker Compose Plugin not found&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # User in docker group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; groups&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -qw&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; is in the docker group&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;#39;${&lt;/span&gt;&lt;span&gt;ADMIN_USER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;#39; is NOT in the docker group&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Log rotation configured?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /etc/docker/daemon.json ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;max-size&amp;quot; /etc/docker/daemon.json&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker Log rotation configured&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MAX_SIZE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;max-size&amp;quot; /etc/docker/daemon.json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39; &amp;quot;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d: -f2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            MAX_FILE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;max-file&amp;quot; /etc/docker/daemon.json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39; &amp;quot;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d: -f2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;max-size: ${&lt;/span&gt;&lt;span&gt;MAX_SIZE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}, max-file: ${&lt;/span&gt;&lt;span&gt;MAX_FILE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;daemon.json exists, but no Log rotation configured&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No daemon.json - Docker logs can grow indefinitely!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Proxy network&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; network ls&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;proxy&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker network &amp;#39;proxy&amp;#39; exists&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker network &amp;#39;proxy&amp;#39; is missing&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker is not installed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 8. TRAEFIK PREPARATION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;8. Traefik Stack Preparation&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TRAEFIK_DIR&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/opt/containers/traefik-stack&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$TRAEFIK_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Directory ${&lt;/span&gt;&lt;span&gt;TRAEFIK_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} exists&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Subdirectories&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; dir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; traefik/dynamic traefik/logs traefik/certs crowdsec/config crowdsec/data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;TRAEFIK_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/${&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  ${&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/ is present&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  ${&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/ is missing&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # acme.json Permissions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;TRAEFIK_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/traefik/certs/acme.json&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ACME_PERMS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;stat -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;%a&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;TRAEFIK_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/traefik/certs/acme.json&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$ACME_PERMS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;600&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;acme.json has correct permissions (600)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;acme.json has permissions ${&lt;/span&gt;&lt;span&gt;ACME_PERMS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} (should be 600)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;acme.json does not exist yet&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Directory ${&lt;/span&gt;&lt;span&gt;TRAEFIK_DIR&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} is missing&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 9. LOG ROTATION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;9. Log Rotation&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Persistent Journal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -d&lt;/span&gt;&lt;span&gt; /var/log/journal ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Persistent Journal activated&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    JOURNAL_SIZE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --disk-usage&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -oP&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;[\d.]+\w+&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Journal size: ${&lt;/span&gt;&lt;span&gt;JOURNAL_SIZE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;unknown&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Journal is NOT persistent (logs are lost on reboot)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Logrotate: Traefik&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /etc/logrotate.d/traefik ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Logrotate for Traefik configured&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Logrotate for Traefik is missing&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Logrotate: UFW&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /etc/logrotate.d/ufw-custom ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Logrotate for UFW logs configured&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;elif&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /etc/logrotate.d/ufw ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Logrotate for UFW logs configured (system default)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Logrotate for UFW logs is missing - /var/log/ufw.log can grow indefinitely!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Docker Log Rotation (Summary)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span&gt; /etc/docker/daemon.json ]] &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;max-size&amp;quot; /etc/docker/daemon.json&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker Container logs rotated&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Docker Container logs are not rotated&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 10. NETWORK &amp;amp; OPEN PORTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;10. Network &amp;amp; Open Ports&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Listening ports (externally accessible):&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ss&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -tlnp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;127.0.0&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;LISTEN&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; | while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; line&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    PORT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$line&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{print $4}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rev&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d: -f1&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rev&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    PROC&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$line&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -oP&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;users:\(\(&amp;quot;\K[^&amp;quot;]+&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unknown&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;         Port ${&lt;/span&gt;&lt;span&gt;PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} (${&lt;/span&gt;&lt;span&gt;PROC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;})&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check for known insecure services&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INSECURE_FOUND&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;for&lt;/span&gt;&lt;span&gt; svc&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; telnetd rshd rlogind vsftpd proftpd&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; is-active&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --quiet&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$svc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Insecure service running: ${&lt;/span&gt;&lt;span&gt;svc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        INSECURE_FOUND&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$INSECURE_FOUND&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No insecure legacy services active&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 11. FILESYSTEM SECURITY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;11. Filesystem&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# World-writable files in critical directories&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WW_COUNT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc /usr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -xdev -type&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -perm -o+w&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; wc&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -l&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$WW_COUNT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;No world-writable files in /etc and /usr&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;WW_COUNT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} world-writable file(s) in /etc or /usr&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# SUID Binaries (informative)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SUID_COUNT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -xdev -type&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -perm -4000&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; wc&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -l&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;log_info&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;SUID binaries found: ${&lt;/span&gt;&lt;span&gt;SUID_COUNT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} (manual review if needed)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Disk Usage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DISK_USAGE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;df&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;NR==2 {print $5}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;%&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$DISK_USAGE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -lt&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 80&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_pass&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Disk usage: ${&lt;/span&gt;&lt;span&gt;DISK_USAGE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}%&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;elif&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$DISK_USAGE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -lt&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 90&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_warn&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Disk usage: ${&lt;/span&gt;&lt;span&gt;DISK_USAGE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}% (getting low)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    log_fail&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Disk usage: ${&lt;/span&gt;&lt;span&gt;DISK_USAGE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}% (critical!)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# SUMMARY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# =============================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}============================================================${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}  SUMMARY${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}============================================================${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  ${&lt;/span&gt;&lt;span&gt;GREEN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}Passed:${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}   ${&lt;/span&gt;&lt;span&gt;pass_count&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  ${&lt;/span&gt;&lt;span&gt;YELLOW&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}Warnings:${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;} ${&lt;/span&gt;&lt;span&gt;warn_count&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  ${&lt;/span&gt;&lt;span&gt;RED&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}Failed:${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}    ${&lt;/span&gt;&lt;span&gt;fail_count&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}============================================================${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$fail_count&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$warn_count&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;\n${&lt;/span&gt;&lt;span&gt;GREEN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}Excellent! All checks passed.${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;elif&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$fail_count&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;\n${&lt;/span&gt;&lt;span&gt;YELLOW&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}Good - no critical failures, but review warnings.${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;\n${&lt;/span&gt;&lt;span&gt;RED&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}${&lt;/span&gt;&lt;span&gt;BOLD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}Attention - there are critical failures that should be resolved!${&lt;/span&gt;&lt;span&gt;NC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$fail_count&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description>
      </item>
      <item>
          <title>Self-Hosting Plausible Analytics with Docker and Traefik</title>
          <pubDate>Wed, 11 Mar 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/plausible-analytics-selfhosted/</link>
          <guid>https://criticalbasics.xyz/posts/plausible-analytics-selfhosted/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/plausible-analytics-selfhosted/">&lt;p&gt;This guide walks you through deploying a fully self-hosted &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://plausible.io/&quot;&gt;Plausible Analytics&lt;/a&gt; instance. Plausible is a lightweight, privacy-friendly alternative to Google Analytics — it doesn’t use cookies, is fully GDPR-compliant, and respects the privacy of your visitors. By self-hosting it, you retain complete ownership of your data while keeping your analytics costs predictable.&lt;/p&gt;
&lt;p&gt;We use the &lt;strong&gt;official Plausible Community Edition repository&lt;/strong&gt; as the foundation and integrate it with our existing Traefik v3 reverse proxy via a &lt;code&gt;compose.override.yml&lt;/code&gt;. This approach keeps the original &lt;code&gt;compose.yml&lt;/code&gt; untouched, making future updates clean and painless.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-03-11&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide created for self-hosting Plausible CE v3.2.0 behind Traefik v3 with CrowdSec, based on the official repository.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide builds upon a secure Docker environment. Before you begin, you must have a fully functional Traefik v3 and CrowdSec stack.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            HARD REQUIREMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The following steps will not work correctly without the Traefik stack running as described in the prerequisite guide.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik_v3_crowdsec_tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;: This is the foundation for our public-facing reverse proxy and security.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;You will also need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A dedicated subdomain for your Plausible instance (e.g., &lt;code&gt;plausible.your-domain.com&lt;/code&gt;) pointed to your server’s IP address.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git&lt;/code&gt; and the &lt;code&gt;openssl&lt;/code&gt; utility (&lt;code&gt;sudo apt install git openssl&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-clone-the-official-repository&quot;&gt;2. Clone the Official Repository&lt;/h2&gt;
&lt;p&gt;Instead of building our own Docker Compose configuration from scratch, we clone the official Plausible CE repository. It ships with a tested &lt;code&gt;compose.yml&lt;/code&gt; and pre-configured ClickHouse settings (including IPv4-only mode and resource-friendly defaults).&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git clone&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; v3.2.0&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --single-branch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://github.com/plausible/community-edition plausible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The repository contains the following structure:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;plausible/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── clickhouse/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── default-profile-low-resources-overrides.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── ipv4-only.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── logs.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── low-resources.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── LICENSE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── README.md&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHY NOT A CUSTOM COMPOSE FILE?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The official &lt;code&gt;compose.yml&lt;/code&gt; includes battle-tested ClickHouse configuration, proper healthchecks, and sensible defaults. Building a custom Compose file from scratch is error-prone and makes updates harder. Instead, we use a &lt;code&gt;compose.override.yml&lt;/code&gt; to add only our Traefik-specific configuration — Docker Compose merges both files automatically.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;3-configuration&quot;&gt;3. Configuration&lt;/h2&gt;
&lt;p&gt;We only need to create two files: an &lt;code&gt;.env&lt;/code&gt; file with your settings and a &lt;code&gt;compose.override.yml&lt;/code&gt; for Traefik integration.&lt;/p&gt;
&lt;h3 id=&quot;3-1-generate-secrets&quot;&gt;3.1. Generate Secrets&lt;/h3&gt;
&lt;p&gt;Plausible requires a secret key base for signing tokens and a TOTP vault key for two-factor authentication.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Generate the secret key base (at least 64 bytes)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SECRET_KEY_BASE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -base64 48&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Your Secret Key Base is: &lt;/span&gt;&lt;span&gt;$SECRET_KEY_BASE&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Generate the TOTP vault key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOTP_VAULT_KEY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -base64 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Your TOTP Vault Key is: &lt;/span&gt;&lt;span&gt;$TOTP_VAULT_KEY&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            SAVE THESE SECRETS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Copy these generated values into a temporary text file. You will need to paste them into the &lt;code&gt;.env&lt;/code&gt; file in the next step.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-2-environment-configuration-env&quot;&gt;3.2. Environment Configuration (&lt;code&gt;.env&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This single file holds all your instance-specific settings. Create it in the repository root:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Required Settings ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Replace with your actual domain, including https://&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;BASE_URL=https://plausible.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Paste the secret key base generated in step 3.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;SECRET_KEY_BASE=PASTE-YOUR-SECRET-KEY-BASE-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Paste the TOTP vault key generated in step 3.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;TOTP_VAULT_KEY=PASTE-YOUR-TOTP-VAULT-KEY-HERE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Registration ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# &amp;quot;invite_only&amp;quot; = only you can invite users. &amp;quot;true&amp;quot; = no new signups at all.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Remove this line entirely to allow open registration.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;DISABLE_REGISTRATION=invite_only&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Email / SMTP (Optional but recommended) ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Without SMTP, features like password resets and weekly reports will not work.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# The &amp;quot;From:&amp;quot; address shown in emails sent by Plausible.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Use your SMTP login address or an alias your mail server accepts.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;MAILER_EMAIL=plausible@your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Your SMTP server address, e.g. smtp.mailbox.org or mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;SMTP_HOST_ADDR=your-mail-server.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Your SMTP port: typically 587 (STARTTLS) or 465 (SSL)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;SMTP_HOST_PORT=587&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Your SMTP username — usually your full email address&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;SMTP_USER_NAME=your-smtp-username&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Your SMTP password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;SMTP_USER_PWD=your-smtp-password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Set to &amp;quot;true&amp;quot; only if your port is 465 (implicit SSL). For port 587, keep &amp;quot;false&amp;quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;SMTP_HOST_SSL_ENABLED=false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            BASE_URL MUST BE CORRECT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;BASE_URL&lt;/code&gt; must match your public URL exactly, including &lt;code&gt;https://&lt;/code&gt;. A mismatch will cause tracking scripts to fail and break the dashboard.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            REGISTRATION POLICY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;DISABLE_REGISTRATION=invite_only&lt;/code&gt; setting means that only you (the admin) can invite new users. This is the recommended setting for personal instances. Set it to &lt;code&gt;true&lt;/code&gt; to completely disable new signups, or remove the line entirely to allow open registration.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-3-traefik-integration-compose-override-yml&quot;&gt;3.3. Traefik Integration (&lt;code&gt;compose.override.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;This file adds the Traefik labels and network connection to the Plausible service. Docker Compose merges it automatically with the official &lt;code&gt;compose.yml&lt;/code&gt; — no need to modify the original file.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose.override.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  plausible:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Replace plausible.your-domain.com with your actual domain.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # This tells Traefik which incoming requests to route to this container.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.plausible.rule=Host(`plausible.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.plausible.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.plausible.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.plausible.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.plausible.loadbalancer.server.port=8000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHY DOES THE DOMAIN APPEAR TWICE?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;&lt;code&gt;BASE_URL&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; tells &lt;strong&gt;Plausible&lt;/strong&gt; which URL it runs under — for generating correct links, cookies, and tracking scripts. The Traefik &lt;code&gt;Host()&lt;/code&gt; label in &lt;code&gt;compose.override.yml&lt;/code&gt; tells &lt;strong&gt;Traefik&lt;/strong&gt; which incoming requests to route to the Plausible container. These are two independent systems that don’t read each other’s configuration, so both need the domain separately.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-4-update-configuration-with-your-values&quot;&gt;3.4. Update Configuration with Your Values&lt;/h3&gt;
&lt;p&gt;Replace all placeholders in the two files you just created. Every value that needs your input is marked with inline comments.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Domain Name:&lt;/strong&gt; In &lt;code&gt;.env&lt;/code&gt; (&lt;code&gt;BASE_URL&lt;/code&gt;) and &lt;code&gt;compose.override.yml&lt;/code&gt; (Traefik &lt;code&gt;Host&lt;/code&gt; label), replace &lt;code&gt;plausible.your-domain.com&lt;/code&gt; with your actual domain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secrets:&lt;/strong&gt; In &lt;code&gt;.env&lt;/code&gt;, paste the &lt;code&gt;SECRET_KEY_BASE&lt;/code&gt; and &lt;code&gt;TOTP_VAULT_KEY&lt;/code&gt; you generated in step 3.1.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email Settings:&lt;/strong&gt; In &lt;code&gt;.env&lt;/code&gt;, update the SMTP section with your mail server details. Each field has an inline comment explaining what to enter.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;4-launch-the-stack&quot;&gt;4. Launch the Stack&lt;/h2&gt;
&lt;p&gt;With both files in place, start the stack:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# From within the /opt/containers/plausible directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first launch will take a few minutes as Docker pulls the images and Plausible runs its initial database migrations. You can monitor the progress with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose logs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Press &lt;code&gt;CTRL+C&lt;/code&gt; to exit the logs view once all services are stable. You should see Plausible report that it is ready.&lt;/p&gt;
&lt;h2 id=&quot;5-verify-the-installation&quot;&gt;5. Verify the Installation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check Running Containers:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ps&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --format&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;{{.Names}}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see three containers running: &lt;code&gt;plausible-plausible-1&lt;/code&gt;, &lt;code&gt;plausible-plausible_db-1&lt;/code&gt; (PostgreSQL), and &lt;code&gt;plausible-plausible_events_db-1&lt;/code&gt; (ClickHouse).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access the Dashboard:&lt;/strong&gt;
Open a web browser and navigate to &lt;code&gt;https://plausible.your-domain.com&lt;/code&gt;. You should see the Plausible registration page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create Your Admin Account:&lt;/strong&gt;
Register with your email address and a strong password. Since we set &lt;code&gt;DISABLE_REGISTRATION=invite_only&lt;/code&gt;, this first account becomes the admin. All future registrations will require an invitation from you.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            EMAIL VERIFICATION WITHOUT SMTP
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If you skipped the SMTP configuration, you can manually verify your email address by running:
&lt;code&gt;sudo docker compose exec plausible_db psql -U postgres -h localhost -d plausible_db -c &quot;UPDATE users SET email_verified = true;&quot;&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;6-add-plausible-to-your-website&quot;&gt;6. Add Plausible to Your Website&lt;/h2&gt;
&lt;p&gt;After logging in and creating your first site in the dashboard, Plausible will provide a tracking snippet. Starting with v3, Plausible generates a &lt;strong&gt;dynamic, site-specific script&lt;/strong&gt; for each site you add. Simply copy the snippet from the site settings and add it to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of your website.&lt;/p&gt;
&lt;p&gt;For a Zola-based site, add the provided snippet to your &lt;code&gt;templates/base.html&lt;/code&gt; (or equivalent template). It will look something like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;lt;!-- Replace both domains: plausible.your-domain.com = your Plausible instance, your-website.com = the site you want to track --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; defer src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;https://plausible.your-domain.com/js/script.js&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; data-domain&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;your-website.com&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            NEW DYNAMIC SNIPPET IN V3
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Plausible v3 introduced a new, more configurable tracking snippet that is specific to each site. Legacy &lt;code&gt;script.js&lt;/code&gt; snippets from older versions will continue to work, but new sites will receive the dynamic format. You can configure tracking options (outbound links, file downloads, tagged events, etc.) directly in the site settings without changing the script URL.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;7-maintenance&quot;&gt;7. Maintenance&lt;/h2&gt;
&lt;h3 id=&quot;updating-plausible&quot;&gt;Updating Plausible&lt;/h3&gt;
&lt;p&gt;Since we cloned the official repository, updating involves fetching the new version tag and restarting. Your &lt;code&gt;compose.override.yml&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; remain untouched.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/plausible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Fetch the latest tags from the repository&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git fetch&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --tags&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check out the new version (replace v3.x.x with the actual new version tag)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git checkout v3.x.x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Re-apply your override (it&amp;#39;s preserved — just verify it&amp;#39;s still there)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose.override.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Pull the new images and restart&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --remove-orphans&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            CHECK RELEASE NOTES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Always consult the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/plausible/analytics/releases&quot;&gt;official Plausible release notes&lt;/a&gt; before updating. Major version upgrades may require changes to your &lt;code&gt;.env&lt;/code&gt; or introduce new configuration options.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;backing-up&quot;&gt;Backing Up&lt;/h3&gt;
&lt;p&gt;A complete backup consists of the PostgreSQL database (user data, site settings) and the ClickHouse database (analytics events). Since the official setup uses Docker named volumes, we back up via the running containers.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# From your /opt/containers/plausible directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. Back up the PostgreSQL database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_db pg_dump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_db&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gzip&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_pg_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.sql.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Back up the ClickHouse data via a temporary Alpine container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_event-data:/data&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -v&lt;/span&gt;&lt;span&gt; $(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;pwd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;:/backup&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  alpine tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -czvf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /backup/plausible_clickhouse_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.tar.gz&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /data .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Backup complete.&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            BACKUP STRATEGY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;For a production instance, consider automating this with a cron job. The PostgreSQL dump can run against the live database without stopping services. For ClickHouse, a file-level backup of the named volume is sufficient for smaller instances.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;restoring-from-backup&quot;&gt;Restoring from Backup&lt;/h3&gt;
&lt;p&gt;To restore your instance from a backup:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/plausible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. Stop the main application&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose stop plausible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Restore PostgreSQL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gunzip&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_pg_backup_YYYY-MM-DD.sql.gz&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_db psql&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. Restore ClickHouse (stop ClickHouse first)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose stop plausible_events_db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; plausible_event-data:/data&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  -v&lt;/span&gt;&lt;span&gt; $(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;pwd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;:/backup&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  alpine sh&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;rm -rf /data/* &amp;amp;&amp;amp; tar -xzvf /backup/plausible_clickhouse_backup_YYYY-MM-DD.tar.gz -C /data&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose start plausible_events_db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 4. Start everything&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose start plausible&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now have a fully self-hosted, privacy-respecting analytics platform running behind your secure Traefik and CrowdSec stack. By using the official Plausible CE repository as a foundation and adding only a lightweight &lt;code&gt;compose.override.yml&lt;/code&gt; for Traefik, your setup is easy to maintain and update — closely following the upstream project without custom workarounds.&lt;/p&gt;
&lt;p&gt;Plausible gives you all the essential web analytics insights — page views, referrers, locations, devices — without compromising your visitors’ privacy or relying on third-party services. Your data stays on your server, under your control.&lt;/p&gt;
&lt;a href=&quot;https://plausible.io/docs/self-hosting&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;PLAUSIBLE SELF-HOSTING DOCS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/plausible/community-edition&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;PLAUSIBLE CE ON GITHUB&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Git &amp; GitHub for Beginners: Navigating the Version Control Labyrinth</title>
          <pubDate>Sat, 07 Feb 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/git-tutorial-cheatsheet/</link>
          <guid>https://criticalbasics.xyz/posts/git-tutorial-cheatsheet/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/git-tutorial-cheatsheet/">&lt;p&gt;Welcome, intrepid coder, to the world of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;! This guide cuts through the noise to give you a solid understanding of version control, focusing on the practical steps and common pitfalls encountered in daily development. We’ll demystify local Git versus online platforms, walk through essential commands, and tackle the ever-present authentication headaches with solutions drawn from real-world scenarios.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-02-07&lt;/td&gt;&lt;td&gt;Initial Version: Guide created for beginners with practical tips, authentication troubleshooting, and common workflow patterns.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;1-git-vs-github-a-tale-of-two-systems&quot;&gt;1. Git vs. GitHub: A Tale of Two Systems&lt;/h1&gt;
&lt;p&gt;Understanding the distinction between &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt; (the tool) and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; (the service) is foundational.&lt;/p&gt;
&lt;h3 id=&quot;local-git&quot;&gt;Local Git&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt; is a &lt;strong&gt;version control system&lt;/strong&gt; that lives on your computer. It meticulously tracks the history of your project as a series of &lt;strong&gt;commits&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repository (Repo)&lt;/strong&gt;: This is your project folder, distinguished by a hidden &lt;code&gt;.git/&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commit&lt;/strong&gt;: A “snapshot” of your changes at a specific point in time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Branch&lt;/strong&gt;: An independent line of development (e.g., &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;feature/my-new-thing&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote&lt;/strong&gt;: A counterpart of your local repository hosted on a server (e.g., &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;github-com&quot;&gt;GitHub.com&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; is a &lt;strong&gt;hosting service&lt;/strong&gt; built around Git repositories. It offers a suite of tools for collaborative development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stores repositories online (publicly or privately).&lt;/li&gt;
&lt;li&gt;Facilitates collaboration through Pull Requests, Issues, and Code Reviews.&lt;/li&gt;
&lt;li&gt;Provides Continuous Integration/Continuous Deployment (CI/CD) with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Can host container images and packages (e.g., &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry&quot;&gt;GitHub Container Registry (GHCR)&lt;/a&gt;: &lt;code&gt;ghcr.io/...&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            KEY TAKEAWAY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Git can function entirely without GitHub. GitHub &lt;em&gt;enhances&lt;/em&gt; Git by providing cloud hosting and robust collaboration features.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;2-open-source-alternatives-to-github&quot;&gt;2. Open-Source Alternatives to GitHub&lt;/h1&gt;
&lt;p&gt;If you prefer self-hosting or exploring other platforms, these are excellent alternatives that all speak the same Git language:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://about.gitlab.com/&quot;&gt;GitLab CE/EE&lt;/a&gt;&lt;/strong&gt;: GitLab Community Edition is fully open-source, offering a comprehensive suite of DevOps tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://gitea.io/&quot;&gt;Gitea&lt;/a&gt;&lt;/strong&gt;: A lightweight, self-hostable Git service, popular for its ease of deployment and minimal resource footprint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt;&lt;/strong&gt;: A community-driven fork of Gitea, focused on open governance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://sourcehut.org/&quot;&gt;SourceHut&lt;/a&gt;&lt;/strong&gt;: A minimalist, “Git-first” development platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            UNIVERSAL COMMANDS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Regardless of the platform, your local Git commands remain almost identical. This is the power of Git!&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;3-the-typical-workflow-six-key-concepts-visualized&quot;&gt;3. The Typical Workflow: Six Key Concepts &amp;amp; Visualized&lt;/h1&gt;
&lt;p&gt;To master Git, grasp these six core areas, and visualize their flow.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Working Tree&lt;/strong&gt;: The actual files in your project directory, including any uncommitted changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Staging Area / Index&lt;/strong&gt;: A temporary area where you select which changes will be included in your &lt;em&gt;next&lt;/em&gt; commit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commit History&lt;/strong&gt;: The chronological record of all your project’s commits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Branch&lt;/strong&gt;: The current line of development you are working on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote &lt;code&gt;origin&lt;/code&gt;&lt;/strong&gt;: The URL pointing to your online repository (often called &lt;code&gt;origin&lt;/code&gt; by default).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Push/Pull&lt;/strong&gt;: The actions of sending (pushing) or receiving (pulling) changes between your local repository and the remote.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;visualizing-the-workflow&quot;&gt;Visualizing the Workflow&lt;/h3&gt;
&lt;p&gt;A simple mental model helps understand the core Git flow:&lt;/p&gt;
&lt;pre style=&quot;font-family: &#39;Perfect DOS VGA 437&#39;, monospace; 
            line-height: 1.0; 
            color: #e0e0e0; 
            background-color: #121212; 
            padding: 15px; 
            border: 1px solid #666666; 
            overflow: auto; 
            white-space: pre; 
            font-size: 14px;&quot;&gt;
Working Directory (Your files)
        ↓ (`git add`)
Staging Area (Index)
        ↓ (`git commit`)
Local Repository (Commit history)
        ↓ (`git push`)
Remote Repository ([GitHub](https://github.com/), [GitLab](https://about.gitlab.com/), etc.)
        ↓ (`git pull`)
(Back to Working Directory for others)
&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;4-initial-setup-a-clean-start&quot;&gt;4. Initial Setup: A Clean Start&lt;/h1&gt;
&lt;p&gt;Setting up Git correctly from the beginning prevents many headaches.&lt;/p&gt;
&lt;h3 id=&quot;4-1-set-your-git-identity-for-commits&quot;&gt;4.1. Set Your Git Identity (For Commits)&lt;/h3&gt;
&lt;p&gt;These details define the &lt;strong&gt;author&lt;/strong&gt; of your commits; they are &lt;em&gt;not&lt;/em&gt; your login credentials for GitHub. The &lt;code&gt;user.name&lt;/code&gt; and &lt;code&gt;user.email&lt;/code&gt; you set here are what will appear in the commit history on platforms like GitHub.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.name &amp;quot;Your Name&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.email &amp;quot;your-email@example.com&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;how-to-check-your-current-git-identity&quot;&gt;How to Check Your Current Git Identity&lt;/h4&gt;
&lt;p&gt;To see what &lt;code&gt;user.name&lt;/code&gt; and &lt;code&gt;user.email&lt;/code&gt; are currently set for your active repository or globally:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For the current repository:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config user.name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config user.email&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Globally (for all repositories):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.email&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;how-to-change-your-git-identity&quot;&gt;How to Change Your Git Identity&lt;/h4&gt;
&lt;p&gt;To change your Git identity:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Globally (recommended for most users, applies to all new repos):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.name &amp;quot;Your New Name&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.email &amp;quot;your-new-email@domain.tld&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;For only the current repository (overrides global settings for this repo):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config user.name &amp;quot;Project Specific Name&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config user.email &amp;quot;project-email@domain.tld&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            EXISTING COMMITS RETAIN THEIR AUTHOR
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Changing these settings only affects &lt;strong&gt;future commits&lt;/strong&gt;. Commits you have already made will retain the &lt;code&gt;user.name&lt;/code&gt; and &lt;code&gt;user.email&lt;/code&gt; that were active at the time of their creation. Rewriting history for already-pushed commits is possible but complex and generally not recommended for beginners.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;4-2-initialize-or-clone-a-repository&quot;&gt;4.2. Initialize or Clone a Repository&lt;/h3&gt;
&lt;p&gt;There are two main ways to start:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clone an existing repository&lt;/strong&gt;: This is standard for team projects or contributing to open source.&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Using HTTPS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone https://github.com/ORG/REPO.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Using SSH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone git@github.com:ORG/REPO.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Initialize a brand-new project&lt;/strong&gt;: If you’re starting a project from scratch on your local machine.&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my-new-project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my-new-project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;You can then connect it to a remote repository later once you create one online.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-3-check-your-remotes&quot;&gt;4.3. Check Your Remotes&lt;/h3&gt;
&lt;p&gt;Confirm the remote repository is correctly configured:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; remote&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;5-essential-commands-your-daily-toolkit&quot;&gt;5. Essential Commands: Your Daily Toolkit&lt;/h1&gt;
&lt;p&gt;Here are the most frequently used Git commands and their purposes.&lt;/p&gt;
&lt;h3 id=&quot;status-overview&quot;&gt;Status &amp;amp; Overview&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; log&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --oneline --decorate -n 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; diff&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;stage-files-prepare-for-commit&quot;&gt;Stage Files (Prepare for Commit)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Or stage specific files:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add path/to/file&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;create-a-commit&quot;&gt;Create a Commit&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Brief, descriptive message&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;push-pull-explained&quot;&gt;Push / Pull Explained&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git push&lt;/code&gt;: Sends your local commits to the remote repository.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git pull&lt;/code&gt;: &lt;strong&gt;Fetches&lt;/strong&gt; changes from the remote &lt;em&gt;and then&lt;/em&gt; &lt;strong&gt;merges&lt;/strong&gt; them into your current local branch.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pull&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # = git fetch + git merge&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            AVOID ACCIDENTAL MERGE COMMITS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;For a cleaner history, especially when working on a personal branch, consider using &lt;code&gt;git pull --rebase&lt;/code&gt;. This fetches remote changes and then re-applies your local commits &lt;em&gt;on top&lt;/em&gt; of them, avoiding an explicit merge commit.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;branching-typical-workflow&quot;&gt;Branching (Typical Workflow)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; checkout&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; feature/my-new-feature&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; origin feature/my-new-feature&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;mini-example-your-first-commit&quot;&gt;Mini-Example: Your First Commit!&lt;/h3&gt;
&lt;p&gt;Let’s try a complete cycle:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. Create a new directory and initialize Git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my-first-repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my-first-repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Create a file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Hello, Git World!&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. Check status (it&amp;#39;s untracked)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 4. Stage the file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 5. Check status again (it&amp;#39;s staged)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 6. Commit the file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Add initial homepage with Hello World&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 7. Check log (see your commit)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; log&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --oneline&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# At this point, you&amp;#39;d typically connect to a remote and push.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For now, you have a local commit!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;6-ignoring-files-with-gitignore&quot;&gt;6. Ignoring Files with &lt;code&gt;.gitignore&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Not every file belongs in your repository. Temporary files, build artifacts, and sensitive data should be ignored.&lt;/p&gt;
&lt;h3 id=&quot;why-is-node-modules-or-target-in-my-git&quot;&gt;Why is &lt;code&gt;node_modules&lt;/code&gt; (or &lt;code&gt;target/&lt;/code&gt;) in my Git?!&lt;/h3&gt;
&lt;p&gt;This is a common beginner question. Files generated by your build system (like &lt;code&gt;node_modules&lt;/code&gt; for JavaScript or &lt;code&gt;target/&lt;/code&gt; for Rust) should &lt;em&gt;not&lt;/em&gt; be committed. They bloat your repository and cause unnecessary merge conflicts.&lt;/p&gt;
&lt;h3 id=&quot;how-to-use-gitignore&quot;&gt;How to Use &lt;code&gt;.gitignore&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Create a file named &lt;code&gt;.gitignore&lt;/code&gt; in the root of your repository and list the files or directories you want Git to ignore.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Example .gitignore content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Node.js dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;node_modules/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Logs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;/span&gt;&lt;span&gt;.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;npm-debug.log*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;yarn-debug.log*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;yarn-error.log*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# OS generated files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;.DS_Store&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;.env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Build artifacts (e.g., for Rust)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;target/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Your application&amp;#39;s local settings (if applicable)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;config/local.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# To create and add to .gitignore:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;node_modules/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .gitignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;*.log&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .gitignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add .gitignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Add .gitignore to exclude common temporary files&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            EFFECTIVE .GITIGNORE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Make sure &lt;code&gt;.gitignore&lt;/code&gt; is committed &lt;em&gt;before&lt;/em&gt; you add any files that should be ignored. If files are already tracked, adding them to &lt;code&gt;.gitignore&lt;/code&gt; won’t untrack them. You’d need &lt;code&gt;git rm --cached &amp;lt;file&amp;gt;&lt;/code&gt; first.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;7-crucial-context-accounts-vs-repository-permissions&quot;&gt;7. Crucial Context: Accounts vs. Repository Permissions&lt;/h1&gt;
&lt;p&gt;This is where many newcomers (and even seasoned pros) stumble.&lt;/p&gt;
&lt;h3 id=&quot;github-account-personal-vs-company-organization-repository&quot;&gt;GitHub Account (Personal) vs. Company/Organization Repository&lt;/h3&gt;
&lt;p&gt;On GitHub, repositories are often owned by an &lt;strong&gt;Organization&lt;/strong&gt; (e.g., &lt;code&gt;DELIGHTFUL-corp/my-project&lt;/code&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You log in with a &lt;strong&gt;GitHub User Account&lt;/strong&gt; (which might be your personal one).&lt;/li&gt;
&lt;li&gt;This user account needs &lt;strong&gt;permissions&lt;/strong&gt; (e.g., &lt;code&gt;WRITE&lt;/code&gt;, &lt;code&gt;MAINTAIN&lt;/code&gt;, &lt;code&gt;ADMIN&lt;/code&gt;) within the Organization’s repository.&lt;/li&gt;
&lt;li&gt;Without sufficient permissions, you might be able to read the repository but not push changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;common-pitfall-the-identity-crisis&quot;&gt;Common Pitfall: The Identity Crisis&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            THE STEALTHY &#39;REPOSITORY NOT FOUND&#39; ERROR
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;A classic issue: you’re logged into GitHub in your browser with Account A, but Git on your command line is using cached credentials from Account B. This often results in “repository not found” errors for private repos even when you believe you have access.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Your &lt;code&gt;git push&lt;/code&gt; fails, even though you “know” you have access to the repository. The error message is often misleading (&lt;code&gt;fatal: repository &#39;https://github.com/ORG/REPO.git/&#39; not found&lt;/code&gt;) rather than an explicit “permission denied.” GitHub frequently returns a &lt;strong&gt;404&lt;/strong&gt; (“not found”) for private repositories when permissions are lacking, to avoid leaking the existence of private repos.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;8-authentication-https-vs-ssh-and-why-your-error-happened&quot;&gt;8. Authentication: HTTPS vs. SSH (And Why Your Error Happened)&lt;/h1&gt;
&lt;p&gt;Authentication methods can be a source of confusion.&lt;/p&gt;
&lt;h3 id=&quot;https-token-credentials&quot;&gt;HTTPS (Token/Credentials)&lt;/h3&gt;
&lt;p&gt;With HTTPS, Git requires authentication details. While passwords were used in the past, today it’s almost always:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens&quot;&gt;Personal Access Token (PAT)&lt;/a&gt;&lt;/strong&gt;, or&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://cli.github.com/&quot;&gt;GitHub CLI&lt;/a&gt; (&lt;code&gt;gh&lt;/code&gt;)&lt;/strong&gt; managing a token for you automatically. The GitHub CLI is an &lt;strong&gt;optional but highly recommended&lt;/strong&gt; tool for smoother authentication workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;installing-github-cli&quot;&gt;Installing GitHub CLI&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Debian/Ubuntu:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install gh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Arch Linux:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; github-cli&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Your specific stumbling block was classic:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gh repo view ... viewerPermission&lt;/code&gt; correctly showed &lt;code&gt;ADMIN&lt;/code&gt; (meaning permissions were there).&lt;/li&gt;
&lt;li&gt;But &lt;code&gt;git ls-remote origin HEAD&lt;/code&gt; reported &lt;code&gt;Repository not found&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This often happens when Git uses &lt;strong&gt;incorrect or cached credentials&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-fix-from-your-real-world-case&quot;&gt;The Fix (from your real-world case)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; auth login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; auth setup-git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sequence ensures that Git is configured to use the credentials managed by the GitHub CLI for &lt;code&gt;https://github.com/...&lt;/code&gt; remotes.&lt;/p&gt;
&lt;h3 id=&quot;ssh-keys&quot;&gt;SSH (Keys)&lt;/h3&gt;
&lt;p&gt;SSH is often more “set it and forget it” once correctly configured:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You add an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh&quot;&gt;SSH public key&lt;/a&gt; to your GitHub account.&lt;/li&gt;
&lt;li&gt;Your remote URL will look like &lt;code&gt;git@github.com:ORG/REPO.git&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;SSH authentication is handled by your SSH agent, not Git’s credential storage. This setup avoids credential helper conflicts, making it robust for many users.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;9-troubleshooting-checklist-when-git-push-acts-up&quot;&gt;9. Troubleshooting Checklist: When &lt;code&gt;git push&lt;/code&gt; Acts Up&lt;/h1&gt;
&lt;p&gt;If &lt;code&gt;git push&lt;/code&gt; fails, go through this checklist.&lt;/p&gt;
&lt;h3 id=&quot;9-1-is-the-remote-correct&quot;&gt;9.1. Is the Remote Correct?&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; remote&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9-2-can-you-even-see-the-repository-authenticating-access&quot;&gt;9.2. Can You Even “See” the Repository? (Authenticating Access)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ls-remote origin HEAD&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If this command fails with “repository not found” or “authentication failed,” the issue is almost certainly &lt;strong&gt;authentication, the remote URL, or your permissions&lt;/strong&gt;. This is the first diagnostic step for “git push repository not found” problems.&lt;/p&gt;
&lt;h3 id=&quot;9-3-which-github-identity-is-active-gh-cli&quot;&gt;9.3. Which GitHub Identity is Active (GH CLI)?&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; auth status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9-4-what-permissions-do-you-have&quot;&gt;9.4. What Permissions Do You Have?&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; repo view ORG/REPO&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --json&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; viewerPermission&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9-5-if-https-credentials-are-stuck-re-link&quot;&gt;9.5. If HTTPS Credentials are Stuck: Re-link&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; auth setup-git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9-6-clear-cached-credentials-if-necessary&quot;&gt;9.6. Clear Cached Credentials (If Necessary)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;protocol=https\nhost=github.com\n\n&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; credential reject&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;10-your-minimal-daily-workflow&quot;&gt;10. Your Minimal Daily Workflow&lt;/h1&gt;
&lt;p&gt;Once authentication is set up correctly (as it should be now), your daily routine is simple:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. Start by pulling any remote changes (optional, but good practice)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Check what you&amp;#39;ve modified&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. Stage your changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; add .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 4. Commit your changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Description of your changes&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 5. Push your changes to the remote repository&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;11-practical-rules-keeping-it-clean-long-term&quot;&gt;11. Practical Rules: Keeping it Clean Long-Term&lt;/h1&gt;
&lt;p&gt;Adhere to these rules for a smoother Git experience.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One Identity Per Purpose&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;GitHub Account (login) = Access &amp;amp; Permissions.&lt;/li&gt;
&lt;li&gt;Git &lt;code&gt;user.name&lt;/code&gt;/&lt;code&gt;user.email&lt;/code&gt; = Commit Author (can be your company identity).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For Private/Org Repos&lt;/strong&gt;: Always ensure your GitHub user is explicitly part of the Organization’s team with the necessary permissions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When Switching Accounts&lt;/strong&gt;: After changing GitHub accounts (e.g., personal to work), always run &lt;code&gt;gh auth status&lt;/code&gt; and potentially &lt;code&gt;gh auth setup-git&lt;/code&gt; again. This is key to resolving “git authentication failed” issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When it says “Repository not found”&lt;/strong&gt;: First, check &lt;code&gt;git ls-remote origin HEAD&lt;/code&gt;. If that fails, it’s time to check your credentials and active account. This specific error often means your authentication is failing for “github 404 private repository” scenarios.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;12-managing-multiple-git-identities-e-g-work-vs-personal&quot;&gt;12. Managing Multiple Git Identities (e.g., Work vs. Personal)&lt;/h1&gt;
&lt;p&gt;It’s common to work on different projects that require different Git identities (e.g., a work email/name for company projects and a personal one for open-source contributions). Git offers flexible ways to manage this.&lt;/p&gt;
&lt;p&gt;Git applies configurations in a specific order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Repository-specific (&lt;code&gt;.git/config&lt;/code&gt;):&lt;/strong&gt; These settings override all others for the current repository.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global (&lt;code&gt;~/.gitconfig&lt;/code&gt;):&lt;/strong&gt; These settings apply to all repositories that don’t have their own specific configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System-wide (&lt;code&gt;$(prefix)/etc/gitconfig&lt;/code&gt;):&lt;/strong&gt; Least specific, rarely modified directly.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;option-a-simple-set-identity-per-repository&quot;&gt;Option A (Simple): Set Identity Per Repository&lt;/h3&gt;
&lt;p&gt;The easiest way to use different identities is to set them directly within each project’s folder. This overrides your global settings only for that specific repository.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Set your default global identity&lt;/strong&gt; (e.g., your personal one, or the one you use most often):&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.name &amp;quot;Your Default Name&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.email &amp;quot;your-default@mail.tld&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigate to a specific project folder&lt;/strong&gt; (e.g., a work project).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set the identity for &lt;em&gt;only this repository&lt;/em&gt;:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config user.name &amp;quot;Work Name&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config user.email &amp;quot;work@company.com&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;This creates/modifies the &lt;code&gt;.git/config&lt;/code&gt; file in that repository.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To verify the local settings:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --local&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --local&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; user.email&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;option-b-advanced-conditional-includes-for-directories&quot;&gt;Option B (Advanced): Conditional Includes for Directories&lt;/h3&gt;
&lt;p&gt;If you organize your projects into separate top-level directories (e.g., &lt;code&gt;~/work/company-projects/&lt;/code&gt; and &lt;code&gt;~/personal-projects/&lt;/code&gt;), you can use Git’s &lt;code&gt;includeIf&lt;/code&gt; directive. This automatically applies different configurations based on the path of the repository.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Define your default global identity&lt;/strong&gt; in &lt;code&gt;~/.gitconfig&lt;/code&gt; (e.g., your personal one):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ~/.gitconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[user]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  name&lt;/span&gt;&lt;span&gt; = Dude (Personal)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  email&lt;/span&gt;&lt;span&gt; = dude.personal@mail.tld&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[includeIf &amp;quot;gitdir:~/work/delightful/&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  path&lt;/span&gt;&lt;span&gt; = ~/.gitconfig-delightful&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[includeIf &amp;quot;gitdir:~/personal-projects/&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  path&lt;/span&gt;&lt;span&gt; = ~/.gitconfig-personal&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: The &lt;code&gt;gitdir:&lt;/code&gt; path should end with a &lt;code&gt;/&lt;/code&gt; to indicate a directory. Make sure these paths exist on your system.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create separate configuration files&lt;/strong&gt; for each specific context.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;~/.gitconfig-delightful&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[user]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  name&lt;/span&gt;&lt;span&gt; = DELIGHTFUL Inc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  email&lt;/span&gt;&lt;span&gt; = dude.work@delightful.tld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;~/.gitconfig-personal&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[user]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  name&lt;/span&gt;&lt;span&gt; = Dude (Open Source)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  email&lt;/span&gt;&lt;span&gt; = dude.opensource@mail.tld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, when you enter a repository within &lt;code&gt;~/work/delightful/&lt;/code&gt;, Git will automatically use the &lt;code&gt;DELIGHTFUL Inc.&lt;/code&gt; identity. When you’re in &lt;code&gt;~/personal-projects/&lt;/code&gt;, it will use &lt;code&gt;Dude (Open Source)&lt;/code&gt;. Any other repository will fall back to the default &lt;code&gt;Dude (Personal)&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-if-you-use-multiple-github-accounts-not-just-identities&quot;&gt;What if You Use Multiple GitHub Accounts (not just identities)?&lt;/h3&gt;
&lt;p&gt;If you manage entirely separate GitHub accounts (e.g., &lt;code&gt;github.com/my-personal-account&lt;/code&gt; and &lt;code&gt;github.com/my-work-account&lt;/code&gt;), you’ll also need to configure &lt;strong&gt;separate SSH keys and SSH host aliases&lt;/strong&gt; in your &lt;code&gt;~/.ssh/config&lt;/code&gt; file. This tells Git which SSH key to use when connecting to &lt;code&gt;github.com&lt;/code&gt; for specific projects. This setup is more advanced and beyond the scope of this beginner tutorial, but it’s important to be aware of it.&lt;/p&gt;
&lt;hr size=&quot;2&quot; noshade color=&quot;#666666&quot; style=&quot;margin: 15px 0; border-style: double;&quot;&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You’re now equipped with the knowledge to navigate Git and GitHub with confidence! We’ve covered the fundamentals, delved into the crucial authentication challenges, and provided a clear path to troubleshooting common issues like “git push repository not found.” Understanding how to manage your Git identity, especially across multiple projects, will streamline your workflow significantly. Version control can seem daunting, but with these principles and tools, you’ll be committing and collaborating like a pro in no time.&lt;/p&gt;
&lt;a href=&quot;https://git-scm.com/doc&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL GIT DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://docs.github.com/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;GITHUB DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Self-hosting Immich with Docker, Traefik, and CrowdSec</title>
          <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/immich/</link>
          <guid>https://criticalbasics.xyz/posts/immich/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/immich/">&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://immich.app/&quot;&gt;Immich&lt;/a&gt; is currently the most powerful open-source alternative to Google Photos. It offers high-performance backup, AI-driven face recognition, and a polished mobile app. This guide focuses on a robust deployment using Docker Compose, integrating it into our  &lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;existing Traefik v3 reverse proxy&lt;/a&gt;&lt;/strong&gt; and securing it with the CrowdSec IPS.&lt;/p&gt;
&lt;p&gt;By placing Immich behind Traefik, we benefit from automatic TLS certificates and a central entry point for our mobile devices, while CrowdSec protects our personal memories from brute-force and bot attacks.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-01-15&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Immich v1.12x+, Traefik v3 integration, pgvector, and specific CrowdSec bypass notes for mobile sync.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This deployment assumes you have followed our foundational security stack guide. Immich is resource-intensive, especially during the initial scan of your library.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            HARD REQUIREMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The following steps will not work correctly without the Traefik stack running as described in the prerequisite guide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose&lt;/a&gt;&lt;/strong&gt;: This provides the &lt;code&gt;proxy&lt;/code&gt; network and the &lt;code&gt;crowdsec-bouncer&lt;/code&gt; middleware.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;System Recommendations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RAM:&lt;/strong&gt; Minimum 4GB (8GB+ recommended for AI/Machine Learning).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage:&lt;/strong&gt; A large dedicated disk or mount point for your photo library.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain:&lt;/strong&gt; A subdomain like &lt;code&gt;photos.your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-directory-structure&quot;&gt;2. Directory Structure&lt;/h2&gt;
&lt;p&gt;Immich requires several volumes for its database, machine learning cache, and the actual photo library.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create the main directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/immich&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/immich&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create directories for data persistence&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; volumes/db&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;      # Postgres data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; volumes/library&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Your actual photos/videos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; volumes/model-cache&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # AI models&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-configuration&quot;&gt;3. Configuration&lt;/h2&gt;
&lt;p&gt;Immich uses a &lt;code&gt;.env&lt;/code&gt; file for core settings and a &lt;code&gt;docker-compose.yml&lt;/code&gt; for service orchestration.&lt;/p&gt;
&lt;h3 id=&quot;3-1-generate-database-password&quot;&gt;3.1. Generate Database Password&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DB_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -hex 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Your Immich DB password: &lt;/span&gt;&lt;span&gt;$DB_PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-2-environment-variables-env&quot;&gt;3.2. Environment Variables (&lt;code&gt;.env&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Create the &lt;code&gt;.env&lt;/code&gt; file. Replace placeholders with your values.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Database ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;DB_PASSWORD=&lt;/span&gt;&lt;span&gt;$DB_PASSWORD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;DB_USERNAME=immich&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;DB_DATABASE_NAME=immich&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- System ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;TZ=Europe/Vienna&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;IMMICH_VERSION=release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Library Location ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# Ensure this path has sufficient space (ideally a dedicated disk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;UPLOAD_LOCATION=./volumes/library&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;# --- Domain ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;DOMAIN_NAME=photos.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-3-docker-compose-docker-compose-yml&quot;&gt;3.3. Docker Compose (&lt;code&gt;docker-compose.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  immich-server:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: immich_server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ${UPLOAD_LOCATION}:/usr/src/app/upload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - /etc/localtime:/etc/localtime:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    env_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - redis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - immich-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.immich.rule=Host(`${DOMAIN_NAME}`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.immich.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.immich.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # See Section 4.3 for opting out of CrowdSec if needed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.immich.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.immich.loadbalancer.server.port=2283&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  immich-machine-learning:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: immich_machine_learning&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./volumes/model-cache:/cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    env_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - immich-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  redis:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: immich_redis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: redis:6.2-alpine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - immich-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  database:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: immich_postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: tensorchord/pgvecto-rs:pg16-v0.2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      POSTGRES_PASSWORD: ${DB_PASSWORD}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      POSTGRES_USER: ${DB_USERNAME}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      POSTGRES_DB: ${DB_DATABASE_NAME}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./volumes/db:/var/lib/postgresql/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - immich-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  immich-net:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    driver: bridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;4-hardware-security-tuning&quot;&gt;4. Hardware &amp;amp; Security Tuning&lt;/h2&gt;
&lt;h3 id=&quot;4-1-hardware-acceleration-optional&quot;&gt;4.1. Hardware Acceleration (Optional)&lt;/h3&gt;
&lt;p&gt;Using an iGPU or GPU speeds up video transcoding and AI processing significantly.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            TRANSCODING &amp; ML
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;To enable Intel QuickSync, add the following to both &lt;code&gt;immich-server&lt;/code&gt; (for video) and &lt;code&gt;immich-machine-learning&lt;/code&gt; (for AI) in your &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;devices&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/dri:/dev/dri&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;4-2-mobile-apps-crowdsec&quot;&gt;4.2. Mobile Apps &amp;amp; CrowdSec&lt;/h3&gt;
&lt;p&gt;Immich mobile apps (especially on iOS) perform many rapid requests during background synchronization.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            MOBILE SYNC &amp; FALSE POSITIVES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If you experience “Connection Lost” or sync issues in the mobile app, check your CrowdSec decisions (&lt;code&gt;cscli decisions list&lt;/code&gt;). Frequent background requests can sometimes trigger rate-limiting or bot-detection scenarios.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;4-3-running-immich-without-crowdsec-optional&quot;&gt;4.3. Running Immich without CrowdSec (Optional)&lt;/h3&gt;
&lt;p&gt;If you find that the CrowdSec middleware frequently interferes with your mobile backups, you can choose to bypass it for Immich specifically while keeping your other services protected.&lt;/p&gt;
&lt;p&gt;To disable CrowdSec for Immich, update the labels in your &lt;code&gt;docker-compose.yml&lt;/code&gt; by removing &lt;code&gt;crowdsec-bouncer@docker&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# In the immich-server labels section:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;traefik.http.routers.immich.middlewares=security-headers@file&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For more details on why you might want to do this, see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/#5-2-scenario-2-service-bypassing-crowdsec-special-case&quot;&gt;Scenario 2: Service Bypassing CrowdSec&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-maintenance-backup&quot;&gt;5. Maintenance &amp;amp; Backup&lt;/h2&gt;
&lt;h3 id=&quot;updating-immich&quot;&gt;Updating Immich&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/immich&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;backup-strategy&quot;&gt;Backup Strategy&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Gezieltes Database Backup:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Export only the &amp;#39;immich&amp;#39; database for a cleaner dump&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; database pg_dump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; immich immich&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; immich_db_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now have a secure, high-performance photo management system. By integrating Immich with Traefik and CrowdSec (or selectively bypassing it for sync reliability), you achieve a “Google Photos” experience while maintaining full control over your private data.&lt;/p&gt;
&lt;a href=&quot;https://immich.app/docs/overview/introduction&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL IMMICH DOCS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/immich-app/immich&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;IMMICH GITHUB&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>BIOS &amp; Firmware Update on Framework 13 (AMD Ryzen AI 300) under Arch Linux</title>
          <pubDate>Wed, 14 Jan 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/framework-bios-update/</link>
          <guid>https://criticalbasics.xyz/posts/framework-bios-update/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/framework-bios-update/">&lt;p&gt;The Framework Laptop 13 (AMD Ryzen AI 300 Series) is a prime example of hardware designed with Linux in mind. Instead of needing a Windows environment or a separate bootable USB stick, Framework leverages the &lt;strong&gt;Linux Vendor Firmware Service (LVFS)&lt;/strong&gt;. This guide outlines the exact, reproducible workflow to keep your system up to date using &lt;code&gt;fwupd&lt;/code&gt; on Arch Linux.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-01-14&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Full protocol for Framework 13 (AMD Ryzen AI 300) BIOS updates.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;Before starting the process, ensure your environment meets these requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hardware:&lt;/strong&gt; Framework Laptop 13 (AMD Ryzen AI 300 Series, e.g., AI 9 HX 370).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Power:&lt;/strong&gt; Power adapter &lt;strong&gt;must be connected&lt;/strong&gt; and charging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partitioning:&lt;/strong&gt; EFI System Partition (ESP) must be mounted (usually at &lt;code&gt;/boot&lt;/code&gt; or &lt;code&gt;/efi&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            MANDATORY POWER CONNECTION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The BIOS flash will refuse to start if the laptop is running on battery. Ensure your power cable is securely plugged in before proceeding.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-understanding-fwupd-lvfs&quot;&gt;2. Understanding fwupd &amp;amp; LVFS&lt;/h2&gt;
&lt;p&gt;Framework officially supports firmware updates via:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;fwupd&lt;/strong&gt;: The Firmware Update Daemon that manages the installation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LVFS&lt;/strong&gt;: The online repository where vendors upload their firmware.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The process uses &lt;strong&gt;UEFI Capsules&lt;/strong&gt;. &lt;code&gt;fwupd&lt;/code&gt; stages the update on your EFI partition, and the actual “flashing” happens during the next reboot within the UEFI environment, not while Linux is running.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-installation&quot;&gt;3. Installation&lt;/h2&gt;
&lt;p&gt;Install the necessary tools on Arch Linux using &lt;code&gt;pacman&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fwupd fwupd-efi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;fwupd.service&lt;/code&gt; is a static systemd service. It doesn’t need to be “enabled”; it starts automatically when called. You can verify its status:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; status fwupd.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-refreshing-firmware-metadata&quot;&gt;4. Refreshing Firmware Metadata&lt;/h2&gt;
&lt;p&gt;First, update the local database of available firmware from LVFS:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fwupdmgr refresh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If prompted to enable the LVFS remote, confirm with &lt;strong&gt;Y&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-checking-for-updates&quot;&gt;5. Checking for Updates&lt;/h2&gt;
&lt;p&gt;List all available updates for your hardware:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fwupdmgr get-updates&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will likely see several entries, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System Firmware&lt;/strong&gt; (The BIOS/UEFI)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fingerprint Sensor Firmware&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UEFI dbx&lt;/strong&gt; (Secure Boot revocation list)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-performing-the-update&quot;&gt;6. Performing the Update&lt;/h2&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            SAFETY FIRST
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;During the update:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do &lt;strong&gt;not&lt;/strong&gt; power off the machine.&lt;/li&gt;
&lt;li&gt;Do &lt;strong&gt;not&lt;/strong&gt; close the lid.&lt;/li&gt;
&lt;li&gt;Be patient. The screen may stay black for several minutes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Start the update process:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; fwupdmgr update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;what-to-expect&quot;&gt;What to expect:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fingerprint Sensor:&lt;/strong&gt; This usually updates instantly without a reboot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System Firmware (BIOS):&lt;/strong&gt; This is the core update. &lt;code&gt;fwupd&lt;/code&gt; will schedule it for the next boot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UEFI dbx:&lt;/strong&gt; Updates the Secure Boot blacklist.
&lt;em&gt;(Note: If you use a custom Secure Boot setup with your own keys, review this step carefully before confirming.)&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-the-reboot-flash-process&quot;&gt;7. The Reboot &amp;amp; Flash Process&lt;/h2&gt;
&lt;p&gt;After the command finishes, &lt;code&gt;fwupd&lt;/code&gt; will prompt you to restart:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reboot is required to complete the update.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What happens during reboot:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The system enters a special firmware update mode.&lt;/li&gt;
&lt;li&gt;The screen might remain black, and fans might spin up loudly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do not interrupt this.&lt;/strong&gt; There might not be a visible progress bar depending on the specific firmware version.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The system will automatically reboot into Arch Linux once the flash is complete.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;8-verifying-success&quot;&gt;8. Verifying Success&lt;/h2&gt;
&lt;p&gt;Once back in your terminal, verify that all devices are on the latest version:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fwupdmgr&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; get-devices&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, check the version directly in the BIOS by pressing &lt;strong&gt;F2&lt;/strong&gt; during startup. You should see the updated version number (e.g., &lt;code&gt;0.0.3.5&lt;/code&gt;).&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Updating firmware on a Framework laptop is a seamless experience that respects the user’s choice of OS:&lt;/p&gt;
&lt;p&gt;✅ Full BIOS update support under Linux
✅ No USB-Stick or Windows required
✅ Safe, transactional updates via UEFI Capsules
✅ Officially supported by Framework&lt;/p&gt;
&lt;a href=&quot;https://knowledgebase.frame.work/en_us/framework-laptop-13-bios-and-driver-releases-amd-ryzen-ai-300-series-r1wqKAs1e&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔧&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL FRAMEWORK BIOS RELEASES&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://wiki.archlinux.org/title/Fwupd&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ARCH WIKI: FWUPD&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://fwupd.org&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🌐&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;FWUPD PROJECT HOME&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Enhancing Ranger with exiftool: Advanced Image Metadata Viewing</title>
          <pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/ranger-exiftool-integration/</link>
          <guid>https://criticalbasics.xyz/posts/ranger-exiftool-integration/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/ranger-exiftool-integration/">&lt;p&gt;For photographers, designers, and anyone working with digital media, having quick access to file metadata is essential. This guide shows you how to integrate the powerful &lt;code&gt;exiftool&lt;/code&gt; utility with the ranger file manager, allowing you to view comprehensive metadata for images and other media files without leaving your terminal.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-01-12&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Shortcut Update:&lt;/strong&gt; Switched metadata shortcut from &lt;code&gt;ei&lt;/code&gt; to &lt;code&gt;ii&lt;/code&gt; (inspect/media prefix)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-07-18&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Created guide for integrating exiftool with ranger&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;Before we begin, make sure you have the following tools installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ranger&lt;/strong&gt;: The terminal file manager&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;exiftool&lt;/strong&gt;: A powerful utility for reading, writing, and manipulating metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;installation-on-various-distributions&quot;&gt;Installation on Various Distributions&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Debian/Ubuntu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install ranger libimage-exiftool-perl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Arch Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ranger perl-image-exiftool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Fedora&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dnf install ranger perl-Image-ExifTool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-creating-the-custom-exif-info-command&quot;&gt;2. Creating the Custom exif_info Command&lt;/h2&gt;
&lt;p&gt;The integration requires adding a custom command to ranger that will use &lt;code&gt;exiftool&lt;/code&gt; to display metadata for the selected file.&lt;/p&gt;
&lt;h3 id=&quot;2-1-create-or-edit-commands-py&quot;&gt;2.1. Create or Edit commands.py&lt;/h3&gt;
&lt;p&gt;First, navigate to your ranger configuration directory and create or edit the &lt;code&gt;commands.py&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/commands.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t have a &lt;code&gt;commands.py&lt;/code&gt; file yet, you can generate a template with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --copy-config=commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-2-add-the-exif-info-command&quot;&gt;2.2. Add the exif_info Command&lt;/h3&gt;
&lt;p&gt;Open the &lt;code&gt;commands.py&lt;/code&gt; file in your favorite text editor and add the following code:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;from&lt;/span&gt;&lt;span&gt; ranger.api.commands&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; import&lt;/span&gt;&lt;span&gt; Command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; mimetypes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; shlex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; shutil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; subprocess&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; exif_info&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Command&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    :exif_info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    Shows file metadata using exiftool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.fm.thisfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; f:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        filename&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; f.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; filename&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; or&lt;/span&gt;&lt;span&gt; os.path.isdir(filename):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; shutil.which(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            try&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                mime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; subprocess.check_output(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;--mime-type&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;-Lb&amp;quot;&lt;/span&gt;&lt;span&gt;, filename],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;                    text&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;                    stderr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;DEVNULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ).strip()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            except&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Exception&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                mime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; mime:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            mime, _&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; mimetypes.guess_type(filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        is_media&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; mime:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            is_media&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                mime.startswith((&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;image/&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;video/&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;audio/&amp;quot;&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                or&lt;/span&gt;&lt;span&gt; mime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;application/pdf&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; is_media:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            q&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; shlex.quote(filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.fm.execute_command(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;exiftool &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;q&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; | less&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.fm.display_file()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Detect whether the selected file is an image, video, audio file, or PDF (using &lt;code&gt;file --mime-type&lt;/code&gt; when available, with an extension-based fallback)&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;exiftool&lt;/code&gt; on media/PDF files and pipe the output to &lt;code&gt;less&lt;/code&gt; for easy viewing&lt;/li&gt;
&lt;li&gt;Fall back to ranger’s default preview (&lt;code&gt;display_file()&lt;/code&gt;) for all other file types&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-creating-a-keyboard-shortcut&quot;&gt;3. Creating a Keyboard Shortcut&lt;/h2&gt;
&lt;p&gt;Now that we have our custom command, let’s create a keyboard shortcut to invoke it easily.&lt;/p&gt;
&lt;h3 id=&quot;3-1-edit-rc-conf&quot;&gt;3.1. Edit rc.conf&lt;/h3&gt;
&lt;p&gt;Open your ranger configuration file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;vim&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/rc.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t have this file yet, you can generate it with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --copy-config=rc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-2-add-the-keyboard-mapping&quot;&gt;3.2. Add the Keyboard Mapping&lt;/h3&gt;
&lt;p&gt;Add the following line to map the &lt;code&gt;exif_info&lt;/code&gt; command to a keyboard shortcut. In this example, we’ll use &lt;code&gt;ii&lt;/code&gt; (which stands for “inspect info”):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map ii exif_info&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use &lt;code&gt;i&lt;/code&gt; as a generic &lt;strong&gt;inspect / media prefix&lt;/strong&gt; to group all image and media-related actions and avoid conflicts with ranger’s built-in &lt;code&gt;o&lt;/code&gt; (order) commands.&lt;/p&gt;
&lt;p&gt;This shortcut is easy to remember as &lt;code&gt;ii&lt;/code&gt; stands for “inspect info” - which is exactly what this command does: it shows you detailed metadata information about your files.&lt;/p&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Shortcut&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ii&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Show detailed metadata for the selected file using exiftool&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-advanced-configuration&quot;&gt;4. Advanced Configuration&lt;/h2&gt;
&lt;h3 id=&quot;4-1-using-with-different-file-types&quot;&gt;4.1. Using with Different File Types&lt;/h3&gt;
&lt;p&gt;One of the advantages of this implementation is that it targets media-related formats and avoids running exiftool on unrelated file types. The command will automatically use exiftool for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Common image formats (JPG, PNG, GIF, TIFF, etc.)&lt;/li&gt;
&lt;li&gt;RAW camera formats (CR2, NEF, ARW, DNG, etc.)&lt;/li&gt;
&lt;li&gt;Video files (MP4, MOV, AVI, MKV, etc.)&lt;/li&gt;
&lt;li&gt;Document formats (PDF, etc.)&lt;/li&gt;
&lt;li&gt;Audio files (MP3, FLAC, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For everything else, it will fall back to ranger’s normal file preview.&lt;/p&gt;
&lt;h3 id=&quot;4-2-format-the-output&quot;&gt;4.2. Format the Output&lt;/h3&gt;
&lt;p&gt;You can customize how the metadata is displayed by modifying the command that calls &lt;code&gt;exiftool&lt;/code&gt;. For example, to show only specific tags:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;q&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; shlex.quote(filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;self&lt;/span&gt;&lt;span&gt;.fm.execute_command(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;exiftool -DateTimeOriginal -Make -Model -LensModel -ExposureTime -FNumber -ISO &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;q&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; | less&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-3-create-a-colorized-output&quot;&gt;4.3. Create a Colorized Output&lt;/h3&gt;
&lt;p&gt;For a more visually appealing output, you can use &lt;code&gt;bat&lt;/code&gt; instead of &lt;code&gt;less&lt;/code&gt; if you have it installed:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;q&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; shlex.quote(filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;self&lt;/span&gt;&lt;span&gt;.fm.execute_command(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;exiftool &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;q&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; | bat --style=plain --color=always | less -R&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-usage&quot;&gt;5. Usage&lt;/h2&gt;
&lt;p&gt;Once everything is set up, you can use your new metadata viewing capability:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open ranger in your terminal&lt;/li&gt;
&lt;li&gt;Navigate to an image or media file&lt;/li&gt;
&lt;li&gt;Press your configured shortcut (e.g., &lt;code&gt;ii&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Browse through the metadata information&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;q&lt;/code&gt; to exit the viewer and return to ranger&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-practical-examples&quot;&gt;6. Practical Examples&lt;/h2&gt;
&lt;h3 id=&quot;6-1-photography-workflow&quot;&gt;6.1. Photography Workflow&lt;/h3&gt;
&lt;p&gt;For photographers, this integration is particularly useful for quickly checking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Camera settings (aperture, shutter speed, ISO)&lt;/li&gt;
&lt;li&gt;Lens information&lt;/li&gt;
&lt;li&gt;Date and time the photo was taken&lt;/li&gt;
&lt;li&gt;GPS coordinates (if available)&lt;/li&gt;
&lt;li&gt;Copyright information&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-2-batch-processing&quot;&gt;6.2. Batch Processing&lt;/h3&gt;
&lt;p&gt;You can combine this with other ranger commands to create a powerful workflow. For example, you could:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;zi&lt;/code&gt; (if you have the &lt;a href=&quot;/posts/ranger-fzf-bat-integration/&quot;&gt;fzf integration&lt;/a&gt;) to quickly find images&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;ii&lt;/code&gt; to check their metadata&lt;/li&gt;
&lt;li&gt;Use ranger’s tagging system to organize files based on metadata information&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;6-3-checking-file-integrity&quot;&gt;6.3. Checking File Integrity&lt;/h3&gt;
&lt;p&gt;For downloaded files or files received from others, you can quickly check:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creation and modification dates&lt;/li&gt;
&lt;li&gt;Software used to create the file&lt;/li&gt;
&lt;li&gt;Embedded comments or descriptions&lt;/li&gt;
&lt;li&gt;File integrity information&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-troubleshooting&quot;&gt;7. Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;7-1-command-not-found&quot;&gt;7.1. Command Not Found&lt;/h3&gt;
&lt;p&gt;If you get a “Command not found” error when trying to use the shortcut:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure you’ve saved the &lt;code&gt;commands.py&lt;/code&gt; file correctly&lt;/li&gt;
&lt;li&gt;Restart ranger to load the new command&lt;/li&gt;
&lt;li&gt;Check that &lt;code&gt;exiftool&lt;/code&gt; is installed and in your PATH&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;7-2-no-metadata-displayed&quot;&gt;7.2. No Metadata Displayed&lt;/h3&gt;
&lt;p&gt;If no metadata is displayed for a file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The file might not contain any metadata&lt;/li&gt;
&lt;li&gt;The file format might not be supported by exiftool&lt;/li&gt;
&lt;li&gt;There might be permission issues with the file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Try running &lt;code&gt;exiftool&lt;/code&gt; directly on the file to see if it works outside of ranger:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;exiftool&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; path/to/your/file&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With this integration, you’ve enhanced ranger’s capabilities for working with digital media files:&lt;/p&gt;
&lt;p&gt;✅ Quick access to comprehensive file metadata
✅ Support for a wide range of file formats
✅ Customizable keyboard shortcuts
✅ Seamless integration with your terminal workflow&lt;/p&gt;
&lt;p&gt;This setup is particularly valuable for photographers, designers, and anyone who works with digital media files regularly. It combines the file management power of ranger with the detailed metadata analysis capabilities of exiftool.&lt;/p&gt;
&lt;a href=&quot;https://exiftool.org/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;EXIFTOOL DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/ranger/ranger/wiki/Custom-Commands&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔧&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;RANGER CUSTOM COMMANDS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://exiftool.org/TagNames/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🏷️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;EXIFTOOL TAG NAMES&lt;/span&gt;
&lt;/a&gt;
&lt;h2 id=&quot;related-ranger-guides&quot;&gt;Related Ranger Guides&lt;/h2&gt;
&lt;p&gt;Enhance your ranger experience with these additional tutorials:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-fzf-bat-integration/&quot;&gt;Ranger and fzf Integration&lt;/a&gt; - Add powerful fuzzy search capabilities&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-compression-workflow/&quot;&gt;File Compression Workflow&lt;/a&gt; - Create and extract archives easily&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-media-preview-configuration/&quot;&gt;Advanced Media Preview Configuration&lt;/a&gt; - Customize file previews for various formats&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-sxiv-integration/&quot;&gt;Ranger and sxiv Integration&lt;/a&gt; - Create a seamless image viewing workflow&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>A Modern Image Optimization Workflow in ranger (with Rofi, ImageMagick &amp; WebP)</title>
          <pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/ranger-image-optimization/</link>
          <guid>https://criticalbasics.xyz/posts/ranger-image-optimization/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/ranger-image-optimization/">&lt;p&gt;For many power users, the terminal is not a limitation but a productivity multiplier. Yet image optimization is often one of the last steps still handled by heavyweight GUI tools.&lt;/p&gt;
&lt;p&gt;This guide shows you how to build a &lt;strong&gt;fully terminal-based image optimization workflow&lt;/strong&gt; around &lt;strong&gt;ranger&lt;/strong&gt;, combining ImageMagick, modern image optimizers, and a Rofi-driven preset menu. The result is a fast, reproducible setup that scales from simple social media exports to high-quality WebP graphics — without ever leaving your file manager.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-01-12&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Shortcut Update:&lt;/strong&gt; Switched optimization shortcut from &lt;code&gt;oi&lt;/code&gt; to &lt;code&gt;io&lt;/code&gt; (inspect/media prefix)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2026-01-09&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Created guide for image optimization workflow with Rofi presets&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide assumes a Linux system with a keyboard-focused workflow. Ensure you have the following tools installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ranger&lt;/strong&gt;: The terminal file manager&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ImageMagick&lt;/strong&gt;: The image processing backend&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pngquant&lt;/strong&gt;: Lossy PNG optimization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;oxipng&lt;/strong&gt;: Lossless PNG optimization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rofi&lt;/strong&gt;: Interactive preset menu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;libwebp&lt;/strong&gt;: WebP support&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            NOTE ON IMAGEMAGICK VERSIONS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This workflow supports both ImageMagick 6 (&lt;code&gt;convert&lt;/code&gt;) and ImageMagick 7 (&lt;code&gt;magick&lt;/code&gt;). On modern systems, ImageMagick 7 is preferred for better performance and syntax consistency. The script automatically detects which version is available.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;1-1-installation-examples&quot;&gt;1.1. Installation Examples&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Arch Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ranger imagemagick pngquant oxipng rofi libwebp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Debian / Ubuntu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install ranger imagemagick pngquant oxipng rofi libwebp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-design-goals-processing-strategy&quot;&gt;2. Design Goals &amp;amp; Processing Strategy&lt;/h2&gt;
&lt;p&gt;Before diving into the code, it is important to understand the design principles behind this setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Non-destructive&lt;/strong&gt;: Original images are never modified.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preset-driven&lt;/strong&gt;: No manual tweaking of parameters during daily use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pixel-safe where required&lt;/strong&gt;: Graphics and screenshots are handled differently from photos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privacy-aware&lt;/strong&gt;: Metadata is stripped by default.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast access&lt;/strong&gt;: One keybinding opens all optimization options.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-1-photos-vs-graphics&quot;&gt;2.1. Photos vs Graphics&lt;/h3&gt;
&lt;p&gt;A critical distinction is made between two image categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Photos (JPEG/PNG)&lt;/strong&gt;: Lossy compression is acceptable. Target: small file size for web/social platforms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graphics / UI / Screenshots&lt;/strong&gt;: Pixel integrity matters. Target: lossless or near-lossless processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-implementation-in-commands-py&quot;&gt;3. Implementation in commands.py&lt;/h2&gt;
&lt;p&gt;The code below should be added to your ranger configuration. It uses CommandLoader to run heavy processing in the background, keeping the ranger UI responsive.&lt;/p&gt;
&lt;h3 id=&quot;3-1-edit-commands-py&quot;&gt;3.1. Edit commands.py&lt;/h3&gt;
&lt;p&gt;Open your ranger configuration directory:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;vim&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/commands.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-2-add-the-optimization-logic&quot;&gt;3.2. Add the Optimization Logic&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;from&lt;/span&gt;&lt;span&gt; ranger.api.commands&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; import&lt;/span&gt;&lt;span&gt; Command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; shutil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; shlex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; subprocess&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;from&lt;/span&gt;&lt;span&gt; ranger.core.loader&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; import&lt;/span&gt;&lt;span&gt; CommandLoader&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_base&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Command&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot; Backend logic for image optimization &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; optimize&lt;/span&gt;&lt;span&gt;(self, target_width, quality, mode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;, suffix&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;, force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;None&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 keep_meta&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;False&lt;/span&gt;&lt;span&gt;, webp_lossless&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;False&lt;/span&gt;&lt;span&gt;, do_colorspace&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        cwd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.fm.thisdir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        marked_files&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cwd.get_selection()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; marked_files:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.fm.notify(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;No files selected!&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; bad&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        output_dir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cwd.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        image_exts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.jpg&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.jpeg&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.png&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.webp&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.tif&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.tiff&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        images&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; marked_files&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; if&lt;/span&gt;&lt;span&gt; f.path.lower().endswith(image_exts)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; images:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.fm.notify(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;No images found!&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; bad&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        magick_bin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;magick&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; if&lt;/span&gt;&lt;span&gt; shutil.which(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;magick&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; else&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;convert&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; if&lt;/span&gt;&lt;span&gt; shutil.which(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;convert&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; None&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; magick_bin:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.fm.notify(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Error: ImageMagick missing!&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; bad&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pngquant_bin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; shutil.which(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;pngquant&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        oxipng_bin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; shutil.which(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;oxipng&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        self&lt;/span&gt;&lt;span&gt;.fm.notify(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Starting optimization (&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;suffix&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)...&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; images:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            base&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.path.basename(f.path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            name, raw_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.path.splitext(base)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            src_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; raw_ext.lower()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            out_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; if&lt;/span&gt;&lt;span&gt; force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; else&lt;/span&gt;&lt;span&gt; src_ext&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            final_suffix&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; suffix&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; if&lt;/span&gt;&lt;span&gt; suffix&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; else f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;_w&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;target_width&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;mode&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            out_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}{&lt;/span&gt;&lt;span&gt;final_suffix&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}{&lt;/span&gt;&lt;span&gt;out_ext&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            dest&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.path.join(output_dir, out_name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;            # Avoid overwriting&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            counter&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            while&lt;/span&gt;&lt;span&gt; os.path.exists(dest):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                out_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}{&lt;/span&gt;&lt;span&gt;final_suffix&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;counter&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}{&lt;/span&gt;&lt;span&gt;out_ext&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                dest&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.path.join(output_dir, out_name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                counter&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            cmd_im&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [magick_bin, f.path,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-auto-orient&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; target_width&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-resize&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;target_width&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;x&amp;gt;&amp;#39;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; do_colorspace:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-colorspace&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;sRGB&amp;#39;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            do_strip_in_im&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; keep_meta:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                do_strip_in_im&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            elif&lt;/span&gt;&lt;span&gt; out_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.png&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; and&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;hq&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; and&lt;/span&gt;&lt;span&gt; oxipng_bin:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                do_strip_in_im&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; do_strip_in_im:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.append(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-strip&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; out_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.jpg&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.jpeg&amp;#39;&lt;/span&gt;&lt;span&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-quality&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; str&lt;/span&gt;&lt;span&gt;(quality)])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                if&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-sampling-factor&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;4:2:0&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-interlace&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Plane&amp;#39;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.append(dest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.loader.add(CommandLoader(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;cmd_im,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;JPG &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;mode&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; read&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            elif&lt;/span&gt;&lt;span&gt; out_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.webp&amp;#39;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-define&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;webp:method=6&amp;#39;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                if&lt;/span&gt;&lt;span&gt; webp_lossless:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-define&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;webp:lossless=true&amp;#39;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-quality&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; str&lt;/span&gt;&lt;span&gt;(quality)])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    cmd_im.extend([&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-define&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;webp:alpha-quality=90&amp;#39;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.append(dest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.loader.add(CommandLoader(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;cmd_im,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;WebP: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; read&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            elif&lt;/span&gt;&lt;span&gt; out_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.png&amp;#39;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.append(dest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                safe_im_cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;.join(shlex.quote(arg)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; arg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; cmd_im)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                full_cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; safe_im_cmd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;PNG (IM): &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                if&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; and&lt;/span&gt;&lt;span&gt; pngquant_bin:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    cmd_pq&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [pngquant_bin,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;--force&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;--skip-if-larger&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;--speed&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;3&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;--quality=65-85&amp;#39;&lt;/span&gt;&lt;span&gt;, dest]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    safe_pq_cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;.join(shlex.quote(arg)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; arg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; cmd_pq)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    full_cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;safe_im_cmd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;safe_pq_cmd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;PNG Lossy: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                elif&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;hq&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; and&lt;/span&gt;&lt;span&gt; oxipng_bin:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    cmd_oxi&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [oxipng_bin,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-o&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;2&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;--strip&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;safe&amp;#39;&lt;/span&gt;&lt;span&gt;, dest]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    safe_oxi_cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;.join(shlex.quote(arg)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; arg&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; cmd_oxi)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    full_cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;safe_im_cmd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;safe_oxi_cmd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;PNG HQ: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.loader.add(CommandLoader(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;sh&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-c&amp;#39;&lt;/span&gt;&lt;span&gt;, full_cmd],&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;descr,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; read&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cmd_im.append(dest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.loader.add(CommandLoader(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;cmd_im,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Convert: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; read&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; True&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # --- PRESETS ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_web&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1920&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 82&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_web&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_web_xl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;2560&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 82&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_webXL&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_web_hq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1920&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 92&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;hq&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_webHQ&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_blog&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1400&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 82&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_blog&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_thumb&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;600&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 75&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_thumb&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_ig_feed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1080&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 85&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_ig&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_ig_portrait&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1350&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 85&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_ig4x5&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_story&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1080&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 85&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_story&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_linkedin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1200&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 85&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_li&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_meta_ads&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1200&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 85&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_ads&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_jpeg_email&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1280&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 80&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_email&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.jpg&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_webp_hq&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1920&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 85&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_web&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.webp&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_webp_lossless&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;hq&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_graphic&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.webp&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; webp_lossless&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; do_colorspace&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;False&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_webp_no_resize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 82&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;lossy&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_webp&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.webp&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_png_graphic&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;hq&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_graphic&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; force_fmt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.png&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; do_colorspace&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;False&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; scale_strip_only&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;scale_base&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.optimize(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;hq&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;_stripped&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; keep_meta&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;False&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; do_colorspace&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;False&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # --- ROFI MENU ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; image_optimization_menu&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Command&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot; Rofi Menu for Image Optimization &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            menu_structure&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;--- WEB ---&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Web Standard (1920px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_web&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Web XL (2560px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_web_xl&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Web HQ (1920px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_web_hq&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Blog (1400px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_blog&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Thumbnail (600px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_thumb&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;--- SOCIAL ---&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;IG Feed (1080px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_ig_feed&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;IG Portrait (1350px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_ig_portrait&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;IG Story/Reel (1080px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_story&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;LinkedIn (1200px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_linkedin&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Meta Ads (1200px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_meta_ads&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;JPEG Email (1280px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_jpeg_email&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;--- MODERN/TOOLS ---&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;WebP HQ (1920px)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_webp_hq&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;WebP Lossless (Grafik)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_webp_lossless&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;WebP Convert (Original Size)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_webp_no_resize&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;PNG Graphic (Original, no sRGB)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_png_graphic&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Strip Metadata Only&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;scale_strip_only&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if not&lt;/span&gt;&lt;span&gt; shutil.which(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;rofi&amp;#39;&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.notify(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Rofi missing!&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; bad&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            options_str&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;.join([item[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; item&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; menu_structure])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            try&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                p&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; subprocess.Popen(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;rofi&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-dmenu&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-p&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Optimize&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-i&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;-lines&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; str&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;len&lt;/span&gt;&lt;span&gt;(menu_structure))],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;                    stdin&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;PIPE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;                    stdout&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;PIPE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;                    stderr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;PIPE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;                    text&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                stdout, _&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; p.communicate(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;options_str)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                selection&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; stdout.strip()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                if not&lt;/span&gt;&lt;span&gt; selection:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                    return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                for&lt;/span&gt;&lt;span&gt; label, cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; menu_structure:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                    if&lt;/span&gt;&lt;span&gt; label&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span&gt; selection:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                        if&lt;/span&gt;&lt;span&gt; cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;true&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                            self&lt;/span&gt;&lt;span&gt;.fm.execute_console(cmd)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                        break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            except&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; as&lt;/span&gt;&lt;span&gt; e:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.notify(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Error: &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; bad&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-creating-keyboard-shortcuts&quot;&gt;4. Creating Keyboard Shortcuts&lt;/h2&gt;
&lt;p&gt;Now, let’s map the interactive menu to a shortcut.&lt;/p&gt;
&lt;h3 id=&quot;4-1-edit-rc-conf&quot;&gt;4.1. Edit rc.conf&lt;/h3&gt;
&lt;p&gt;Open your rc.conf:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;vim&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/rc.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-add-the-mapping&quot;&gt;4.2. Add the Mapping&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Image Optimization Menu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map io image_optimization_menu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use &lt;code&gt;i&lt;/code&gt; as a generic &lt;strong&gt;inspect / media prefix&lt;/strong&gt; to group all image and media-related actions and avoid conflicts with ranger’s built-in &lt;code&gt;o&lt;/code&gt; (order) commands.&lt;/p&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Shortcut&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;io&lt;/td&gt;&lt;td&gt;Open Rofi menu to select image optimization preset&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-preset-overview&quot;&gt;5. Preset Overview&lt;/h2&gt;
&lt;p&gt;The workflow provides curated presets for real-world scenarios:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Web Standard (1920px)&lt;/strong&gt;: Balanced compression for websites.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web XL (2560px)&lt;/strong&gt;: Extra-wide output for large screens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web HQ (1920px)&lt;/strong&gt;: Minimal compression for high-quality portfolios.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blog (1400px)&lt;/strong&gt;: Cleaner sizing for article layouts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thumbnail (600px)&lt;/strong&gt;: Small previews.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Instagram Feed (1080px)&lt;/strong&gt;: Optimized for Instagram’s upload limits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IG Portrait (1350px)&lt;/strong&gt;: 4:5 portrait-friendly sizing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IG Story/Reel (1080px)&lt;/strong&gt;: Vertical-first exports.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LinkedIn (1200px)&lt;/strong&gt;: Social sharing format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meta Ads (1200px)&lt;/strong&gt;: Ad-friendly sizing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JPEG Email (1280px)&lt;/strong&gt;: Compatibility-first export.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebP HQ&lt;/strong&gt;: Modern lossy format for superior size-to-quality ratio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebP Lossless (Graphic)&lt;/strong&gt;: Lossless WebP for pixel-perfect graphics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebP Convert (Original Size)&lt;/strong&gt;: Convert without resizing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PNG Graphic (Original, no sRGB)&lt;/strong&gt;: Preserve pixel values and skip sRGB conversion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strip Metadata&lt;/strong&gt;: Removes EXIF/GPS data without changing pixel values.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            WHY ROFI?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Rofi provides fuzzy search and instant feedback. It fits perfectly into window manager workflows and avoids the need to memorize dozens of separate keybindings.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-practical-use-cases&quot;&gt;6. Practical Use Cases&lt;/h2&gt;
&lt;h3 id=&quot;6-1-content-publishing&quot;&gt;6.1. Content Publishing&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your image folder in ranger.&lt;/li&gt;
&lt;li&gt;Mark images with Space.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;io&lt;/code&gt; and select &lt;strong&gt;Web Standard&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Optimized files appear in the same folder as the originals.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;6-2-privacy-stripping&quot;&gt;6.2. Privacy Stripping&lt;/h3&gt;
&lt;p&gt;Before sharing photos online, mark them and run &lt;strong&gt;Strip Metadata Only&lt;/strong&gt; to ensure no GPS or camera information is leaked.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-troubleshooting&quot;&gt;7. Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;7-1-images-appear-rotated&quot;&gt;7.1. Images appear rotated&lt;/h3&gt;
&lt;p&gt;The script uses &lt;code&gt;-auto-orient&lt;/code&gt; before processing. This ensures that the orientation tag is respected even when metadata is stripped.&lt;/p&gt;
&lt;h3 id=&quot;7-2-colors-look-different&quot;&gt;7.2. Colors look different&lt;/h3&gt;
&lt;p&gt;Web presets normalize images to sRGB. If you need to preserve a specific color profile, use the &lt;strong&gt;Strip Only&lt;/strong&gt; or &lt;strong&gt;PNG Graphic&lt;/strong&gt; presets which skip colorspace conversion.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;8-summary&quot;&gt;8. Summary&lt;/h2&gt;
&lt;p&gt;With this integration, you’ve transformed ranger into a high-performance image processing station:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Batch processing of multiple images&lt;/li&gt;
&lt;li&gt;✅ Searchable Rofi menu for all presets&lt;/li&gt;
&lt;li&gt;✅ Background execution via CommandLoader&lt;/li&gt;
&lt;li&gt;✅ Support for modern formats like WebP&lt;/li&gt;
&lt;li&gt;✅ Optimized for web, social media, and privacy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This setup combines the simplicity of ranger with the industrial-grade power of ImageMagick, ensuring your images are always perfectly optimized for any platform.&lt;/p&gt;
&lt;a href=&quot;https://imagemagick.org/script/command-line-options.php&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;IMAGEMAGICK CLI DOCS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/shinchiro/mpv-scripts&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔧&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;MORE RANGER TOOLS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://pngquant.org/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🖼️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;PNGQUANT HOME&lt;/span&gt;
&lt;/a&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;9-related-ranger-guides&quot;&gt;9. Related Ranger Guides&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://criticalbasics.xyz/posts/ranger-fzf-bat-integration/&quot;&gt;Ranger and fzf Integration&lt;/a&gt;&lt;/strong&gt;: Search files at lightning speed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://criticalbasics.xyz/posts/ranger-exiftool-integration/&quot;&gt;Image Metadata Viewing with exiftool&lt;/a&gt;&lt;/strong&gt;: View EXIF data before optimizing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://criticalbasics.xyz/posts/ranger-compression-workflow/&quot;&gt;File Compression Workflow&lt;/a&gt;&lt;/strong&gt;: Archive your optimized assets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://criticalbasics.xyz/posts/ranger-media-preview-configuration/&quot;&gt;Advanced Media Preview Configuration&lt;/a&gt;&lt;/strong&gt;: Better previews for WebP files&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Turning on Samsung M51 without Power Button: The Heimdall Method</title>
          <pubDate>Tue, 09 Dec 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/samsung-m51-heimdall-start/</link>
          <guid>https://criticalbasics.xyz/posts/samsung-m51-heimdall-start/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/samsung-m51-heimdall-start/">&lt;p&gt;When the power button of a Samsung Galaxy smartphone breaks, the device often seems like a lost cause once the battery runs empty or it turns off. A frustrating detail: Without a working power button, the device often shows no charging animation when plugged in, but rather stays on a black screen—it appears “dead” even though the battery is charging.&lt;/p&gt;
&lt;p&gt;This guide demonstrates a reliable workaround: We force the device into &lt;strong&gt;Download Mode&lt;/strong&gt; using a button combination and use the open-source tool &lt;strong&gt;Heimdall&lt;/strong&gt; on Linux to force a reboot.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            COMPATIBILITY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This guide was specifically verified with a &lt;strong&gt;Samsung Galaxy M51&lt;/strong&gt;. However, the method works with almost all Samsung devices that have physical volume keys due to the underlying technology:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Galaxy S-Series&lt;/strong&gt; (e.g., S7 to S21)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Galaxy A-Series&lt;/strong&gt; (e.g., A51, A52, A21s)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Galaxy M-Series&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Galaxy Tab Tablets&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-12-09&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Update &amp;amp; Refinement:&lt;/strong&gt; Updated to Heimdall 2.2.2, added troubleshooting section, and clarified distinction between Warning Screen and Download Mode.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-12-08&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide created based on successful tests with a Samsung Galaxy M51.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;Before we begin, ensure you have access to a Linux PC. This guide specifically references Arch Linux, but the commands are easily transferable to Debian/Ubuntu.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            IMPORTANT: ROOT &amp; BATTERY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;No Root on Phone needed:&lt;/strong&gt; Your smartphone does &lt;em&gt;not&lt;/em&gt; need to be rooted. We only need &lt;code&gt;sudo&lt;/code&gt; rights on the &lt;strong&gt;PC&lt;/strong&gt; to access the USB interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Charge Battery:&lt;/strong&gt; Ensure the device has been on the charger for at least 15 minutes, even if the display remained black.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Cable:&lt;/strong&gt; Use a fully functional USB data cable, not a charge-only cable.&lt;/li&gt;
&lt;/ol&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;2-forcing-download-mode&quot;&gt;2. Forcing Download Mode&lt;/h2&gt;
&lt;p&gt;Since the power button is non-functional, we utilize a service button combination. This step is performed while the device is powered off.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Disconnect Cable:&lt;/strong&gt; Ensure the USB cable is &lt;em&gt;not&lt;/em&gt; connected to the smartphone (but is already plugged into the PC).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hold Buttons:&lt;/strong&gt; Press and hold both &lt;strong&gt;Volume Up (Vol+)&lt;/strong&gt; and &lt;strong&gt;Volume Down (Vol-)&lt;/strong&gt; simultaneously.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect:&lt;/strong&gt; While holding both buttons, plug the USB cable into the smartphone.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The display should now light up and show a turquoise &lt;strong&gt;Warning Screen&lt;/strong&gt; (&lt;code&gt;Warning! A custom OS can cause...&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is &lt;em&gt;not&lt;/em&gt; Download Mode yet.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;Confirm:&lt;/strong&gt; Now press the &lt;strong&gt;Vol Up&lt;/strong&gt; key once. Only now does the device switch to the actual &lt;strong&gt;Download Mode&lt;/strong&gt;. The screen will display a large “Downloading…”.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;3-heimdall-setup&quot;&gt;3. Heimdall Setup&lt;/h2&gt;
&lt;p&gt;We use the tool &lt;code&gt;heimdall&lt;/code&gt;, an open-source alternative to Samsung’s Odin.&lt;/p&gt;
&lt;h3 id=&quot;3-1-installation&quot;&gt;3.1. Installation&lt;/h3&gt;
&lt;p&gt;On Arch Linux, install the package as follows (tested with version 2.2.2):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; heimdall&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Debian/Ubuntu users, the command is usually &lt;code&gt;sudo apt install heimdall-flash&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;3-2-verify-connection&quot;&gt;3.2. Verify Connection&lt;/h3&gt;
&lt;p&gt;Check if your PC recognizes the smartphone in Download Mode.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;heimdall&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; detect&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The expected output should be:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Device detected&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(If an error occurs here, see Section 5 “Troubleshooting”.)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;4-triggering-the-reboot&quot;&gt;4. Triggering the Reboot&lt;/h2&gt;
&lt;p&gt;Now for the crucial step. We send a command to the smartphone that usually cleanly terminates a flashing session.&lt;/p&gt;
&lt;p&gt;Run the following command in your terminal:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; heimdall close-pc-screen&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;the-result&quot;&gt;The Result&lt;/h3&gt;
&lt;p&gt;You should see a success message in the terminal:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Attempting to close connect to pc screen...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Rebooting device...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Attempt complete&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The smartphone screen will immediately turn black and restart. Since we are no longer in the special maintenance mode, the Android system will boot up normally—without needing the power button.&lt;/p&gt;
&lt;h2 id=&quot;5-troubleshooting&quot;&gt;5. Troubleshooting&lt;/h2&gt;
&lt;p&gt;If it doesn’t work right away, here are the common pitfalls:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem: &lt;code&gt;heimdall detect&lt;/code&gt; shows “Failed to detect compatible device”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution A (Cable):&lt;/strong&gt; The most common issue is low-quality USB cables. Try a different one, ideally the original Samsung cable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Solution B (Permissions):&lt;/strong&gt; Missing &lt;code&gt;udev&lt;/code&gt; rules might be the cause. Try running the command with admin privileges: &lt;code&gt;sudo heimdall detect&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Problem: &lt;code&gt;libusb error&lt;/code&gt; or &lt;code&gt;Claiming interface failed&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Another process is blocking the USB port. Unplug the cable, wait 5 seconds, and plug it back in. Ensure no other software (like ModemManager) is trying to access the device.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Problem: Device reboots back into Download Mode&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution:&lt;/strong&gt; In rare cases, one of the volume buttons might be stuck physically. Ensure the keys are not jammed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-technical-background&quot;&gt;6. Technical Background&lt;/h2&gt;
&lt;p&gt;Why does this work?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hardware Design:&lt;/strong&gt; Samsung devices have a hardware trigger (&lt;code&gt;Vol+&lt;/code&gt; &amp;amp; &lt;code&gt;Vol-&lt;/code&gt; + USB Insert) that activates &lt;em&gt;before&lt;/em&gt; the main bootloader. This allows technicians to access the device even with corrupted software or broken physical buttons.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Protocol:&lt;/strong&gt; The command &lt;code&gt;close-pc-screen&lt;/code&gt; sends a specific &lt;strong&gt;End-of-Session command&lt;/strong&gt; to the bootloader. The bootloader interprets this as “Maintenance successfully finished” and initiates a regular system reboot.&lt;/li&gt;
&lt;/ul&gt;
&lt;a href=&quot;https://git.sr.ht/~grimler/Heimdall&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;HEIMDALL SOURCE CODE&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://wiki.archlinux.org/title/Android_flashing#Heimdall&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ARCH WIKI: HEIMDALL&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying Mastodon with Docker and a Modern Traefik Stack</title>
          <pubDate>Thu, 30 Oct 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/mastodon/</link>
          <guid>https://criticalbasics.xyz/posts/mastodon/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/mastodon/">&lt;p&gt;This guide provides a step-by-step walkthrough for deploying a production-ready Mastodon instance. We will use the official Mastodon Docker images and configure them to run securely behind our modern Traefik v3 reverse proxy, which handles TLS, security headers, and threat protection via CrowdSec.&lt;/p&gt;
&lt;p&gt;This setup ensures a robust, scalable, and secure social media platform that you control.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-10-30&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Guide created, adapting the official Mastodon Docker setup for a modern Traefik v3 and CrowdSec security stack.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide builds upon a secure and pre-existing Docker environment. Before you begin, you must have a fully functional Traefik v3 and CrowdSec stack.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            HARD REQUIREMENT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The following steps will not work correctly without the Traefik stack running as described in the prerequisite guide.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;: This is the foundation for our public-facing reverse proxy and security.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;You will also need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A dedicated domain for your Mastodon instance (e.g., &lt;code&gt;mastodon.your-domain.com&lt;/code&gt;) pointed to your server’s IP address.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access.&lt;/li&gt;
&lt;li&gt;A functional email (SMTP) server for sending transactional emails.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-directory-structure&quot;&gt;2. Directory Structure&lt;/h2&gt;
&lt;p&gt;First, create a dedicated directory for your Mastodon configuration and data. This structure will hold all necessary files and persistent data.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create the main directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mastodon&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mastodon&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create directories for persistent data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres redis public/system&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Mastodon runs as user 991. We need to set the correct permissions.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 991:991 public/system&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-configuration&quot;&gt;3. Configuration&lt;/h2&gt;
&lt;p&gt;Configuring Mastodon involves generating a configuration file using an interactive wizard and then creating our Docker Compose file to orchestrate the services.&lt;/p&gt;
&lt;h3 id=&quot;3-1-docker-compose-docker-compose-yml&quot;&gt;3.1. Docker Compose (&lt;code&gt;docker-compose.yml&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;First, create the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. We create this file &lt;em&gt;before&lt;/em&gt; running the setup wizard so that Docker knows which image to use.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  db:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: postgres:14-alpine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    shm_size: 256mb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - mastodon-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;#39;CMD&amp;#39;, &amp;#39;pg_isready&amp;#39;, &amp;#39;-U&amp;#39;, &amp;#39;postgres&amp;#39;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./postgres:/var/lib/postgresql/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;#39;POSTGRES_HOST_AUTH_METHOD=trust&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  redis:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: redis:7-alpine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - mastodon-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;#39;CMD&amp;#39;, &amp;#39;redis-cli&amp;#39;, &amp;#39;ping&amp;#39;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./redis:/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  web:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/mastodon/mastodon:v4.4.8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: mastodon-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    env_file: .env.production&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command: bash -c &amp;quot;rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - mastodon-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;#39;CMD-SHELL&amp;#39;, &amp;#39;wget -q --spider --proxy=off localhost:3000/health || exit 1&amp;#39;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - redis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    user: 991:991&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./public/system:/mastodon/public/system&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-web.rule=Host(`${MASTODON_HOST}`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-web.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-web.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-web.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.mastodon-web.loadbalancer.server.port=3000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  streaming:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/mastodon/mastodon:v4.4.8 # Note: Since v4.3.0, streaming is part of the main image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: mastodon-streaming&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    env_file: .env.production&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command: node ./streaming&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - mastodon-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;#39;CMD-SHELL&amp;#39;, &amp;#39;wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1&amp;#39;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - redis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-streaming.rule=Host(`${MASTODON_HOST}`) &amp;amp;&amp;amp; PathPrefix(`/api/v1/streaming`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-streaming.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-streaming.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.mastodon-streaming.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.mastodon-streaming.loadbalancer.server.port=4000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  sidekiq:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/mastodon/mastodon:v4.4.8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: mastodon-sidekiq&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    env_file: .env.production&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command: bundle exec sidekiq&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    depends_on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - redis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - mastodon-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./public/system:/mastodon/public/system&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;#39;CMD-SHELL&amp;#39;, &amp;quot;ps aux | grep &amp;#39;[s]idekiq&amp;#39; || false&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    user: 991:991&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  mastodon-net:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    driver: bridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            A NOTE ON DATABASE SECURITY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;POSTGRES_HOST_AUTH_METHOD=trust&lt;/code&gt; setting is convenient and generally safe within an isolated Docker network where no ports are exposed to the outside world. It allows other containers within the same &lt;code&gt;docker-compose.yml&lt;/code&gt; to connect without a password. For production environments with stricter security requirements, you should configure proper password-based authentication.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            TRAEFIK LABELS EXPLAINED
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;labels&lt;/code&gt; section is crucial. It tells our Traefik proxy how to handle requests for Mastodon.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tls.certresolver=tls_resolver&lt;/code&gt;&lt;/strong&gt;: This uses the Let’s Encrypt resolver we defined in our main Traefik stack.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;middlewares=security-headers@file,crowdsec-bouncer@docker&lt;/code&gt;&lt;/strong&gt;: This is the key integration. It applies our predefined security headers and protects the instance with the CrowdSec bouncer, blocking malicious IPs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-2-environment-file-env&quot;&gt;3.2. Environment File (&lt;code&gt;.env&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Create a simple &lt;code&gt;.env&lt;/code&gt; file to store your domain name. The &lt;code&gt;docker-compose.yml&lt;/code&gt; will use this.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;MASTODON_HOST=mastodon.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            IMPORTANT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Replace &lt;code&gt;mastodon.your-domain.com&lt;/code&gt; with your actual domain. This file is separate from the main Mastodon configuration (&lt;code&gt;.env.production&lt;/code&gt;) that we will generate next.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-3-mastodon-setup-wizard&quot;&gt;3.3. Mastodon Setup Wizard&lt;/h3&gt;
&lt;p&gt;Mastodon provides an interactive setup wizard to generate its main configuration file (&lt;code&gt;.env.production&lt;/code&gt;). Let’s run it.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# This command runs the setup task in a temporary container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web bundle exec rake mastodon:setup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The wizard will ask you a series of questions. Here are some recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain name&lt;/strong&gt;: Enter the same domain you used in your &lt;code&gt;.env&lt;/code&gt; file (e.g., &lt;code&gt;mastodon.your-domain.com&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single user mode?&lt;/strong&gt;: &lt;code&gt;n&lt;/code&gt; (unless you want a private, single-person instance).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Are you using Docker?&lt;/strong&gt;: &lt;code&gt;y&lt;/code&gt;. This will correctly set the database and Redis hostnames.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database host&lt;/strong&gt;: It should default to &lt;code&gt;db&lt;/code&gt;. Press Enter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis host&lt;/strong&gt;: It should default to &lt;code&gt;redis&lt;/code&gt;. Press Enter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SMTP settings&lt;/strong&gt;: Provide the details for your email server. Mastodon needs this to send confirmation emails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save configuration?&lt;/strong&gt;: &lt;code&gt;y&lt;/code&gt;. This will create the &lt;code&gt;.env.production&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-launch-the-stack&quot;&gt;4. Launch the Stack&lt;/h2&gt;
&lt;p&gt;Now that all configuration is in place, you can start your Mastodon instance.&lt;/p&gt;
&lt;h3 id=&quot;4-1-initial-database-migration&quot;&gt;4.1. Initial Database Migration&lt;/h3&gt;
&lt;p&gt;Before the first full launch, we need to prepare the database.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Run the database migration in a temporary container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web rails db:migrate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-start-all-services&quot;&gt;4.2. Start All Services&lt;/h3&gt;
&lt;p&gt;With the database ready, bring the entire stack online.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first launch will take a few minutes as Docker downloads the images. You can monitor the progress with &lt;code&gt;sudo docker compose logs -f&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;5-post-installation-steps&quot;&gt;5. Post-Installation Steps&lt;/h2&gt;
&lt;p&gt;Your instance is running, but you need to create an admin account.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Use this command to create an admin user interactively&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web tootctl accounts create YOUR_USERNAME&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  --email&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; YOUR_EMAIL@example.com&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --confirmed --role&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Admin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;YOUR_USERNAME&lt;/code&gt; and &lt;code&gt;YOUR_EMAIL@example.com&lt;/code&gt; with your desired credentials. You will be prompted to set a password.&lt;/p&gt;
&lt;p&gt;You can now navigate to &lt;code&gt;https://mastodon.your-domain.com&lt;/code&gt; and log in with your new admin account.&lt;/p&gt;
&lt;h2 id=&quot;6-maintenance&quot;&gt;6. Maintenance&lt;/h2&gt;
&lt;h3 id=&quot;updating-mastodon&quot;&gt;Updating Mastodon&lt;/h3&gt;
&lt;p&gt;Updating is a straightforward process. First, check the official Mastodon release notes for any special instructions.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mastodon&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Update the image tags in your docker-compose.yml to the new version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Pull the new images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose pull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Stop the services before migrating the database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose down&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Run database migrations required by the new version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose run&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; web rails db:migrate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Start the stack again&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d --remove-orphans&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;backing-up&quot;&gt;Backing Up&lt;/h3&gt;
&lt;p&gt;A complete backup consists of the database, user-uploaded files, and Redis data.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mastodon&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. Back up the database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; docker compose exec&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; db pg_dump&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mastodon_production&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gzip&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mastodon_db_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.sql.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Back up user-uploaded files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -czvf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mastodon_files_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.tar.gz public/system&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. Back up Redis data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -czvf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mastodon_redis_backup_&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +%F&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.tar.gz redis&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You have successfully deployed a production-ready Mastodon instance. By leveraging Docker for containerization and integrating with a modern Traefik and CrowdSec stack, your instance is not only scalable and easy to manage but also benefits from robust, centralized security and TLS management.&lt;/p&gt;
&lt;a href=&quot;https://docs.joinmastodon.org/admin/install/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL MASTODON DOCS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/mastodon/mastodon&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OFFICIAL GITHUB REPO&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying Mailcow with Docker and Traefik for a Full E-Mail Stack</title>
          <pubDate>Fri, 03 Oct 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/mailcow-mailserver/</link>
          <guid>https://criticalbasics.xyz/posts/mailcow-mailserver/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/mailcow-mailserver/">&lt;p&gt;Mailcow is a powerful and flexible open-source mail server suite that allows you to manage your email communications securely and efficiently. With Mailcow, you can create multiple email domains and accounts, manage users, and leverage features like spam filtering and encryption, giving you full control over your email infrastructure. This guide will show you how to set up Mailcow using Docker Compose behind an existing Traefik reverse proxy.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-10-03&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Major Revision:&lt;/strong&gt; Corrected &lt;code&gt;certdumper&lt;/code&gt; command, simplified Traefik labels, and fixed critical &lt;code&gt;mailcow.conf&lt;/code&gt; networking settings to resolve 404 errors. Enhanced troubleshooting for network conflicts.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-09-18&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; First version of this guide was created.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide assumes you have a fully functional server environment with the following components already set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose&lt;/a&gt;&lt;/strong&gt;: This is the foundation for our reverse proxy, security, and certificate management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker and Docker Compose&lt;/strong&gt;: Must be installed on your server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Required Tools&lt;/strong&gt;: You will need &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;jq&lt;/code&gt;. Install them with:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-directory-structure&quot;&gt;2. Directory Structure&lt;/h2&gt;
&lt;p&gt;First, create a dedicated directory for your Mailcow installation.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            PATH CONSISTENCY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This guide uses &lt;code&gt;/opt/containers/mailcow/&lt;/code&gt; as the primary directory for the Mailcow stack. The Traefik stack is assumed to be in &lt;code&gt;/opt/containers/traefik-stack/&lt;/code&gt;, consistent with our &lt;a href=&quot;../traefik-v3-crowdsec-tutorial/&quot;&gt;Traefik v3 tutorial&lt;/a&gt;. If your paths differ, be sure to adjust them in all configuration files and commands throughout this guide.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mailcow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-clone-the-mailcow-repository&quot;&gt;3. Clone the Mailcow Repository&lt;/h2&gt;
&lt;p&gt;Clone the latest version of the Mailcow Dockerized project from GitHub into the directory you just created.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git clone https://github.com/mailcow/mailcow-dockerized /opt/containers/mailcow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;4-generate-the-configuration-file&quot;&gt;4. Generate the Configuration File&lt;/h2&gt;
&lt;p&gt;Navigate into the new directory and run the configuration generation script.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mailcow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;./generate_config.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted for the following information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mail server hostname (FQDN):&lt;/strong&gt; Enter the fully qualified domain name for your mail server, for example, &lt;code&gt;mail.your-domain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timezone:&lt;/strong&gt; Press Enter to accept the default or provide your own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Available Branches:&lt;/strong&gt; Press &lt;code&gt;1&lt;/code&gt; to select the master branch.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-configure-for-traefik-integration&quot;&gt;5. Configure for Traefik Integration&lt;/h2&gt;
&lt;p&gt;To make Mailcow work with our external Traefik instance, we need to create an override file and modify the main configuration.&lt;/p&gt;
&lt;h3 id=&quot;5-1-create-docker-compose-override-yml&quot;&gt;5.1. Create &lt;code&gt;docker-compose.override.yml&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This file contains all our customizations, telling Mailcow to use the external &lt;code&gt;proxy&lt;/code&gt; network and defining labels for Traefik to route traffic correctly. It also sets up a &lt;code&gt;certdumper&lt;/code&gt; service, which is crucial for sharing Traefik’s Let’s Encrypt certificates with Mailcow’s services (Postfix and Dovecot).&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            HOW THE CERTDUMPER WORKS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;certdumper&lt;/code&gt; is essential. It extracts certificates from Traefik’s &lt;code&gt;acme.json&lt;/code&gt; and saves them as &lt;code&gt;.pem&lt;/code&gt; files that Postfix and Dovecot can read. The command &lt;code&gt; --restart-containers mailcowdockerized-postfix-mailcow-1,...&lt;/code&gt; is critical; it restarts the mail services by their full Docker container name after a certificate is updated, ensuring the new certificate is loaded immediately.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Create the file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee /opt/containers/mailcow/docker-compose.override.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    name: proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  certdumper:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: ghcr.io/kereis/traefik-certs-dumper:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    network_mode: none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # Correct command to restart containers by their full name. Mailcow&amp;#39;s project name is &amp;quot;mailcowdockerized&amp;quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    command: --restart-containers mailcowdockerized-postfix-mailcow-1,mailcowdockerized-dovecot-mailcow-1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Adjust this path to match YOUR Traefik stack&amp;#39;s certificate location&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - /opt/containers/traefik-stack/traefik/certs:/traefik:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - /var/run/docker.sock:/var/run/docker.sock:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./data/assets/ssl:/output:rw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      DOMAIN: ${MAILCOW_HOSTNAME}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Adjust this to match YOUR Traefik acme file name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      ACME_FILE_PATH: &amp;quot;/traefik/acme.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    healthcheck:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      test: [&amp;quot;CMD&amp;quot;, &amp;quot;/usr/bin/healthcheck&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      interval: 30s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      timeout: 10s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      retries: 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  nginx-mailcow:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # We use !reset to completely remove the default port bindings set by Mailcow.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ports: !reset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.docker.network=proxy&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # HTTPS Router (Secure)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # The HTTP to HTTPS redirect is handled globally by our Traefik setup, so we only need the secure router.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx-mailcow-secure.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx-mailcow-secure.rule=Host(`mail.your-domain.com`) || Host(`autodiscover.your-domain.com`) || Host(`autoconfig.your-domain.com`) || Host(`mta-sts.your-domain.com`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx-mailcow-secure.tls=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx-mailcow-secure.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx-mailcow-secure.service=nginx-mailcow&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx-mailcow-secure.middlewares=security-headers@file,crowdsec-bouncer@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Service Definition: Point to Mailcow&amp;#39;s internal Nginx port.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # This must be 80, as we are NOT changing the internal ports in mailcow.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.nginx-mailcow.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            CROWDSEC BOUNCER SCOPE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;crowdsec-bouncer@docker&lt;/code&gt; middleware only protects the HTTP/HTTPS endpoints routed through Traefik (like the Mailcow UI and SOGo). It does &lt;strong&gt;not&lt;/strong&gt; protect mail services like SMTP, IMAP, or POP3, as their traffic does not pass through the Traefik router. To harden these mail protocols, you need to configure CrowdSec to parse their log files (e.g., using the &lt;code&gt;crowdsecurity/postfix&lt;/code&gt; and &lt;code&gt;crowdsecurity/dovecot&lt;/code&gt; collections on the host).&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            IMPORTANT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;You must replace &lt;code&gt;your-domain.com&lt;/code&gt; with your actual domain name. You can do this manually or with the following command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;s/your-domain.com/your-actual-domain.com/g&amp;quot; docker-compose.override.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;5-2-adjust-mailcow-conf&quot;&gt;5.2. Adjust &lt;code&gt;mailcow.conf&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Next, edit the main configuration file. There are only &lt;strong&gt;two changes&lt;/strong&gt; needed here.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano /opt/containers/mailcow/mailcow.conf```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;infobox type=&amp;quot;danger&amp;quot; title=&amp;quot;Critical: Do Not Change Ports or Bindings!&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Do&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; change `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;HTTP_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;HTTPS_PORT&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;HTTP_BIND&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; or `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;HTTPS_BIND&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Leaving them at their default values is crucial. Changing `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;HTTP_BIND&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; will&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; prevent Traefik from reaching the Mailcow web UI, resulting in a&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;404 Not Found error&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;. The internal ports do not conflict with Traefik because they are inside the Docker network, not on the host.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/infobox&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  **&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;Disable Mailcow&amp;#39;s Let&amp;#39;s Encrypt:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Traefik is responsible for all certificate management. This is the most important change.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ```&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ini&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Find this line:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    SKIP_LETS_ENCRYPT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Change it to:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    SKIP_LETS_ENCRYPT&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  **&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;Add SAN for Internal TLS:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; This helps internal services correctly recognize the hostname on the certificate provided by the `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;certdumper&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ```&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ini&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Find this line (it may be commented out):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # ADDITIONAL_SAN=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Change it to:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ADDITIONAL_SAN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;${&lt;/span&gt;&lt;span&gt;MAILCOW_HOSTNAME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Save&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; and close the file. No other changes are needed in this file.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;### 5.3. Activate MTA-STS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;MTA-STS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; (Mail Transfer Agent-Strict Transport Security) is a security standard that helps prevent man-in-the-middle attacks by ensuring emails are transmitted over secure TLS connections.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;table&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;retro-infobox&amp;quot;&lt;/span&gt;&lt;span&gt; width&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span&gt; cellspacing&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span&gt; cellpadding&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;10&amp;quot;&lt;/span&gt;&lt;span&gt; border&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; bgcolor=&amp;quot;#ccffcc&amp;quot; style=&amp;quot;color: #000000; font-weight: bold;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            💡&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            EASIER&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ALTERNATIVE: USE THE MAILCOW UI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/td&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;/tr&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; bgcolor=&amp;quot;#000000&amp;quot; style=&amp;quot;color: #ffffff;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;Instead of creating the policy file by hand, you can navigate to &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;System -&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gt&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Configuration&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; -&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gt&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; MTA-STS&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/strong&amp;gt; in the Mailcow UI after setup. The UI provides a generator that creates the correct policy and DNS records for you, which is less error-prone. The manual method below is still valid if you prefer it.&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/p&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/td&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/tr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/table&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;If&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; you choose the manual route, create the required directory:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;```&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mailcow/data/web/.well-known/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, create the policy file with a simple &lt;code&gt;enforce&lt;/code&gt; policy. This file will be served by Mailcow’s web server.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee /opt/containers/mailcow/data/web/.well-known/mta-sts.txt&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;version: STSv1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;mode: enforce&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;max_age: 15552000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;mx: mail.your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            IMPORTANT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;You must replace &lt;code&gt;your-domain.com&lt;/code&gt; with your actual domain name in the file above. You can do this with the following command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;s/your-domain.com/your-actual-domain.com/g&amp;quot; /opt/containers/mailcow/data/web/.well-known/mta-sts.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;6-launch-mailcow&quot;&gt;6. Launch Mailcow&lt;/h2&gt;
&lt;p&gt;You can now start the Mailcow stack.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mailcow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            TROUBLESHOOTING TIPS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pool Overlaps&lt;/strong&gt;: If you see an error like &lt;code&gt;Pool overlaps with other one on this address space&lt;/code&gt;, another Docker network is using Mailcow’s default IP range. You can fix this permanently by editing &lt;code&gt;mailcow.conf&lt;/code&gt; and setting &lt;code&gt;IPV4_NETWORK&lt;/code&gt; to an unused subnet prefix (e.g., &lt;code&gt;IPV4_NETWORK=172.25.1&lt;/code&gt;). Mailcow will correctly append &lt;code&gt;.0/24&lt;/code&gt; to create the network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAM Usage&lt;/strong&gt;: On a VPS with limited memory, you can disable resource-intensive services by setting &lt;code&gt;SKIP_FTS=y&lt;/code&gt; (disables full-text search in Solr) or &lt;code&gt;SKIP_CLAMD=y&lt;/code&gt; (disables the ClamAV antivirus engine) in &lt;code&gt;mailcow.conf&lt;/code&gt;. This reduces security and functionality, so use it with caution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPv6 Issues&lt;/strong&gt;: Some Mailcow versions had startup issues when &lt;code&gt;ENABLE_IPV6=y&lt;/code&gt; was set. If you face problems, check the official Mailcow blog for release notes and patches.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;7-dns-configuration&quot;&gt;7. DNS Configuration&lt;/h2&gt;
&lt;p&gt;Correct DNS setup is critical for a mail server to function.&lt;/p&gt;
&lt;h3 id=&quot;7-1-reverse-dns-ptr-record&quot;&gt;7.1. Reverse DNS (PTR Record)&lt;/h3&gt;
&lt;p&gt;Your server’s Reverse DNS (PTR) record for both IPv4 and IPv6 must match the hostname you configured in &lt;code&gt;mailcow.conf&lt;/code&gt; (&lt;code&gt;mail.your-domain.com&lt;/code&gt;). This is usually set in your server provider’s control panel and is essential for not being marked as spam, especially by major providers like Gmail.&lt;/p&gt;
&lt;h3 id=&quot;7-2-dns-records&quot;&gt;7.2. DNS Records&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            USING CLOUDFLARE?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If you are using Cloudflare for your DNS, all mail-related records (including &lt;code&gt;mail&lt;/code&gt;, &lt;code&gt;imap&lt;/code&gt;, &lt;code&gt;smtp&lt;/code&gt;, &lt;code&gt;autodiscover&lt;/code&gt;, &lt;code&gt;autoconfig&lt;/code&gt;, and &lt;code&gt;mta-sts&lt;/code&gt;) &lt;strong&gt;must&lt;/strong&gt; be set to “DNS only” (grey cloud). Cloudflare’s proxy (orange cloud) only supports web protocols like HTTP/HTTPS and will break mail services. For more details, see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://developers.cloudflare.com/dns/manage-dns-records/proxied-dns-records/#supported-ports&quot;&gt;official Cloudflare documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;In your domain’s DNS management panel, add the following records. We start with a non-restrictive DMARC policy (&lt;code&gt;p=none&lt;/code&gt;) to prevent legitimate emails from being rejected during the initial setup.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            GMAIL &amp; YAHOO SENDER REQUIREMENTS (2024)
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;As of 2024, major providers like Gmail and Yahoo enforce stricter sender policies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;All Senders&lt;/strong&gt;: Must have either SPF or DKIM configured.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bulk Senders&lt;/strong&gt; (5,000+ emails/day): Must have SPF, DKIM, &lt;strong&gt;and&lt;/strong&gt; a DMARC policy. They also require one-click unsubscribe links and must maintain a low spam complaint rate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Failing to meet these requirements will result in your emails being rejected. For more details, see the official announcements from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://blog.google/products/gmail/gmail-security-authentication-spam-protection/&quot;&gt;Google&lt;/a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://blog.postmaster.yahooinc.com/post/730172167494483968/more-secure-less-spam&quot;&gt;Yahoo&lt;/a&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            DMARC STAGED ROLLOUT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Starting with &lt;code&gt;p=none&lt;/code&gt; is the safest approach. This allows you to monitor email traffic via the reports sent to your &lt;code&gt;rua&lt;/code&gt; address without affecting mail delivery.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Monitor&lt;/strong&gt;: Keep &lt;code&gt;p=none&lt;/code&gt; for a few weeks and analyze the reports to ensure all legitimate sending sources are correctly authenticated with SPF and DKIM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quarantine&lt;/strong&gt;: Once you are confident, switch to &lt;code&gt;p=quarantine&lt;/code&gt;. This tells receiving servers to treat failing emails with suspicion (e.g., by sending them to the spam folder).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reject&lt;/strong&gt;: After another monitoring period, you can move to the final policy, &lt;code&gt;p=reject&lt;/code&gt;, which instructs receivers to block emails that fail DMARC checks.&lt;/li&gt;
&lt;/ol&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;mail&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;your-server-ip&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;mail&lt;/td&gt;&lt;td&gt;AAAA&lt;/td&gt;&lt;td&gt;your-server-ipv6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;autodiscover&lt;/td&gt;&lt;td&gt;CNAME&lt;/td&gt;&lt;td&gt;mail.your-domain.com.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;autoconfig&lt;/td&gt;&lt;td&gt;CNAME&lt;/td&gt;&lt;td&gt;mail.your-domain.com.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;imap&lt;/td&gt;&lt;td&gt;CNAME&lt;/td&gt;&lt;td&gt;mail.your-domain.com.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pop3&lt;/td&gt;&lt;td&gt;CNAME&lt;/td&gt;&lt;td&gt;mail.your-domain.com.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;smtp&lt;/td&gt;&lt;td&gt;CNAME&lt;/td&gt;&lt;td&gt;mail.your-domain.com.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;@&lt;/td&gt;&lt;td&gt;MX 10&lt;/td&gt;&lt;td&gt;mail.your-domain.com.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SPF&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;@&lt;/td&gt;&lt;td&gt;TXT&lt;/td&gt;&lt;td&gt;&lt;code&gt;v=spf1 mx a -all&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            SPF FINE-TUNING
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;v=spf1 mx a -all&lt;/code&gt; record is a safe default. The &lt;code&gt;a&lt;/code&gt; part authorizes the server’s main IP address (from the &lt;code&gt;A&lt;/code&gt; record) to send mail. If you only send mail from Mailcow, you can make this slightly stricter by using &lt;code&gt;v=spf1 mx -all&lt;/code&gt;, which only authorizes servers listed in your &lt;code&gt;MX&lt;/code&gt; records.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;| &lt;strong&gt;DMARC&lt;/strong&gt;            |       |                                              |
| _dmarc               | TXT   | &lt;code&gt;v=DMARC1; p=none; rua=mailto:admin@your-domain.com&lt;/code&gt; |
| &lt;strong&gt;MTA-STS&lt;/strong&gt;          |       |                                              |
| mta-sts              | A     | your-server-ip                               |
| mta-sts              | AAAA  | your-server-ipv6                             |
| _mta-sts             | TXT   | &lt;code&gt;v=STSv1; id=2025091801&lt;/code&gt;                      |
| _smtp._tls           | TXT   | &lt;code&gt;v=TLSRPTv1; rua=mailto:admin@your-domain.com&lt;/code&gt; |
| &lt;strong&gt;Service Records&lt;/strong&gt;  |       |                                              |
| _autodiscover._tcp   | SRV   | &lt;code&gt;0 1 443 mail.your-domain.com.&lt;/code&gt;              |
| _caldavs._tcp        | SRV   | &lt;code&gt;0 1 443 mail.your-domain.com.&lt;/code&gt;              |
| _caldavs._tcp        | TXT   | &lt;code&gt;&quot;path=/SOGo/dav/&quot;&lt;/code&gt;                        |
| _carddavs._tcp       | SRV   | &lt;code&gt;0 1 443 mail.your-domain.com.&lt;/code&gt;              |
| _carddavs._tcp       | TXT   | &lt;code&gt;&quot;path=/SOGo/dav/&quot;&lt;/code&gt;                        |
| _imaps._tcp          | SRV   | &lt;code&gt;0 1 993 mail.your-domain.com.&lt;/code&gt;              |
| _pop3s._tcp          | SRV   | &lt;code&gt;0 1 995 mail.your-domain.com.&lt;/code&gt;              |
| _submission._tcp     | SRV   | &lt;code&gt;0 1 587 mail.your-domain.com.&lt;/code&gt;              |
| _smtps._tcp          | SRV   | &lt;code&gt;0 1 465 mail.your-domain.com.&lt;/code&gt;              |&lt;/p&gt;
&lt;p&gt;A DKIM record will be added later after it’s generated by Mailcow.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            UNUSED SRV RECORDS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This guide only lists SRV records for encrypted services (IMAPS, POP3S, etc.). If you decide not to offer certain services (e.g., POP3), you should also omit their corresponding SRV records to prevent clients from attempting to connect to them.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            DNS RECORD NOTES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A vs. CNAME for &lt;code&gt;mta-sts&lt;/code&gt;&lt;/strong&gt;: We use &lt;code&gt;A&lt;/code&gt;/&lt;code&gt;AAAA&lt;/code&gt; records for &lt;code&gt;mta-sts&lt;/code&gt; pointing directly to the server’s IP. While a &lt;code&gt;CNAME&lt;/code&gt; pointing to &lt;code&gt;mail.your-domain.com&lt;/code&gt; is also valid, using &lt;code&gt;A&lt;/code&gt;/&lt;code&gt;AAAA&lt;/code&gt; records avoids potential edge cases with some DNS resolvers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trailing Dots&lt;/strong&gt;: Note the trailing dot (&lt;code&gt;.&lt;/code&gt;) at the end of hostnames in &lt;code&gt;MX&lt;/code&gt; and &lt;code&gt;SRV&lt;/code&gt; records (e.g., &lt;code&gt;mail.your-domain.com.&lt;/code&gt;). This signifies that the name is fully qualified. Some DNS providers add this automatically, while others require you to add it manually.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;8-firewall-configuration&quot;&gt;8. Firewall Configuration&lt;/h2&gt;
&lt;p&gt;Your firewall must allow traffic on several ports for email services to be reachable.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Port&lt;/th&gt;&lt;th&gt;Service&lt;/th&gt;&lt;th&gt;Protocol&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;25&lt;/td&gt;&lt;td&gt;SMTP&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;587&lt;/td&gt;&lt;td&gt;Submission&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;465&lt;/td&gt;&lt;td&gt;SMTPS&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;143&lt;/td&gt;&lt;td&gt;IMAP&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;993&lt;/td&gt;&lt;td&gt;IMAPS&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;110&lt;/td&gt;&lt;td&gt;POP3&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;995&lt;/td&gt;&lt;td&gt;POP3S&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4190&lt;/td&gt;&lt;td&gt;ManageSieve&lt;/td&gt;&lt;td&gt;TCP&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            PROTOCOL HYGIENE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;For better security, consider disabling protocols you don’t need. For example, if all your clients use IMAP, you can keep the POP3 ports (110, 995) closed. It is also best practice to enforce encrypted connections, favoring Submission (587) and IMAPS (993) over their unencrypted counterparts.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            RESERVED INTERNAL PORTS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Mailcow uses several ports internally (e.g., 8081, 9081, 65510). Avoid using these for your own services on the Docker host to prevent conflicts.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;ufw&lt;/code&gt; to open these ports:&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            DOCKER BYPASSES UFW RULES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;By default, Docker manipulates &lt;code&gt;iptables&lt;/code&gt; directly and &lt;strong&gt;bypasses UFW rules&lt;/strong&gt;, meaning your container ports might be exposed even if &lt;code&gt;ufw&lt;/code&gt; is configured to block them. There are two effective ways to mitigate this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bind Services to Localhost (Recommended)&lt;/strong&gt;: As we did in &lt;code&gt;mailcow.conf&lt;/code&gt; with &lt;code&gt;HTTP_BIND&lt;/code&gt;, binding services to &lt;code&gt;127.0.0.1&lt;/code&gt; ensures they are never exposed externally by Docker. This is the most secure approach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modify UFW’s Configuration&lt;/strong&gt;: For services that must be exposed, you can edit &lt;code&gt;/etc/ufw/after.rules&lt;/code&gt; to correctly manage traffic from Docker’s network. This is more complex but necessary for direct external access. For more details, see the official &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.docker.com/network/packet-filtering-firewalls/&quot;&gt;Docker documentation on packet filtering&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 25/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 587/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 465/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 143/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 993/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 110/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 995/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw allow 4190/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ufw status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;9-initial-mailcow-setup&quot;&gt;9. Initial Mailcow Setup&lt;/h2&gt;
&lt;p&gt;Navigate to your Mailcow UI at &lt;code&gt;https://mail.your-domain.com&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default Username:&lt;/strong&gt; &lt;code&gt;admin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Default Password:&lt;/strong&gt; &lt;code&gt;moohoo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, change the administrator password under &lt;strong&gt;System -&amp;gt; Configuration -&amp;gt; Edit&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;9-1-add-your-domain&quot;&gt;9.1. Add Your Domain&lt;/h3&gt;
&lt;p&gt;Go to &lt;strong&gt;Email -&amp;gt; Configuration&lt;/strong&gt; and click &lt;strong&gt;“Add domain”&lt;/strong&gt;. Enter your main domain (e.g., &lt;code&gt;your-domain.com&lt;/code&gt;, not &lt;code&gt;mail.your-domain.com&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;9-2-generate-dkim-key&quot;&gt;9.2. Generate DKIM Key&lt;/h3&gt;
&lt;p&gt;A DKIM key is essential for email authentication.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;System -&amp;gt; Configuration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Options -&amp;gt; ARC/DKIM keys&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;A 2048-bit key should already be generated for your domain. Copy the public key text from the text box.&lt;/li&gt;
&lt;li&gt;Go back to your DNS provider and add a new TXT record:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;dkim._domainkey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Value:&lt;/strong&gt; Paste the entire copied key, including the &lt;code&gt;v=DKIM1;k=rsa;p=...&lt;/code&gt; part.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            LONG DKIM RECORDS
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Some DNS providers have a 255-character limit for a single TXT record string. If your 2048-bit DKIM key is longer, you may need to split it into multiple quoted strings. Many providers handle this automatically, but if you encounter issues, check your provider&amp;#39;s documentation on how to format long TXT records.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;10-testing-and-verification&quot;&gt;10. Testing and Verification&lt;/h2&gt;
&lt;p&gt;After waiting for DNS propagation, thoroughly test your setup.&lt;/p&gt;
&lt;h3 id=&quot;10-1-internal-dns-and-certificate-check&quot;&gt;10.1. Internal DNS and Certificate Check&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mailcow DNS Check&lt;/strong&gt;: In the Mailcow UI, go to &lt;strong&gt;Email -&amp;gt; Configuration -&amp;gt; DNS&lt;/strong&gt; next to your domain for an internal check of your records.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify Certificates&lt;/strong&gt;: Ensure that the certificates from Traefik have been correctly passed to Mailcow’s services. Run these commands, replacing &lt;code&gt;mail.your-domain.com&lt;/code&gt; with your mail server’s FQDN:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check SMTP certificate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Q&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; s_client&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -starttls&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; smtp&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -crlf -connect&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com:587&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check IMAP certificate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Q&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; s_client&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -starttls&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; imap&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -crlf -connect&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mail.your-domain.com:143&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;In the output, look for a certificate chain issued by a trusted authority. For Let’s Encrypt, the chain typically starts with &lt;code&gt;ISRG Root X1&lt;/code&gt;. The key is to confirm it is &lt;strong&gt;not&lt;/strong&gt; a self-signed certificate. If you see a self-signed certificate (where the issuer matches the subject), it indicates a problem with the &lt;code&gt;certdumper&lt;/code&gt; service or its path mappings. In that case, check the certdumper logs:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/mailcow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose logs certdumper&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;10-2-external-testing-tools&quot;&gt;10.2. External Testing Tools&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;mail-tester.com&lt;/strong&gt;: Send an email to the address provided on their site to get a score out of 10.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mxtoolbox.com&lt;/strong&gt;: Provides various checks for your mail server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;checktls.com/TestReceiver&lt;/strong&gt;: Use this to specifically verify your MTA-STS configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;11-create-mailboxes-and-log-in&quot;&gt;11. Create Mailboxes and Log In&lt;/h2&gt;
&lt;p&gt;Under &lt;strong&gt;Email -&amp;gt; Mailboxes&lt;/strong&gt;, you can add new users. Once a user is created, the primary way to access the webmail interface (SOGo) is by clicking &lt;strong&gt;Apps -&amp;gt; Webmail&lt;/strong&gt; from within the Mailcow UI. While you can also try going directly to &lt;code&gt;https://mail.your-domain.com/SOGo/&lt;/code&gt;, be aware that recent Mailcow versions may redirect unauthenticated access back to the main login page.&lt;/p&gt;
&lt;h2 id=&quot;12-conclusion&quot;&gt;12. Conclusion&lt;/h2&gt;
&lt;p&gt;You have now successfully deployed a full-featured Mailcow e-mail server. By leveraging Docker for containerization and Traefik for reverse proxying and certificate management, you have a secure, robust, and maintainable mail solution. This setup provides you with complete control over your email, enhanced security through features like MTA-STS, and the flexibility to manage multiple domains and users with ease.&lt;/p&gt;
&lt;h2 id=&quot;13-further-reading&quot;&gt;13. Further Reading&lt;/h2&gt;
&lt;p&gt;For more detailed information, refer to the official Mailcow documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reverse Proxy Overview:&lt;/strong&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.mailcow.email/post_installation/reverse-proxy/r_p/&quot;&gt;docs.mailcow.email/post_installation/reverse-proxy/r_p/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IP Bindings:&lt;/strong&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.mailcow.email/&quot;&gt;docs.mailcow.email&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MTA-STS Setup:&lt;/strong&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.mailcow.email/&quot;&gt;docs.mailcow.email&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a href=&quot;https://www.mail-tester.com/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🛡️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;TEST YOUR EMAIL SCORE&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Deploying a Secure Nginx Website with Traefik and Docker Compose</title>
          <pubDate>Wed, 17 Sep 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/nginx-webserver/</link>
          <guid>https://criticalbasics.xyz/posts/nginx-webserver/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/nginx-webserver/">&lt;p&gt;This tutorial explains how to deploy a simple and secure Nginx web server using Docker Compose. This setup is designed to run behind an existing Traefik reverse proxy, providing a robust and easily manageable solution for hosting a static website.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-06-12&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Matrix Federation:&lt;/strong&gt; Corrected the future Matrix &lt;code&gt;.well-known&lt;/code&gt; federation port to &lt;code&gt;8448&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-09-17&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Article created to demonstrate a secure Nginx deployment behind a Traefik v3 stack.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide builds directly upon a previously established secure Docker environment. Before you begin, you must have a fully functional Traefik v3 and CrowdSec stack.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            CRUCIAL PREREQUISITE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This tutorial is part of a series and assumes you have a fully functional Docker environment with Traefik running. You must have already completed the setup described in our previous tutorial:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;../traefik_v3_crowdsec_tutorial/&quot;&gt;Traefik v3 and CrowdSec with Docker Compose: A Modern Security Stack&lt;/a&gt;&lt;/strong&gt;: This is the foundation for our reverse proxy and security.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you haven’t already created the external network for Traefik, do so now:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; network create proxy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;You will also need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker and Docker Compose installed on your server.&lt;/li&gt;
&lt;li&gt;A domain name pointed to your server’s IP address.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; or root access.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-directory-structure&quot;&gt;2. Directory Structure&lt;/h2&gt;
&lt;p&gt;To keep our project organized, we’ll create a dedicated directory for the Nginx service. All subsequent file paths in this guide are relative to this base directory.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create the main directory for your Nginx site&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nginx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nginx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create subdirectories for configuration and website files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir conf html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This structure separates your Nginx configuration from your actual website content.&lt;/p&gt;
&lt;h2 id=&quot;3-configuration-files&quot;&gt;3. Configuration Files&lt;/h2&gt;
&lt;p&gt;Next, we will create the necessary configuration files for Nginx and Docker Compose.&lt;/p&gt;
&lt;h3 id=&quot;3-1-environment-file-env&quot;&gt;3.1. Environment File (&lt;code&gt;.env&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;First, create a &lt;code&gt;.env&lt;/code&gt; file to store your domain name. This makes the configuration cleaner and easier to update.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;DOMAIN_NAME=your-domain.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            IMPORTANT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Replace &lt;code&gt;your-domain.com&lt;/code&gt; with your actual domain name.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-2-docker-compose-file&quot;&gt;3.2. Docker Compose File&lt;/h3&gt;
&lt;p&gt;Now, create the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. It will read the &lt;code&gt;DOMAIN_NAME&lt;/code&gt; variable from your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee docker-compose.yml&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  nginx:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image: nginx:1.27.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    container_name: nginx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    restart: unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./html:/usr/share/nginx/html:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./conf/nginx.conf:/etc/nginx/nginx.conf:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - ./conf/mime.types:/etc/nginx/mime.types:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # --- Routing ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx.rule=Host(`${DOMAIN_NAME}`) || Host(`www.${DOMAIN_NAME}`)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx.entrypoints=websecure&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx.tls=true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx.tls.certresolver=tls_resolver&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # --- Middlewares ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # 1. CORS headers for Matrix federation (defined on-the-fly)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.nginx-cors.headers.accessControlAllowMethods=GET,OPTIONS,PUT,POST&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.nginx-cors.headers.accessControlAllowHeaders=*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.middlewares.nginx-cors.headers.accessControlAllowOriginList=*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # 2. Assignment of all middlewares&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.routers.nginx.middlewares=security-headers@file,crowdsec-bouncer@docker,nginx-cors@docker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # --- Service Definition ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - &amp;quot;traefik.http.services.nginx.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      - proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  proxy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    external: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key Points from this file:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;labels&lt;/code&gt;&lt;/strong&gt;: These are instructions for Traefik. We define routing, TLS, and a chain of middlewares.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;middlewares&lt;/code&gt;&lt;/strong&gt;: We apply three middlewares: &lt;code&gt;security-headers&lt;/code&gt; (from a file), &lt;code&gt;crowdsec-bouncer&lt;/code&gt; (from the Traefik service’s own labels), and &lt;code&gt;nginx-cors&lt;/code&gt;. The &lt;code&gt;nginx-cors&lt;/code&gt; middleware is defined on-the-fly here and is &lt;strong&gt;critical for Matrix federation&lt;/strong&gt;, as it allows other servers to access the &lt;code&gt;.well-known&lt;/code&gt; delegation files. For a standard website without Matrix integration, this middleware and its assignment can be omitted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;volumes&lt;/code&gt;&lt;/strong&gt;: We mount our local &lt;code&gt;html&lt;/code&gt; and &lt;code&gt;conf&lt;/code&gt; directories into the container as read-only (&lt;code&gt;ro&lt;/code&gt;) for better security.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;networks&lt;/code&gt;&lt;/strong&gt;: The service is attached to the external &lt;code&gt;proxy&lt;/code&gt; network, allowing it to communicate with the Traefik container.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-3-nginx-configuration&quot;&gt;3.3. Nginx Configuration&lt;/h3&gt;
&lt;p&gt;Next, create the main Nginx configuration file at &lt;code&gt;/opt/containers/nginx/conf/nginx.conf&lt;/code&gt;. This file controls the behavior of the web server and is optimized for serving a static site with Gzip compression.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee conf/nginx.conf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;worker_processes  2;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;user              www-data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;events {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    use           epoll;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    worker_connections  128;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;http {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    include       /etc/nginx/mime.types;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    default_type  application/octet-stream;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # --- Basic Settings ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    sendfile        on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    tcp_nopush      on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    tcp_nodelay     on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    keepalive_timeout  65;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    types_hash_max_size 2048;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # --- Gzip Settings ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip_disable &amp;quot;msie6&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip_vary on;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip_proxied any;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip_comp_level 6;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip_buffers 16 8k;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip_http_version 1.1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # --- Main Server Block ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    server {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        listen 80;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        server_name _;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        root /usr/share/nginx/html;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        index index.html;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        location / {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            try_files $uri $uri/ =404;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        # --- Future-Proofing for Matrix Synapse ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        location /.well-known/matrix/server {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            return 200 &amp;#39;{&amp;quot;m.server&amp;quot;: &amp;quot;matrix.YOUR_DOMAIN_COM_PLACEHOLDER:8448&amp;quot;}&amp;#39;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            add_header &amp;quot;Content-Type&amp;quot; &amp;quot;application/json&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        location /.well-known/matrix/client {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;             return 200 &amp;#39;{&amp;quot;m.homeserver&amp;quot;: {&amp;quot;base_url&amp;quot;: &amp;quot;https://matrix.YOUR_DOMAIN_COM_PLACEHOLDER&amp;quot;}, &amp;quot;m.identity_server&amp;quot;: {&amp;quot;base_url&amp;quot;: &amp;quot;https://vector.im&amp;quot;}}&amp;#39;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;             add_header &amp;quot;Content-Type&amp;quot; &amp;quot;application/json; charset=utf-8&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;             add_header &amp;quot;Access-Control-Allow-Origin&amp;quot; &amp;quot;*&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        # --- Error Pages ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        error_page 404 /404.html;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        location = /404.html {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            internal;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        error_page 500 502 503 504 /50x.html;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        location = /50x.html {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;            internal;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, read the .env file and use sed to replace the placeholders:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;/span&gt;&lt;span&gt; $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;^#&amp;#39; .env&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; xargs&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;s/YOUR_DOMAIN_COM_PLACEHOLDER/${&lt;/span&gt;&lt;span&gt;DOMAIN_NAME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/g&amp;quot; conf/nginx.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            PREPARING FOR MATRIX SYNAPSE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The &lt;code&gt;location /.well-known/matrix&lt;/code&gt; blocks are included as a forward-thinking measure. They are required for setting up a federated &lt;strong&gt;&lt;a href=&quot;../matrix_synapse_server/&quot;&gt;Matrix Synapse server&lt;/a&gt;&lt;/strong&gt; on your domain. By including them now, you won’t need to reconfigure this Nginx service when you decide to deploy Matrix later. These directives tell Matrix clients and other servers where to find your chat homeserver.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;3-4-mime-types&quot;&gt;3.4. Mime Types&lt;/h3&gt;
&lt;p&gt;Create a &lt;code&gt;mime.types&lt;/code&gt; file at &lt;code&gt;/opt/containers/nginx/conf/mime.types&lt;/code&gt;. This file ensures that Nginx sends the correct &lt;code&gt;Content-Type&lt;/code&gt; header for various file formats, which is particularly important for web fonts and modern web assets.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee conf/mime.types&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;types {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    text/html                                        html htm shtml;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    text/css                                         css;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    text/xml                                         xml;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image/gif                                        gif;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image/jpeg                                       jpeg jpg;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    application/javascript                           js;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    application/atom+xml                             atom;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    application/rss+xml                              rss;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # Fonts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    application/vnd.ms-fontobject                    eot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    font/truetype                                    ttf;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    font/opentype                                    otf;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    font/woff                                        woff;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    font/woff2                                       woff2;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image/svg+xml                                    svg svgz;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image/png                                        png;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    image/x-icon                                     ico;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-5-website-content&quot;&gt;3.5. Website Content&lt;/h3&gt;
&lt;p&gt;Before launching the server, place your website files into the &lt;code&gt;/opt/containers/nginx/html&lt;/code&gt; directory. For a quick test, create a simple &lt;code&gt;index.html&lt;/code&gt; file within it.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create a simple index.html for testing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee html/index.html&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;title&amp;gt;Welcome to My Nginx Site&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;style&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        body { font-family: sans-serif; background-color: #f0f0f0; text-align: center; padding: 50px; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        h1 { color: #333; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;/style&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;h1&amp;gt;Success!&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;p&amp;gt;Your Nginx website is running securely behind Traefik.&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create custom error pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee html/404.html&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;title&amp;gt;404 Not Found&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;h1&amp;gt;404 - Page Not Found&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;p&amp;gt;The page you are looking for does not exist.&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; tee html/50x.html&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;title&amp;gt;Server Error&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;h1&amp;gt;50x - Server Error&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;lt;p&amp;gt;An internal server error occurred.&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;5-launch-and-verify&quot;&gt;5. Launch and Verify&lt;/h2&gt;
&lt;p&gt;With all the files in place, you can start your Nginx container. Use &lt;code&gt;docker compose&lt;/code&gt; for consistency with the main Traefik stack.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Navigate to your project directory if you aren&amp;#39;t already there&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /opt/containers/nginx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Start the service in the background&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; compose up&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can check the status of your new container with &lt;code&gt;docker compose ps&lt;/code&gt;. It should show a state of &lt;code&gt;Up&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, open a web browser and navigate to &lt;code&gt;https://your-domain.com&lt;/code&gt;. You should see the “Success!” message from your &lt;code&gt;index.html&lt;/code&gt; file, served over a secure HTTPS connection managed by Traefik.&lt;/p&gt;
&lt;h2 id=&quot;6-conclusion&quot;&gt;6. Conclusion&lt;/h2&gt;
&lt;p&gt;You have successfully deployed a secure, containerized Nginx web server behind your Traefik and CrowdSec stack. This setup not only serves your static content efficiently but also benefits from centralized TLS management, security headers, and threat protection. Furthermore, it is already prepared for future expansion, such as the addition of a &lt;strong&gt;&lt;a href=&quot;../matrix_synapse_server/&quot;&gt;Matrix Synapse server&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
</description>
      </item>
      <item>
          <title>Secure Server-to-Server File Transfers with rsync and tmux</title>
          <pubDate>Fri, 08 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/server-file-transfer-rsync-tmux/</link>
          <guid>https://criticalbasics.xyz/posts/server-file-transfer-rsync-tmux/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/server-file-transfer-rsync-tmux/">&lt;p&gt;This guide provides a definitive, “terminal-first” approach to transferring large amounts of data directly between two remote servers. By combining the power of &lt;code&gt;rsync&lt;/code&gt; for data synchronization, &lt;code&gt;tmux&lt;/code&gt; for session persistence, and a securely configured SSH deploy key for authentication, you can create a “fire-and-forget” transfer process that is robust, efficient, and secure.&lt;/p&gt;
&lt;p&gt;This method avoids routing traffic through your local machine, saving you bandwidth and making the process immune to local network disconnects.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-08-08&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Article created.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-the-goal-direct-robust-server-to-server-transfers&quot;&gt;1. The Goal: Direct, Robust Server-to-Server Transfers&lt;/h2&gt;
&lt;p&gt;Before we begin, it’s essential to understand the data flow we are building.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            UNDERSTANDING THE ARCHITECTURE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The goal is to initiate a transfer that runs entirely on &lt;strong&gt;Server1&lt;/strong&gt;, pulling data from itself and pushing it directly to &lt;strong&gt;Server2&lt;/strong&gt;. Your local computer is only used to set up the infrastructure and start the process; it can be disconnected immediately afterward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data Flow:&lt;/strong&gt; &lt;code&gt;Server1 (Source)  ---(Data Transfer)---&amp;gt;  Server2 (Destination)&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;2-prerequisites&quot;&gt;2. Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;You have &lt;strong&gt;key-based SSH access&lt;/strong&gt; from your &lt;strong&gt;local computer&lt;/strong&gt; to two Linux servers, &lt;code&gt;Server1&lt;/code&gt; and &lt;code&gt;Server2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Password authentication on your servers is (correctly) disabled.&lt;/li&gt;
&lt;li&gt;You have &lt;code&gt;sudo&lt;/code&gt; or &lt;code&gt;root&lt;/code&gt; privileges on &lt;code&gt;Server1&lt;/code&gt; to install software.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;local-ssh-configuration-for-your-convenience&quot;&gt;Local SSH Configuration (For Your Convenience)&lt;/h3&gt;
&lt;p&gt;Define aliases for your servers in your &lt;strong&gt;local computer’s&lt;/strong&gt; &lt;code&gt;~/.ssh/config&lt;/code&gt; file. This only makes it easier for &lt;em&gt;you&lt;/em&gt; to connect; it does not affect the servers themselves.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# In ~/.ssh/config on your LOCAL machine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Host Server1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    HostName cloud.server1.xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    User your_user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Host Server2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    HostName cloud.server2.xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    User root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Port 2222 &lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Use your actual port&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-the-core-method-building-the-key-infrastructure&quot;&gt;3. The Core Method: Building the Key Infrastructure&lt;/h2&gt;
&lt;p&gt;This is the most critical part of the tutorial. We will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a deploy key on &lt;code&gt;Server1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Configure the SSH client &lt;strong&gt;on &lt;code&gt;Server1&lt;/code&gt;&lt;/strong&gt; so it knows how to find &lt;code&gt;Server2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use our local PC as a trusted intermediary to securely install and restrict the key on &lt;code&gt;Server2&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;3-1-on-server1-create-the-deploy-key&quot;&gt;3.1. On Server1: Create the Deploy Key&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On your local machine, connect to Server1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Server1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Now, on Server1, generate a new, passwordless SSH key pair&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# When prompted for a passphrase, press Enter twice to leave it empty.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh-keygen&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ed25519&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.ssh/id_deploy_to_server2&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;rsync deploy key for server2&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-2-on-server1-configure-its-ssh-client&quot;&gt;3.2. On Server1: Configure its SSH Client&lt;/h3&gt;
&lt;p&gt;We must teach &lt;code&gt;Server1&lt;/code&gt; how to connect to &lt;code&gt;Server2&lt;/code&gt;. We do this by creating a &lt;code&gt;config&lt;/code&gt; file in its &lt;code&gt;.ssh&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On Server1, create and open the config file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nano&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.ssh/config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following configuration. &lt;strong&gt;Replace the values&lt;/strong&gt; with the actual connection details for &lt;code&gt;Server2&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Host Server2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    HostName cloud.server2.xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    User root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Port 2222&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    IdentityFile ~/.ssh/id_deploy_to_server2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IdentityFile&lt;/code&gt;: This line is key. It tells &lt;code&gt;Server1&lt;/code&gt;’s SSH client: “When connecting to the host aliased as ‘Server2’, &lt;strong&gt;always&lt;/strong&gt; use this specific private key.”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Save the file (&lt;code&gt;Ctrl+X&lt;/code&gt;, then &lt;code&gt;Y&lt;/code&gt;, then &lt;code&gt;Enter&lt;/code&gt;) and set the correct permissions:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On Server1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.ssh/config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-3-on-server1-copy-the-public-key-for-transfer&quot;&gt;3.3. On Server1: Copy the Public Key for Transfer&lt;/h3&gt;
&lt;p&gt;Display the public key so you can copy it to your clipboard.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On Server1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.ssh/id_deploy_to_server2.pub&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Action:&lt;/strong&gt; Mark and copy the entire output (the line starting &lt;code&gt;ssh-ed25519 AAAA...&lt;/code&gt;). Then, log out from &lt;code&gt;Server1&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;exit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-4-from-your-local-pc-install-and-restrict-the-key-on-server2&quot;&gt;3.4. From Your Local PC: Install and Restrict the Key on Server2&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 1. On your local PC, append the key to Server2&amp;#39;s authorized_keys.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#    Replace &amp;#39;PASTE_KEY_FROM_CLIPBOARD_HERE&amp;#39; with the key you just copied.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Server2 &amp;quot;echo &amp;#39;PASTE_KEY_FROM_CLIPBOARD_HERE&amp;#39; &amp;gt;&amp;gt; ~/.ssh/authorized_keys&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 2. Now, SSH to Server2 to restrict the key.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Server2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# 3. Once on Server2, open the file for editing.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nano&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.ssh/authorized_keys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the editor, find the key you just added at the bottom of the file. Navigate to the &lt;strong&gt;very beginning&lt;/strong&gt; of that line and prepend the &lt;code&gt;command&lt;/code&gt; restriction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ssh-ed25519 AAAA... rsync deploy key for server2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;After (replace &lt;code&gt;/path/to/destination/&lt;/code&gt; with your actual path!):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;command=&amp;quot;rsync --server -vlogDtpre.iL --partial . /path/to/destination/&amp;quot;,no-port-forwarding,no-x11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAA... rsync deploy key for server2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save the file and exit the editor (&lt;code&gt;Ctrl+X&lt;/code&gt;, then &lt;code&gt;Y&lt;/code&gt;, then &lt;code&gt;Enter&lt;/code&gt;).&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-test-the-connection-and-launch-the-transfer&quot;&gt;4. Test the Connection and Launch the Transfer&lt;/h2&gt;
&lt;h3 id=&quot;4-1-test-the-inter-server-connection&quot;&gt;4.1. Test the Inter-Server Connection&lt;/h3&gt;
&lt;p&gt;This test now verifies that the new configuration on &lt;code&gt;Server1&lt;/code&gt; is working correctly.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On your local PC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Server1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Now, on Server1, this command will work because of the new ~/.ssh/config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Server2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            SUCCESS LOOKS LIKE A FAILURE!
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The terminal may appear to hang and show a message like &lt;code&gt;PTY allocation request failed on channel 0&lt;/code&gt;. This is the &lt;strong&gt;expected and correct behavior!&lt;/strong&gt; It proves that the server has successfully rejected your request for an interactive shell due to our security rule.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Press &lt;code&gt;Ctrl+C&lt;/code&gt;&lt;/strong&gt; to return to the prompt. Your test was successful.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;4-2-launch-the-uninterruptible-transfer&quot;&gt;4.2. Launch the Uninterruptible Transfer&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On Server1, install tmux if you haven&amp;#39;t already&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install tmux&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Start a new tmux session&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;tmux&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; syncJob&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Inside the tmux session, execute the now-simplified rsync command.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# No -e option is needed because Server1&amp;#39;s SSH client is now configured!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;rsync&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -avh --info=progress2 --partial \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  /path/to/source/&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  Server2:/path/to/destination/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-3-detach-and-disconnect&quot;&gt;4.3. Detach and Disconnect&lt;/h3&gt;
&lt;p&gt;The process is now running. Detach from the &lt;code&gt;tmux&lt;/code&gt; session and log out.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Ctrl+b&lt;/code&gt;&lt;/strong&gt;, then &lt;strong&gt;&lt;code&gt;d&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On Server1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;exit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-managing-the-rsync-session&quot;&gt;5. Managing the &lt;code&gt;rsync&lt;/code&gt; Session&lt;/h2&gt;
&lt;p&gt;You can check on, re-attach, or terminate your transfer at any time.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;To check the progress:&lt;/strong&gt; &lt;code&gt;ssh Server1&lt;/code&gt; and then &lt;code&gt;tmux attach -t syncJob&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;To kill the session:&lt;/strong&gt; &lt;code&gt;ssh Server1&lt;/code&gt; and then &lt;code&gt;tmux kill-session -t syncJob&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-quick-troubleshooting&quot;&gt;6. Quick Troubleshooting&lt;/h2&gt;
&lt;div class=&quot;styled-table-container&quot;&gt;
  &lt;table id=&quot;custom-table&quot; &gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;40%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;60%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Problem&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Solution&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;“Could not resolve hostname Server2”&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;The &lt;code&gt;~/.ssh/config&lt;/code&gt; file on &lt;strong&gt;Server1&lt;/strong&gt; is missing, has incorrect permissions (should be 600), or the &lt;code&gt;Host Server2&lt;/code&gt; entry is misspelled.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;“Permission denied (publickey).”&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;The &lt;code&gt;IdentityFile&lt;/code&gt; path in &lt;code&gt;Server1&lt;/code&gt;’s &lt;code&gt;~/.ssh/config&lt;/code&gt; might be wrong. Or, the public key was not correctly added to &lt;code&gt;Server2&lt;/code&gt;’s &lt;code&gt;authorized_keys&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;ssh Server2&lt;/code&gt; test works, but &lt;code&gt;rsync&lt;/code&gt; fails&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Check the &lt;code&gt;User&lt;/code&gt; in &lt;code&gt;Server1&lt;/code&gt;’s &lt;code&gt;~/.ssh/config&lt;/code&gt;. Does that user have permission to write to the destination directory on &lt;code&gt;Server2&lt;/code&gt;? Also, check the path in the &lt;code&gt;command=&lt;/code&gt; restriction.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Files are copied into a nested directory&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;You likely omitted the trailing slash (&lt;code&gt;/&lt;/code&gt;) on your source path. &lt;code&gt;/path/to/source&lt;/code&gt; copies the directory itself, while &lt;code&gt;/path/to/source/&lt;/code&gt; copies its contents.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-conclusion&quot;&gt;7. Conclusion&lt;/h2&gt;
&lt;p&gt;By following this definitive guide, you have built a powerful and professionally architected data transfer system. The key was configuring the client (&lt;code&gt;Server1&lt;/code&gt;) to know how to reach the target (&lt;code&gt;Server2&lt;/code&gt;), a fundamental concept for any automated inter-server task. This setup is ideal for large backups, data migrations, and any scenario where a direct, robust, server-to-server connection is required.&lt;/p&gt;
&lt;a href=&quot;https://www.samba.org/ftp/rsync/rsync.html&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;RSYNC DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/tmux/tmux/wiki&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🛡️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;TMUX WIKI &amp; DOCS&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>A Smart, mimeapps.list-Aware File Opener for Neomutt</title>
          <pubDate>Mon, 04 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/neomutt-file-opener/</link>
          <guid>https://criticalbasics.xyz/posts/neomutt-file-opener/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/neomutt-file-opener/">&lt;p&gt;Tired of being locked into a single default program for your email attachments in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/LukeSmithxyz/mutt-wizard&quot;&gt;Neomutt&lt;/a&gt;? This tutorial will guide you through creating an intelligent file-open-chooser that dynamically reads your system’s &lt;code&gt;mimeapps.list&lt;/code&gt; configuration. With a single keypress, you can select from all associated applications to open any attachment, bringing the flexibility of a file manager like Ranger directly into your email client.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-08-04&lt;/td&gt;&lt;td&gt;Initial version of the tutorial published.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;Before we begin, ensure your system has the necessary software and configuration in place.&lt;/p&gt;
&lt;h3 id=&quot;1-1-required-software&quot;&gt;1.1. Required Software&lt;/h3&gt;
&lt;p&gt;This script relies on a few common command-line utilities.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Arch Linux Installation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; neomutt rofi file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Optional: dmenu as a fallback for rofi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dmenu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;1-2-existing-configuration&quot;&gt;1.2. Existing Configuration&lt;/h3&gt;
&lt;p&gt;You should already have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working Neomutt setup (e.g., one configured with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/LukeSmithxyz/mutt-wizard&quot;&gt;&lt;code&gt;mutt-wizard&lt;/code&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A populated &lt;code&gt;~/.config/mimeapps.list&lt;/code&gt; file with your preferred application associations.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2&quot;&gt;2. The Core Script: &lt;code&gt;file-open-chooser&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This script is the heart of our new functionality. It identifies an attachment’s file type, finds all associated programs from your &lt;code&gt;mimeapps.list&lt;/code&gt;, and presents them in a selection menu.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            BEYOND NEOMUTT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;While we focus on Neomutt here, this script is a full-featured, system-wide file opener. It reads your mimeapps.list and works in any context where files can be piped via stdin - terminal, other mail clients, RSS readers, or custom scripts.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;step-1-create-the-script-s-directory-and-file&quot;&gt;Step 1: Create the Script’s Directory and File&lt;/h3&gt;
&lt;p&gt;To keep your scripts organized, we will create a dedicated folder and the script file within it.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create the subdirectory for our project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/Scripts/file-open-chooser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create the script file itself&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/Scripts/file-open-chooser/file-open-chooser.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, open the file &lt;code&gt;~/Scripts/file-open-chooser/file-open-chooser.sh&lt;/code&gt; and paste the entire content below into it.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set -euo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Create a temporary file to hold the attachment content piped from Neomutt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tempfile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tempfile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Determine the MIME type of the temporary file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mimetype&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --mime-type -b&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tempfile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Function to extract available programs from mimeapps.list ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;get_programs_for_mime&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; mime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Read from both [Default Applications] and [Added Associations] sections&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default Applications&amp;quot; &amp;quot;Added Associations&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^\[&lt;/span&gt;&lt;span&gt;$section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;\]&amp;quot; ~/.config/mimeapps.list&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;            # Use awk to find and print programs for the given MIME type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            apps&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;awk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; section=&amp;quot;&lt;/span&gt;&lt;span&gt;$section&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mime=&amp;quot;&lt;/span&gt;&lt;span&gt;$mime&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                /^\[.*\]/ { current_section = $0; gsub(/[\[\]]/, &amp;quot;&amp;quot;, current_section) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                current_section == section &amp;amp;&amp;amp; $0 ~ &amp;quot;^&amp;quot; mime &amp;quot;=&amp;quot; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    sub(&amp;quot;^&amp;quot; mime &amp;quot;=&amp;quot;, &amp;quot;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    gsub(/;/, &amp;quot;\n&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                    print&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                }&amp;#39; ~/.config/mimeapps.list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$apps&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$apps&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Always include a &amp;quot;Default&amp;quot; option to use the system&amp;#39;s xdg-open&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Function to convert a .desktop file name to a human-readable application name ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;desktop_to_name&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; desktop&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    local&lt;/span&gt;&lt;span&gt; desktop_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Search for the .desktop file in standard system locations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; dir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.local/share/applications /usr/share/applications /usr/local/share/applications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/&lt;/span&gt;&lt;span&gt;$desktop&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            desktop_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$dir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/&lt;/span&gt;&lt;span&gt;$desktop&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$desktop_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Extract the &amp;#39;Name=&amp;#39; field from the .desktop file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;^Name=&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$desktop_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f2-&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;$desktop&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Fallback to the filename if Name is not found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$desktop&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Main Logic ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Collect a unique, sorted list of programs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;programs&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;get_programs_for_mime&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$mimetype&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;display_programs&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Build the display list with readable names&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; program&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$program&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        display_programs&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$display_programs$program&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;\n&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        readable_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;desktop_to_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$program&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        display_programs&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$display_programs$readable_name&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; (&lt;/span&gt;&lt;span&gt;$program&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)\n&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done &amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$programs&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Show the selection menu using rofi, dmenu, or a terminal prompt as fallback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;choice&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Initialize variable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rofi&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    choice&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$display_programs&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rofi&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -dmenu -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Open &lt;/span&gt;&lt;span&gt;$mimetype&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; with:&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;elif&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; command -v&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dmenu&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    choice&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$display_programs&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; dmenu&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Open &lt;/span&gt;&lt;span&gt;$mimetype&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; with:&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Choose program to open &lt;/span&gt;&lt;span&gt;$mimetype&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; file:&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$display_programs&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; nl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    read -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Enter choice number: &amp;quot; num&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    choice&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$display_programs&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;num&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}p&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Exit if the user cancelled the selection (e.g., by pressing Esc in rofi)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tempfile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Execute the chosen program&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Default&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    setsid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; xdg-open &amp;quot;&lt;/span&gt;&lt;span&gt;$tempfile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Extract the .desktop filename from the selection (e.g., from &amp;quot;Okular (org.kde.okular.desktop)&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    desktop_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;s/.*(\(.*\))/\1/&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$desktop_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ] &amp;amp;&amp;amp; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$desktop_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Use gtk-launch for .desktop files, as it&amp;#39;s the proper way to launch them&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        setsid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gtk-launch &amp;quot;&lt;/span&gt;&lt;span&gt;$desktop_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$tempfile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Fallback to xdg-open if something went wrong&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        setsid&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; xdg-open &amp;quot;&lt;/span&gt;&lt;span&gt;$tempfile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Clean up the temporary file after a delay to give the program time to open it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 60&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$tempfile&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;) &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-2-make-the-script-executable&quot;&gt;Step 2: Make the Script Executable&lt;/h3&gt;
&lt;p&gt;Your shell needs permission to run the script file.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +x ~/Scripts/file-open-chooser/file-open-chooser.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3&quot;&gt;3. Neomutt Integration&lt;/h2&gt;
&lt;p&gt;Now, let’s teach Neomutt our new trick. We will bind the &lt;code&gt;o&lt;/code&gt; key (for “open”) in the attachment view to execute our script directly.&lt;/p&gt;
&lt;p&gt;Add the following line to your Neomutt configuration file (e.g., &lt;code&gt;~/.config/mutt/muttrc&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add a macro to the attachment menu (key &amp;#39;o&amp;#39;) to pipe the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# attachment to our script by calling it with its full path.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;macro attach o &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;lt;pipe-entry&amp;gt;bash $HOME/Scripts/file-open-chooser/file-open-chooser.sh&amp;lt;enter&amp;gt;&amp;quot; &amp;quot;Choose program to open attachment&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHY &#39;BASH $HOME/...&#39;?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;By explicitly calling &lt;code&gt;bash&lt;/code&gt;, we ensure the script is executed with the Bash interpreter. Using &lt;code&gt;$HOME&lt;/code&gt; instead of &lt;code&gt;~&lt;/code&gt; is a good practice inside configurations, as it’s more robustly expanded in different contexts.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-4&quot;&gt;4. Usage in Neomutt&lt;/h2&gt;
&lt;p&gt;Your new workflow is simple and efficient:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to an email with an attachment.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;v&lt;/code&gt; to open the attachment view.&lt;/li&gt;
&lt;li&gt;Use the arrow keys to select the desired attachment.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;o&lt;/code&gt; (our new macro).&lt;/li&gt;
&lt;li&gt;A Rofi (or dmenu) window will appear, listing all compatible programs.&lt;/li&gt;
&lt;li&gt;Select a program, and the file will open.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Example Workflows:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PDF Attachment&lt;/strong&gt; → &lt;code&gt;o&lt;/code&gt; → Choose between Okular, Zathura, Evince…&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image Attachment&lt;/strong&gt; → &lt;code&gt;o&lt;/code&gt; → Choose between Viewnior, GIMP, Inkscape…&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video Attachment&lt;/strong&gt; → &lt;code&gt;o&lt;/code&gt; → Choose between MPV, VLC…&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-5&quot;&gt;5. Customization&lt;/h2&gt;
&lt;p&gt;To add a new program to the list for a specific file type, simply edit your &lt;code&gt;~/.config/mimeapps.list&lt;/code&gt; file. The changes are picked up by the script immediately, with no need to restart anything!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example &lt;code&gt;[Added Associations]&lt;/code&gt; section:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Added Associations]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;application/&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pdf&lt;/span&gt;&lt;span&gt;=org.kde.okular.desktop&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;;org.pwmt.zathura.desktop;org.gnome.Evince.desktop;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;image/&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;jpeg&lt;/span&gt;&lt;span&gt;=viewnior.desktop&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;;gimp.desktop;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;another-useful-keybinding&quot;&gt;Another Useful Keybinding&lt;/h3&gt;
&lt;p&gt;You can still define a separate shortcut to &lt;em&gt;always&lt;/em&gt; use the default system application without seeing the menu.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add this to your muttrc. &amp;#39;O&amp;#39; (Shift+o) will open with the default handler.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;macro attach O &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;lt;pipe-entry&amp;gt;xdg-open&amp;lt;enter&amp;gt;&amp;quot; &amp;quot;Open with default application&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-6&quot;&gt;6. Troubleshooting&lt;/h2&gt;
&lt;p&gt;If things don’t work as expected, here are some common issues and their solutions.&lt;/p&gt;
&lt;div class=&quot;styled-table-container&quot;&gt;
  &lt;table id=&quot;custom-table&quot; &gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;40%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;60%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Problem&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Solution&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Permission denied error&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;The script is likely not executable. Run &lt;code&gt;chmod +x ~/Scripts/file-open-chooser/file-open-chooser.sh&lt;/code&gt; again to be sure.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;File not found error&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Double-check the path in your Neomutt macro. Make sure it exactly matches the location of your script. Verify with &lt;code&gt;ls -l ~/Scripts/file-open-chooser/file-open-chooser.sh&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Rofi/dmenu does not start&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Test &lt;code&gt;rofi&lt;/code&gt; directly by running &lt;code&gt;rofi -show run&lt;/code&gt;. If it fails, check for error messages. Ensure it’s installed. The script should fall back to a terminal prompt if &lt;code&gt;rofi&lt;/code&gt; is missing.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Incorrect or no programs listed&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Test the MIME type detection with &lt;code&gt;file --mime-type -b /path/to/some/file.pdf&lt;/code&gt;. Check your &lt;code&gt;~/.config/mimeapps.list&lt;/code&gt; to ensure the associations for that MIME type are correct.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-conclusion&quot;&gt;7. Conclusion&lt;/h2&gt;
&lt;p&gt;By implementing this file-open-chooser, you’ve significantly enhanced Neomutt’s capabilities. Your setup now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Leverages your existing &lt;code&gt;mimeapps.list&lt;/code&gt; configuration without duplication.&lt;/li&gt;
&lt;li&gt;✅ Works universally with any file type.&lt;/li&gt;
&lt;li&gt;✅ Provides flexible application choices with a single keypress.&lt;/li&gt;
&lt;li&gt;✅ Integrates elegantly with modern tools like Rofi.&lt;/li&gt;
&lt;li&gt;✅ Is robust, with fallbacks for different system configurations.&lt;/li&gt;
&lt;li&gt;✅ Is easy to set up with a direct, simple configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You now have the same power and flexibility to open files in your email client as you do in your file manager.&lt;/p&gt;
&lt;a href=&quot;https://neomutt.org/guide/advanced-usage#using-external-programs&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;NEOMUTT DOCS: EXTERNAL PROGRAMS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/davatorium/rofi&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🚀&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ROFI ON GITHUB&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Guide: NVIDIA Legacy Drivers &amp; Multi-Monitor Setup on a ThinkPad W520 (Arch Linux)</title>
          <pubDate>Wed, 30 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/thinkpad-w520-nvidia-multi-monitor/</link>
          <guid>https://criticalbasics.xyz/posts/thinkpad-w520-nvidia-multi-monitor/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/thinkpad-w520-nvidia-multi-monitor/">&lt;p&gt;This tutorial walks you through the process of setting up a &lt;strong&gt;ThinkPad W520&lt;/strong&gt; to run exclusively on its discrete NVIDIA GPU. This is essential for using external monitors connected via the docking station and achieving a stable, high-performance desktop environment on Arch Linux with the i3 window manager.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            THE GOAL
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;The primary objective is to enable the NVIDIA Quadro 1000M/2000M GPU in “Discrete Graphics” mode, install the required legacy &lt;code&gt;nvidia-390xx&lt;/code&gt; driver, and configure the system for a stable multi-monitor experience without the freezes commonly caused by compositors like &lt;code&gt;picom&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-07-29&lt;/td&gt;&lt;td&gt;Initial version of the guide created.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-correct-bios-configuration&quot;&gt;1. Correct BIOS Configuration&lt;/h2&gt;
&lt;p&gt;First, we need to instruct the system to use only the NVIDIA GPU, bypassing the integrated Intel graphics.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press &lt;strong&gt;F1&lt;/strong&gt; during startup to enter the BIOS setup utility.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;code&gt;Config&lt;/code&gt; → &lt;code&gt;Display&lt;/code&gt; menu.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Graphics Device&lt;/strong&gt; option to &lt;strong&gt;Discrete Graphics&lt;/strong&gt;. Do not use “Optimus” or “Integrated Graphics.”&lt;/li&gt;
&lt;li&gt;If the option exists, disable &lt;code&gt;OS Detection for Optimus&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Save your changes and exit the BIOS. The system will now reboot.&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            WHY DISCRETE GRAPHICS?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;On the ThinkPad W520, the physical display outputs (DisplayPort, DVI) on the laptop and its docking station are wired directly to the NVIDIA GPU. They will not function if the system is running on integrated graphics.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-installing-the-nvidia-legacy-driver&quot;&gt;2. Installing the NVIDIA Legacy Driver&lt;/h2&gt;
&lt;p&gt;The NVIDIA Quadro 1000M/2000M GPU found in the W520 belongs to the “Fermi” architecture. Mainline NVIDIA drivers no longer support it, so we must install the &lt;code&gt;nvidia-390xx&lt;/code&gt; legacy driver from the Arch User Repository (AUR).&lt;/p&gt;
&lt;h3 id=&quot;2-1-install-an-aur-helper-yay&quot;&gt;2.1. Install an AUR Helper (yay)&lt;/h3&gt;
&lt;p&gt;If you don’t already have an AUR helper, &lt;code&gt;yay&lt;/code&gt; is a popular choice.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S --needed&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git base-devel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone https://aur.archlinux.org/yay.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; yay&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;makepkg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -si&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-2-install-the-nvidia-390xx-driver-from-the-aur&quot;&gt;2.2. Install the NVIDIA 390xx Driver from the AUR&lt;/h3&gt;
&lt;p&gt;Now, use your AUR helper to install the driver and its utilities.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nvidia-390xx-dkms nvidia-390xx-utils&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;-dkms&lt;/code&gt; package ensures that the NVIDIA kernel module is automatically rebuilt every time your Linux kernel is updated, which prevents breakage.&lt;/li&gt;
&lt;li&gt;During the installation, if prompted, allow the installer to blacklist the open-source &lt;code&gt;nouveau&lt;/code&gt; driver, as it conflicts with the proprietary NVIDIA driver.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-3-ensure-kernel-headers-are-present&quot;&gt;2.3. Ensure Kernel Headers are Present&lt;/h3&gt;
&lt;p&gt;DKMS requires kernel headers to build modules. Install them if they are not already on your system.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; linux-headers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installation, you can run &lt;code&gt;sudo dkms autoinstall&lt;/code&gt; to manually rebuild the module if needed.&lt;/p&gt;
&lt;h3 id=&quot;2-4-reboot-and-verify&quot;&gt;2.4. Reboot and Verify&lt;/h3&gt;
&lt;p&gt;A reboot is necessary to load the new kernel module.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reboot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After rebooting, check if the NVIDIA GPU is active and the driver is loaded correctly by running:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nvidia-smi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If this command displays your GPU details and driver version, the installation was successful.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-minimal-xorg-configuration&quot;&gt;3. Minimal Xorg Configuration&lt;/h2&gt;
&lt;p&gt;To ensure the X server starts correctly, we will create a minimal configuration file.&lt;/p&gt;
&lt;p&gt;Create the directory if it doesn’t exist:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /etc/X11/xorg.conf.d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create and edit the configuration file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nano /etc/X11/xorg.conf.d/20-nvidia.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following content to the file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Section &amp;quot;Device&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Identifier &amp;quot;NVIDIA Card&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Driver &amp;quot;nvidia&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Option &amp;quot;AllowEmptyInitialConfiguration&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EndSection&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reboot your system one more time. After this, Xorg should correctly detect all connected displays (both the internal laptop screen and any external monitors) and run them at their native resolutions.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-taming-the-compositor-picom&quot;&gt;4. Taming the Compositor (picom)&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;nvidia-390xx&lt;/code&gt; driver can have stability issues with modern compositors like &lt;code&gt;picom&lt;/code&gt;, often causing applications like &lt;code&gt;rofi&lt;/code&gt; or terminal emulators to freeze the entire desktop. Here are two solutions.&lt;/p&gt;
&lt;h3 id=&quot;4-1-the-stable-solution-configure-picom&quot;&gt;4.1. The Stable Solution: Configure picom&lt;/h3&gt;
&lt;p&gt;You can make &lt;code&gt;picom&lt;/code&gt; more stable by changing its rendering backend.&lt;/p&gt;
&lt;p&gt;Open your &lt;code&gt;picom&lt;/code&gt; configuration file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nano&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/picom/picom.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Find and set the following lines:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;backend = &amp;quot;xrender&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vsync = false;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;xrender&lt;/code&gt; backend uses CPU-based rendering. While it may be slightly less performant than the GPU-based GLX backend, it is significantly more stable with this legacy driver.&lt;/p&gt;
&lt;h3 id=&quot;4-2-the-rock-solid-alternative-disable-picom&quot;&gt;4.2. The Rock-Solid Alternative: Disable picom&lt;/h3&gt;
&lt;p&gt;If you don’t need transparency or other compositor effects, the most stable option is to disable &lt;code&gt;picom&lt;/code&gt; entirely.&lt;/p&gt;
&lt;p&gt;First, stop any running instance:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;killall&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; picom&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, prevent it from starting automatically by commenting out or deleting the relevant line in your i3 config (&lt;code&gt;~/.config/i3/config&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# exec --no-startup-id picom&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            ACHIEVING TEAR-FREE VIDEO WITHOUT A COMPOSITOR
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;You can still get a tear-free experience by enabling the “Force Full Composition Pipeline” option in the NVIDIA settings.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;nvidia-settings&lt;/code&gt; from the terminal.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;em&gt;X Server Display Configuration&lt;/em&gt; → &lt;em&gt;Advanced&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Check the box for &lt;strong&gt;Force Full Composition Pipeline&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Apply&lt;/strong&gt;, and then save the configuration by running &lt;code&gt;sudo nvidia-settings --write-config&lt;/code&gt;. This will make the setting persistent across reboots.&lt;/li&gt;
&lt;/ol&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-multi-monitor-autostart-in-i3&quot;&gt;5. Multi-Monitor Autostart in i3&lt;/h2&gt;
&lt;p&gt;To have i3 automatically arrange your monitors every time it starts, create a simple shell script.&lt;/p&gt;
&lt;p&gt;First, create a directory for your layout scripts:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.screenlayout&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the script:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nano&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.screenlayout/monitors.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add your &lt;code&gt;xrandr&lt;/code&gt; command to the script. Use the &lt;code&gt;xrandr&lt;/code&gt; command with no arguments to find the names of your connected outputs (e.g., &lt;code&gt;eDP-1&lt;/code&gt;, &lt;code&gt;DP-1&lt;/code&gt;, &lt;code&gt;DP-5&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;xrandr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --output&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; eDP-1&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --primary --mode&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1920x1080&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --pos 0x0 --rotate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; normal&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;       --output&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; DP-1&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --mode&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; 1920x1080&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --right-of&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; eDP-1&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rotate&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; normal&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the script executable:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +x ~/.screenlayout/monitors.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, add this script to your i3 config to execute it on startup:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# In ~/.config/i3/config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exec --no-startup-id ~/.screenlayout/monitors.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;you-re-all-set&quot;&gt;You’re All Set!&lt;/h2&gt;
&lt;p&gt;Congratulations! You should now have a fully functional and stable setup.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your ThinkPad W520 is running on its powerful NVIDIA GPU.&lt;/li&gt;
&lt;li&gt;External monitors connected via the dock are recognized and working.&lt;/li&gt;
&lt;li&gt;Desktop freezes caused by the compositor have been resolved.&lt;/li&gt;
&lt;li&gt;Your i3 session automatically configures your monitor layout on startup.&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Efficient File Compression in Ranger File Manager</title>
          <pubDate>Fri, 18 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/ranger-compression-workflow/</link>
          <guid>https://criticalbasics.xyz/posts/ranger-compression-workflow/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/ranger-compression-workflow/">&lt;p&gt;Terminal file managers like ranger offer powerful ways to manage your files efficiently. This guide shows you how to enhance ranger with custom commands for compressing files into various archive formats directly from the file manager interface. This is part of a series of guides on extending ranger’s functionality.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-07-18&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Created guide for compression workflow in ranger&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;Before we begin, make sure you have the following tools installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ranger&lt;/strong&gt;: The terminal file manager&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;atool&lt;/strong&gt;: A script for managing file archives of various types&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Archive utilities&lt;/strong&gt;: While atool is a wrapper, you’ll need the actual compression tools installed:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;zip&lt;/strong&gt;, &lt;strong&gt;unzip&lt;/strong&gt;: For .zip archives&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tar&lt;/strong&gt;: For .tar, .tar.gz, .tar.bz2 archives&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;p7zip-full&lt;/strong&gt; (Debian/Ubuntu) or &lt;strong&gt;p7zip&lt;/strong&gt; (Arch/Fedora): For .7z archives&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rar&lt;/strong&gt;, &lt;strong&gt;unrar&lt;/strong&gt;: For .rar archives&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;installation-on-various-distributions&quot;&gt;Installation on Various Distributions&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Debian/Ubuntu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install ranger atool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Arch Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ranger atool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Fedora&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dnf install ranger atool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;atool&lt;/code&gt; package provides commands like &lt;code&gt;apack&lt;/code&gt; (for creating archives) and &lt;code&gt;aunpack&lt;/code&gt; (for extracting archives), which we’ll use in our custom ranger commands.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-creating-the-custom-compress-command&quot;&gt;2. Creating the Custom compress Command&lt;/h2&gt;
&lt;p&gt;The integration requires adding a custom command to ranger that will use &lt;code&gt;apack&lt;/code&gt; to compress selected files into an archive.&lt;/p&gt;
&lt;h3 id=&quot;2-1-create-or-edit-commands-py&quot;&gt;2.1. Create or Edit commands.py&lt;/h3&gt;
&lt;p&gt;First, navigate to your ranger configuration directory and create or edit the &lt;code&gt;commands.py&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/commands.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t have a &lt;code&gt;commands.py&lt;/code&gt; file yet, you can generate a template with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --copy-config=commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-2-add-the-compress-command&quot;&gt;2.2. Add the compress Command&lt;/h3&gt;
&lt;p&gt;Open the &lt;code&gt;commands.py&lt;/code&gt; file in your favorite text editor and add the following code:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;from&lt;/span&gt;&lt;span&gt; ranger.core.loader&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; import&lt;/span&gt;&lt;span&gt; CommandLoader&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; compress&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Command&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot; Compress marked files to current directory &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        cwd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.fm.thisdir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        marked_files&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cwd.get_selection()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; marked_files:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; refresh&lt;/span&gt;&lt;span&gt;(_):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            cwd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.fm.get_directory(original_path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            cwd.load_content()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        original_path&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cwd.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.line.split()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        au_flags&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; parts[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;/span&gt;&lt;span&gt;:]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Compressing to: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; os.path.basename(parts[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        obj&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; CommandLoader(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;apack&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; au_flags&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                [os.path.relpath(f.path, cwd.path)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; marked_files],&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;descr,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; read&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        obj.signal_bind(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;after&amp;#39;&lt;/span&gt;&lt;span&gt;, refresh)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        self&lt;/span&gt;&lt;span&gt;.fm.loader.add(obj)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tab&lt;/span&gt;&lt;span&gt;(self, tabnum):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot; Complete with current folder name &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        extension&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.zip&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.tar.gz&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.rar&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.7z&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;compress &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; os.path.basename(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;self&lt;/span&gt;&lt;span&gt;.fm.thisdir.path)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; extension]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Take the marked files in ranger&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;apack&lt;/code&gt; to compress them into an archive&lt;/li&gt;
&lt;li&gt;Refresh the directory view after compression&lt;/li&gt;
&lt;li&gt;Provide tab completion for common archive formats&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-adding-an-extract-command-optional&quot;&gt;3. Adding an Extract Command (Optional)&lt;/h2&gt;
&lt;p&gt;For a complete compression workflow, you might also want to add an extraction command. Add this to your &lt;code&gt;commands.py&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; extract_here&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Command&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot; Extract selected files to current directory &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        cwd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.fm.thisdir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        marked_files&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cwd.get_selection()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; marked_files:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; refresh&lt;/span&gt;&lt;span&gt;(_):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            cwd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.fm.get_directory(original_path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            cwd.load_content()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        original_path&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cwd.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        au_flags&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-X&amp;#39;&lt;/span&gt;&lt;span&gt;, cwd.path]&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Extract to current directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        au_flags&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;/span&gt;&lt;span&gt;.line.split()[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;/span&gt;&lt;span&gt;:]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        au_flags&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;-e&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        self&lt;/span&gt;&lt;span&gt;.fm.copy_buffer.clear()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        self&lt;/span&gt;&lt;span&gt;.fm.cut_buffer&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; len&lt;/span&gt;&lt;span&gt;(marked_files)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;extracting: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; os.path.basename(marked_files[&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span&gt;].path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;extracting &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; files&amp;quot;&lt;/span&gt;&lt;span&gt;.format(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;len&lt;/span&gt;&lt;span&gt;(marked_files))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        obj&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; CommandLoader(&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;aunpack&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; au_flags&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                [f.path&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; marked_files],&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; descr&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;descr,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; read&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        obj.signal_bind(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;after&amp;#39;&lt;/span&gt;&lt;span&gt;, refresh)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        self&lt;/span&gt;&lt;span&gt;.fm.loader.add(obj)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-creating-keyboard-shortcuts&quot;&gt;4. Creating Keyboard Shortcuts&lt;/h2&gt;
&lt;p&gt;Now that we have our custom commands, let’s create keyboard shortcuts to invoke them easily.&lt;/p&gt;
&lt;h3 id=&quot;4-1-edit-rc-conf&quot;&gt;4.1. Edit rc.conf&lt;/h3&gt;
&lt;p&gt;Open your ranger configuration file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;vim&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/rc.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t have this file yet, you can generate it with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --copy-config=rc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-add-the-keyboard-mappings&quot;&gt;4.2. Add the Keyboard Mappings&lt;/h3&gt;
&lt;p&gt;Add the following lines to map the commands to keyboard shortcuts:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Compression and extraction&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map cc console compress%space&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map cx extract_here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With these shortcuts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cc&lt;/code&gt; will start the compress command and wait for you to specify the archive name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cx&lt;/code&gt; will extract the selected archive in the current directory&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Shortcut&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Compress selected files into an archive&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cx&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Extract selected archive in the current directory&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-advanced-configuration&quot;&gt;5. Advanced Configuration&lt;/h2&gt;
&lt;h3 id=&quot;5-1-customize-archive-formats&quot;&gt;5.1. Customize Archive Formats&lt;/h3&gt;
&lt;p&gt;You can modify the list of supported archive extensions in the &lt;code&gt;tab&lt;/code&gt; method of the &lt;code&gt;compress&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tab&lt;/span&gt;&lt;span&gt;(self, tabnum):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot; Complete with current folder name &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    extension&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.zip&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.tar.gz&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.tar.bz2&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.tar.xz&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.rar&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.7z&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;compress &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; os.path.basename(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;self&lt;/span&gt;&lt;span&gt;.fm.thisdir.path)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; extension]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add or remove archive formats based on your needs and installed utilities.&lt;/p&gt;
&lt;h3 id=&quot;5-2-add-compression-options&quot;&gt;5.2. Add Compression Options&lt;/h3&gt;
&lt;p&gt;You can enhance the &lt;code&gt;compress&lt;/code&gt; command to support additional options like compression level:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tab&lt;/span&gt;&lt;span&gt;(self, tabnum):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot; Complete with current folder name and compression options &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    extension&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.zip&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.tar.gz&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.rar&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.7z&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    base_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.path.basename(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;self&lt;/span&gt;&lt;span&gt;.fm.thisdir.path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Basic archive names&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    options&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;compress &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; base_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; extension]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Add options with compression levels for zip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; tabnum&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        options&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;compress &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; base_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.zip -mx=9&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Maximum compression&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        options&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;compress &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span&gt; base_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.zip -mx=1&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Fastest compression&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; options&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;5-3-exclude-certain-files&quot;&gt;5.3. Exclude Certain Files&lt;/h3&gt;
&lt;p&gt;You might want to exclude certain files from compression (like temporary files or already compressed files). You can modify the &lt;code&gt;execute&lt;/code&gt; method to filter the marked files:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;marked_files&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; cwd.get_selection()&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; if not&lt;/span&gt;&lt;span&gt; f.path.endswith((&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.zip&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.rar&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.7z&amp;#39;&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-usage&quot;&gt;6. Usage&lt;/h2&gt;
&lt;p&gt;Once everything is set up, you can use your new compression workflow:&lt;/p&gt;
&lt;h3 id=&quot;6-1-creating-archives&quot;&gt;6.1. Creating Archives&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open ranger in your terminal&lt;/li&gt;
&lt;li&gt;Navigate to the directory containing files you want to compress&lt;/li&gt;
&lt;li&gt;Select files using the &lt;code&gt;space&lt;/code&gt; key (or select a single file with the cursor)&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;cc&lt;/code&gt; to start the compress command&lt;/li&gt;
&lt;li&gt;Type the archive name or press &lt;code&gt;Tab&lt;/code&gt; to auto-complete with suggested formats&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Enter&lt;/code&gt; to create the archive&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;6-2-extracting-archives&quot;&gt;6.2. Extracting Archives&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to an archive file or select it&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;cx&lt;/code&gt; to extract its contents to the current directory&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-practical-examples&quot;&gt;7. Practical Examples&lt;/h2&gt;
&lt;h3 id=&quot;7-1-backup-workflow&quot;&gt;7.1. Backup Workflow&lt;/h3&gt;
&lt;p&gt;Create quick backups of important directories:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to a project folder&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;cc&lt;/code&gt; then &lt;code&gt;Tab&lt;/code&gt; to get suggestions&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;.tar.gz&lt;/code&gt; format for good compression&lt;/li&gt;
&lt;li&gt;Add a date to the filename: &lt;code&gt;project-backup-2025-07-18.tar.gz&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;7-2-sharing-files&quot;&gt;7.2. Sharing Files&lt;/h3&gt;
&lt;p&gt;Compress files for sharing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select multiple files with &lt;code&gt;space&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;cc&lt;/code&gt; and create a &lt;code&gt;.zip&lt;/code&gt; file (most compatible format)&lt;/li&gt;
&lt;li&gt;The archive is ready to be emailed or transferred&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;7-3-working-with-different-archive-types&quot;&gt;7.3. Working with Different Archive Types&lt;/h3&gt;
&lt;p&gt;The workflow supports various archive formats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.zip&lt;/code&gt; - Good compatibility across platforms&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.tar.gz&lt;/code&gt; - Better compression, common on Linux&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.7z&lt;/code&gt; - Best compression ratio&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.rar&lt;/code&gt; - Good for split archives&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;8-troubleshooting&quot;&gt;8. Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;8-1-command-not-found&quot;&gt;8.1. Command Not Found&lt;/h3&gt;
&lt;p&gt;If you get a “Command not found” error when trying to use the shortcut:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure you’ve saved the &lt;code&gt;commands.py&lt;/code&gt; file correctly&lt;/li&gt;
&lt;li&gt;Restart ranger to load the new command&lt;/li&gt;
&lt;li&gt;Check that &lt;code&gt;atool&lt;/code&gt; is installed and in your PATH&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;8-2-compression-fails&quot;&gt;8.2. Compression Fails&lt;/h3&gt;
&lt;p&gt;If compression fails:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check if you have the appropriate compression tools installed&lt;/li&gt;
&lt;li&gt;Verify that you have write permissions in the current directory&lt;/li&gt;
&lt;li&gt;Make sure you have enough disk space&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Try running &lt;code&gt;apack&lt;/code&gt; directly to see if it works outside of ranger:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;apack&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; archive.zip file1 file2 file3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;8-3-file-not-found-errors&quot;&gt;8.3. File Not Found Errors&lt;/h3&gt;
&lt;p&gt;If you get “file not found” errors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure you’re not trying to compress files with special characters in their names&lt;/li&gt;
&lt;li&gt;Check if the paths are correct&lt;/li&gt;
&lt;li&gt;Try using relative paths instead of absolute paths&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With this compression workflow integration, you’ve enhanced ranger’s capabilities for working with archives:&lt;/p&gt;
&lt;p&gt;✅ Quick compression of files with just a few keystrokes
✅ Support for multiple archive formats
✅ Tab completion for common archive types
✅ Easy extraction of archives
✅ Seamless integration with your terminal workflow&lt;/p&gt;
&lt;p&gt;This setup is particularly valuable for system administrators, developers, and anyone who frequently needs to create or extract archives. It combines the file management power of ranger with the versatility of atool for handling various archive formats.&lt;/p&gt;
&lt;a href=&quot;https://www.nongnu.org/atool/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ATOOL DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/ranger/ranger/wiki/Custom-Commands&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔧&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;RANGER CUSTOM COMMANDS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://wiki.archlinux.org/title/Ranger#Archives&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📦&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;ARCH WIKI: RANGER ARCHIVES&lt;/span&gt;
&lt;/a&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;related-ranger-guides&quot;&gt;Related Ranger Guides&lt;/h2&gt;
&lt;p&gt;Enhance your ranger experience with these additional tutorials:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-fzf-bat-integration/&quot;&gt;Ranger and fzf Integration&lt;/a&gt; - Add powerful fuzzy search capabilities&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-exiftool-integration/&quot;&gt;Image Metadata Viewing with exiftool&lt;/a&gt; - View detailed metadata for images and media files&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-media-preview-configuration/&quot;&gt;Advanced Media Preview Configuration&lt;/a&gt; - Customize file previews for various formats&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/posts/ranger-sxiv-integration/&quot;&gt;Ranger and sxiv Integration&lt;/a&gt; - Create a seamless image viewing workflow&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Enhancing Ranger with fzf and bat: A Powerful File Search Integration</title>
          <pubDate>Fri, 18 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/ranger-fzf-bat-integration/</link>
          <guid>https://criticalbasics.xyz/posts/ranger-fzf-bat-integration/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/ranger-fzf-bat-integration/">&lt;p&gt;The ranger file manager is already a powerful tool for navigating your filesystem, but with the addition of &lt;code&gt;fzf&lt;/code&gt; (fuzzy finder) and &lt;code&gt;bat&lt;/code&gt; (syntax highlighter), you can supercharge your file searching capabilities. This guide will show you how to integrate these tools for a seamless and visually appealing search experience.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-07-18&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Created guide for integrating fzf and bat with ranger&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-prerequisites&quot;&gt;1. Prerequisites&lt;/h2&gt;
&lt;p&gt;Before we begin, ensure you have the following tools installed on your system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ranger&lt;/strong&gt;: The terminal file manager&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fzf&lt;/strong&gt;: Command-line fuzzy finder&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bat&lt;/strong&gt;: A cat clone with syntax highlighting&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;installation-on-various-distributions&quot;&gt;Installation on Various Distributions&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Debian/Ubuntu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install ranger fzf bat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Arch Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ranger fzf bat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Fedora&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dnf install ranger fzf bat&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: On some distributions, &lt;code&gt;bat&lt;/code&gt; might be packaged as &lt;code&gt;batcat&lt;/code&gt;. You can create an alias in your shell configuration file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; bat&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;batcat&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-creating-the-custom-fzf-select-command&quot;&gt;2. Creating the Custom fzf_select Command&lt;/h2&gt;
&lt;p&gt;The integration requires adding a custom command to ranger. This command will use &lt;code&gt;fzf&lt;/code&gt; for searching and &lt;code&gt;bat&lt;/code&gt; for file previews.&lt;/p&gt;
&lt;h3 id=&quot;2-1-create-or-edit-commands-py&quot;&gt;2.1. Create or Edit commands.py&lt;/h3&gt;
&lt;p&gt;First, navigate to your ranger configuration directory and create or edit the &lt;code&gt;commands.py&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/commands.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t have a &lt;code&gt;commands.py&lt;/code&gt; file yet, you can generate a template with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --copy-config=commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-2-add-the-fzf-select-command&quot;&gt;2.2. Add the fzf_select Command&lt;/h3&gt;
&lt;p&gt;Open the &lt;code&gt;commands.py&lt;/code&gt; file in your favorite text editor and add the following code:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;from&lt;/span&gt;&lt;span&gt; ranger.api.commands&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; import&lt;/span&gt;&lt;span&gt; Command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;/span&gt;&lt;span&gt; subprocess&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; fzf_select&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Command&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    :fzf_select&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    Find a file or directory using fzf with preview using bat, excluding certain directories unless currently in them.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; execute&lt;/span&gt;&lt;span&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        exclude_dirs&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;Remote&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;USBmount&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;NFSshares&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Games_ROMS&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # List of directories to exclude&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        current_dir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.getcwd()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        base_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.path.basename(current_dir)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Check if the current directory is in the list of directories to exclude&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; base_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; exclude_dirs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            find_command&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;find . -type f -o -type d&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;            # Construct the find command with exclusion criteria&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            exclude_opts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39; &amp;#39;&lt;/span&gt;&lt;span&gt;.join(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;-path &amp;#39;./&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39; -prune -o&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span&gt; exclude_dirs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            find_command&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;find . &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;( &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;exclude_opts&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; -false &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;) -o &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;( -type f -o -type d &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;) -print&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        command&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;find_command&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; | fzf --preview &amp;#39;[[ -f &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{{}}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ]] &amp;amp;&amp;amp; bat --style=numbers --color=always &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{{}}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; || echo &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{{}}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; is a directory&amp;#39; --preview-window=right:70%:wrap --exact&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fzf&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; subprocess.Popen(command,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; stdout&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;PIPE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; shell&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; text&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; cwd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;current_dir)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        selected, _&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; fzf.communicate()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; fzf.returncode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            selected&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; selected.strip()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            selected_path&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os.path.abspath(selected)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; os.path.isdir(selected_path):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;                # Change to the directory if it&amp;#39;s a directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.cd(selected_path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            else&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;                # Open the file if it&amp;#39;s a file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                self&lt;/span&gt;&lt;span&gt;.fm.select_file(selected_path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;            # Explicitly refresh the ranger window&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            self&lt;/span&gt;&lt;span&gt;.fm.ui.redraw_window()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Exclude specific directories from the search (unless you’re already in one of them)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;bat&lt;/code&gt; for file previews and show a simple message for directories&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;fzf&lt;/code&gt; with the appropriate options&lt;/li&gt;
&lt;li&gt;Navigate to the selected file or directory&lt;/li&gt;
&lt;li&gt;Explicitly refresh the ranger window after selection&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-creating-a-keyboard-shortcut&quot;&gt;3. Creating a Keyboard Shortcut&lt;/h2&gt;
&lt;p&gt;Now that we have our custom command, let’s create a keyboard shortcut to invoke it easily.&lt;/p&gt;
&lt;h3 id=&quot;3-1-edit-rc-conf&quot;&gt;3.1. Edit rc.conf&lt;/h3&gt;
&lt;p&gt;Open your ranger configuration file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;vim&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/rc.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t have this file yet, you can generate it with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --copy-config=rc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-2-add-the-keyboard-mapping&quot;&gt;3.2. Add the Keyboard Mapping&lt;/h3&gt;
&lt;p&gt;Add the following line to map the &lt;code&gt;fzf_select&lt;/code&gt; command to a keyboard shortcut. In this example, we’ll use &lt;code&gt;zi&lt;/code&gt; (which stands for “zoom in”):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map zi fzf_select&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This shortcut is easy to remember as &lt;code&gt;zi&lt;/code&gt; stands for “zoom in” - which is exactly what this command does: it zooms into your file structure to quickly find what you’re looking for.&lt;/p&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Shortcut&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;zi&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Start fuzzy search with fzf and bat preview (“zoom in” to your files)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-advanced-configuration&quot;&gt;4. Advanced Configuration&lt;/h2&gt;
&lt;h3 id=&quot;4-1-customize-directory-exclusions&quot;&gt;4.1. Customize Directory Exclusions&lt;/h3&gt;
&lt;p&gt;You can modify the list of directories to exclude from the search by changing the &lt;code&gt;exclude_dirs&lt;/code&gt; list in the &lt;code&gt;fzf_select&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exclude_dirs&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;Remote&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;USBmount&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;NFSshares&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;Games_ROMS&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;VirtualMachines&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Add or remove directories as needed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-show-hidden-files&quot;&gt;4.2. Show Hidden Files&lt;/h3&gt;
&lt;p&gt;If you want to include hidden files in your search, modify the &lt;code&gt;find_command&lt;/code&gt; variable:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;find_command&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;find . -type f -o -type d -name &amp;#39;.*&amp;#39; -o -type f -o -type d&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-3-customize-preview-options&quot;&gt;4.3. Customize Preview Options&lt;/h3&gt;
&lt;p&gt;You can customize how &lt;code&gt;bat&lt;/code&gt; displays file previews by modifying the preview part of the command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;command&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{&lt;/span&gt;&lt;span&gt;find_command&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; | fzf --preview &amp;#39;[[ -f &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{{}}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ]] &amp;amp;&amp;amp; bat --style=full --color=always --line-range :150 &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{{}}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; || echo &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;{{}}&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; is a directory&amp;#39; --preview-window=right:60%:wrap --exact&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Uses the “full” style for bat (includes line numbers, Git modifications, etc.)&lt;/li&gt;
&lt;li&gt;Shows up to 150 lines in the preview&lt;/li&gt;
&lt;li&gt;Sets the preview window width to 60% of the terminal&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-usage&quot;&gt;5. Usage&lt;/h2&gt;
&lt;p&gt;Once everything is set up, you can use your new fuzzy search capability:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open ranger in your terminal&lt;/li&gt;
&lt;li&gt;Press your configured shortcut (e.g., &lt;code&gt;zi&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Type to search for files&lt;/li&gt;
&lt;li&gt;Use arrow keys to navigate through results&lt;/li&gt;
&lt;li&gt;Press Enter to select a file or directory&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-troubleshooting&quot;&gt;6. Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;6-1-command-not-found&quot;&gt;6.1. Command Not Found&lt;/h3&gt;
&lt;p&gt;If you get a “Command not found” error when trying to use the shortcut:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure you’ve saved the &lt;code&gt;commands.py&lt;/code&gt; file correctly&lt;/li&gt;
&lt;li&gt;Restart ranger to load the new command&lt;/li&gt;
&lt;li&gt;Check that &lt;code&gt;fzf&lt;/code&gt; and &lt;code&gt;bat&lt;/code&gt; are installed and in your PATH&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-2-preview-not-working&quot;&gt;6.2. Preview Not Working&lt;/h3&gt;
&lt;p&gt;If file previews aren’t displaying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify that &lt;code&gt;bat&lt;/code&gt; is installed correctly&lt;/li&gt;
&lt;li&gt;Try using &lt;code&gt;batcat&lt;/code&gt; instead of &lt;code&gt;bat&lt;/code&gt; if you’re on Debian/Ubuntu&lt;/li&gt;
&lt;li&gt;Check if your terminal supports the preview feature&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With this integration, you’ve significantly enhanced ranger’s search capabilities:&lt;/p&gt;
&lt;p&gt;✅ Lightning-fast file searching with fuzzy matching
✅ Beautiful syntax-highlighted previews
✅ Seamless navigation to selected files
✅ Customizable interface and behavior&lt;/p&gt;
&lt;p&gt;This setup combines the best of three powerful tools: ranger’s file management, fzf’s search capabilities, and bat’s beautiful syntax highlighting.&lt;/p&gt;
&lt;a href=&quot;https://github.com/ranger/ranger/wiki/Custom-Commands&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;RANGER CUSTOM COMMANDS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/junegunn/fzf&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔍&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;FZF DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/sharkdp/bat&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🦇&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;BAT DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Advanced Media Preview Configuration in Ranger</title>
          <pubDate>Fri, 18 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/ranger-media-preview-configuration/</link>
          <guid>https://criticalbasics.xyz/posts/ranger-media-preview-configuration/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/ranger-media-preview-configuration/">&lt;p&gt;One of ranger’s most powerful features is its ability to preview various file types directly in the terminal. This guide shows you how to customize the preview system to support a wide range of media files with optimal display settings.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-07-18&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Created guide for customizing media previews in ranger&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-understanding-ranger-s-preview-system&quot;&gt;1. Understanding Ranger’s Preview System&lt;/h2&gt;
&lt;p&gt;Ranger uses a script called &lt;code&gt;scope.sh&lt;/code&gt; to generate previews for different file types. This script determines how to handle each file based on its MIME type or extension, then calls the appropriate external tools to generate a preview.&lt;/p&gt;
&lt;h3 id=&quot;1-1-the-preview-process&quot;&gt;1.1. The Preview Process&lt;/h3&gt;
&lt;p&gt;When you select a file in ranger:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ranger calls the &lt;code&gt;scope.sh&lt;/code&gt; script&lt;/li&gt;
&lt;li&gt;The script identifies the file type&lt;/li&gt;
&lt;li&gt;It selects an appropriate preview method&lt;/li&gt;
&lt;li&gt;The preview is displayed in the preview pane&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;1-2-default-configuration&quot;&gt;1.2. Default Configuration&lt;/h3&gt;
&lt;p&gt;By default, ranger comes with a sample &lt;code&gt;scope.sh&lt;/code&gt; file, but it’s not automatically installed. You need to copy it to your configuration directory and customize it for your needs.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-setting-up-the-preview-script&quot;&gt;2. Setting Up the Preview Script&lt;/h2&gt;
&lt;h3 id=&quot;2-1-copy-the-default-scope-sh&quot;&gt;2.1. Copy the Default scope.sh&lt;/h3&gt;
&lt;p&gt;First, create your ranger configuration directory if it doesn’t exist:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, copy the default &lt;code&gt;scope.sh&lt;/code&gt; script:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --copy-config=scope&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create &lt;code&gt;~/.config/ranger/scope.sh&lt;/code&gt; with the default configuration.&lt;/p&gt;
&lt;h3 id=&quot;2-2-make-the-script-executable&quot;&gt;2.2. Make the Script Executable&lt;/h3&gt;
&lt;p&gt;Ensure the script is executable:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +x ~/.config/ranger/scope.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-installing-preview-dependencies&quot;&gt;3. Installing Preview Dependencies&lt;/h2&gt;
&lt;p&gt;To get the most out of ranger’s preview capabilities, you’ll need to install various tools for different file types:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Debian/Ubuntu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt update&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apt install highlight atool lynx mediainfo poppler-utils&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ffmpegthumbnailer imagemagick transmission-cli odt2txt&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    python3-pygments catdoc docx2txt fontforge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Arch Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; highlight atool lynx mediainfo poppler ffmpegthumbnailer&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    imagemagick transmission-cli python-pygments catdoc fontforge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Fedora&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; dnf install highlight atool lynx mediainfo poppler-utils ffmpegthumbnailer&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ImageMagick transmission python3-pygments catdoc fontforge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Optional: Install xlsx2csv for spreadsheet previews&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install xlsx2csv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-customizing-the-preview-script&quot;&gt;4. Customizing the Preview Script&lt;/h2&gt;
&lt;p&gt;Now let’s customize the &lt;code&gt;scope.sh&lt;/code&gt; script to enhance the preview capabilities. Open the file in your favorite text editor:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;vim&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/ranger/scope.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-1-image-preview-configuration&quot;&gt;4.1. Image Preview Configuration&lt;/h3&gt;
&lt;p&gt;Find the section that handles images and customize it:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;mimetype&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Image previews&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt;    image/&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # Use preview size of 1920px for large images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        local&lt;/span&gt;&lt;span&gt; geometry&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;1920x1080&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;mimetype&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;image/svg+xml&amp;quot;&lt;/span&gt;&lt;span&gt; ]];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            convert&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;IMAGE_CACHE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            exiftool&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -b -PreviewImage -w&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;IMAGE_CACHE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;            # If exiftool failed, try standard conversion&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            convert&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}[0]&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -resize&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;geometry&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;IMAGE_CACHE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-video-preview-with-ffmpegthumbnailer&quot;&gt;4.2. Video Preview with FFmpegthumbnailer&lt;/h3&gt;
&lt;p&gt;Enhance the video preview section:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;video/*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Video preview using ffmpegthumbnailer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ffmpegthumbnailer&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;IMAGE_CACHE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -s 0 -q 10&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-3-pdf-preview-configuration&quot;&gt;4.3. PDF Preview Configuration&lt;/h3&gt;
&lt;p&gt;Improve PDF preview with higher resolution:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/pdf&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Higher quality PDF preview (first page)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pdftoppm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f 1 -l 1 -scale-to 1024 -singlefile -jpeg&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;IMAGE_CACHE_PATH&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-4-office-documents-preview&quot;&gt;4.4. Office Documents Preview&lt;/h3&gt;
&lt;p&gt;Add better support for office documents:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Office documents&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/vnd.openxmlformats-officedocument.wordprocessingml.document&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/vnd.oasis.opendocument.text&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Convert to plain text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    docx2txt&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot; -&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    odt2txt&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/vnd.oasis.opendocument.spreadsheet&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Convert to CSV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    xlsx2csv&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-5-archive-content-preview&quot;&gt;4.5. Archive Content Preview&lt;/h3&gt;
&lt;p&gt;Enhance archive preview:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Archives&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/zip&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/x-rar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/x-7z-compressed&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/x-tar&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/x-bzip2&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/x-gzip&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/x-xz&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # List archive contents&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    atool&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --list --&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    bsdtar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --list --file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-6-syntax-highlighting-for-code&quot;&gt;4.6. Syntax Highlighting for Code&lt;/h3&gt;
&lt;p&gt;Improve code syntax highlighting:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Syntax highlighting for code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;text/*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Try to use pygmentize for syntax highlighting&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    env&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; COLORTERM=8bit bat&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --color=always --style=plain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    pygmentize&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; terminal&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -O&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; style=monokai&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Fallback to cat if pygmentize is not available&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    cat&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-advanced-customizations&quot;&gt;5. Advanced Customizations&lt;/h2&gt;
&lt;h3 id=&quot;5-1-custom-preview-size&quot;&gt;5.1. Custom Preview Size&lt;/h3&gt;
&lt;p&gt;You can adjust the preview size by modifying your &lt;code&gt;rc.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add to ~/.config/ranger/rc.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_images&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_images_method kitty&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # or use: w3m, iterm2, terminology, urxvt, sixel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_max_size&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 10485760&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Don&amp;#39;t preview files larger than 10MB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;5-2-font-preview&quot;&gt;5.2. Font Preview&lt;/h3&gt;
&lt;p&gt;Add font preview capability:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add to scope.sh under the case statement&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Note: This requires FontForge to be installed for the fontimage command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;font/*&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/font*&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/x-font*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    preview_png&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/tmp/$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;basename&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;IMAGE_CACHE_PATH&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;).png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; fontimage&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;preview_png&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                 --pixelsize&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;120&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                 --fontname \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                 --pixelsize&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;80&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                 --text&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  ABCDEFGHIJKLMNOPQRSTUVWXYZ  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                 --text&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  abcdefghijklmnopqrstuvwxyz  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                 --text&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  0123456789.:,;(*!?&amp;#39;)  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;                 --text&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;  The quick brown fox jumps over the lazy dog.  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;                 &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        convert&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;preview_png&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;IMAGE_CACHE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;preview_png&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;5-3-audio-file-preview&quot;&gt;5.3. Audio File Preview&lt;/h3&gt;
&lt;p&gt;Add audio file metadata preview:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add to scope.sh under the case statement&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;audio/*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Show audio metadata&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    mediainfo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    exiftool&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span&gt;FILE_PATH&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; exit 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-configuring-image-preview-methods&quot;&gt;6. Configuring Image Preview Methods&lt;/h2&gt;
&lt;p&gt;Ranger supports several methods for displaying image previews in the terminal. You’ll need to configure both &lt;code&gt;scope.sh&lt;/code&gt; and &lt;code&gt;rc.conf&lt;/code&gt; to use them properly.&lt;/p&gt;
&lt;h3 id=&quot;6-1-available-preview-methods&quot;&gt;6.1. Available Preview Methods&lt;/h3&gt;
&lt;p&gt;Add this to your &lt;code&gt;rc.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Choose one of these methods:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_images&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_images_method kitty&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Options: kitty, ueberzug, w3m, iterm2, terminology, urxvt, sixel&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Different methods work with different terminals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;kitty&lt;/strong&gt;: For the kitty terminal&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ueberzug&lt;/strong&gt;: Works with most terminals (requires python-ueberzug)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;w3m&lt;/strong&gt;: Works with most terminals that support w3m&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iterm2&lt;/strong&gt;: For iTerm2 on macOS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;terminology&lt;/strong&gt;: For the Terminology terminal&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;urxvt&lt;/strong&gt;: For urxvt with pixbuf support&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sixel&lt;/strong&gt;: For terminals with sixel support&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-2-installing-ueberzugpp-recommended&quot;&gt;6.2. Installing UeberzugPP (Recommended)&lt;/h3&gt;
&lt;p&gt;For the best image preview experience across different terminals, install UeberzugPP. Note that the original Ueberzug project is no longer maintained, and UeberzugPP is the modern replacement with Wayland support:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For Arch Linux (via AUR)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ueberzugpp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For other distributions (compile from source)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone https://github.com/jstkdng/ueberzugpp.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ueberzugpp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; build&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cmake&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -DCMAKE_BUILD_TYPE=Release&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ..&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;make&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Alternative: Install via pip (if available)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install ueberzugpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then set in &lt;code&gt;rc.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_images&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_images_method ueberzug&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: Even though we’re using UeberzugPP, the method name in ranger’s configuration remains &lt;code&gt;ueberzug&lt;/code&gt; for compatibility.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-testing-your-configuration&quot;&gt;7. Testing Your Configuration&lt;/h2&gt;
&lt;p&gt;After making changes to &lt;code&gt;scope.sh&lt;/code&gt;, restart ranger and test the preview functionality:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to different file types&lt;/li&gt;
&lt;li&gt;Check if the previews are displayed correctly&lt;/li&gt;
&lt;li&gt;Adjust the configuration as needed&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;7-1-debugging-preview-issues&quot;&gt;7.1. Debugging Preview Issues&lt;/h3&gt;
&lt;p&gt;If previews aren’t working as expected:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Run ranger with the &lt;code&gt;--debug&lt;/code&gt; flag:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --debug&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the output for errors related to the preview script&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure all required dependencies are installed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that &lt;code&gt;scope.sh&lt;/code&gt; is executable&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;8-practical-examples&quot;&gt;8. Practical Examples&lt;/h2&gt;
&lt;h3 id=&quot;8-1-image-gallery-browsing&quot;&gt;8.1. Image Gallery Browsing&lt;/h3&gt;
&lt;p&gt;With proper image preview configuration, you can use ranger as an image browser:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to a directory with images&lt;/li&gt;
&lt;li&gt;Use arrow keys to browse through images&lt;/li&gt;
&lt;li&gt;See high-quality previews directly in the terminal&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;8-2-code-review&quot;&gt;8.2. Code Review&lt;/h3&gt;
&lt;p&gt;With syntax highlighting enabled:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to source code files&lt;/li&gt;
&lt;li&gt;See syntax-highlighted code in the preview pane&lt;/li&gt;
&lt;li&gt;Quickly scan through multiple files&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;8-3-document-management&quot;&gt;8.3. Document Management&lt;/h3&gt;
&lt;p&gt;With document preview support:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browse through PDF documents&lt;/li&gt;
&lt;li&gt;See previews of the first page&lt;/li&gt;
&lt;li&gt;View plain text content of office documents&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;9-troubleshooting&quot;&gt;9. Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;9-1-missing-dependencies&quot;&gt;9.1. Missing Dependencies&lt;/h3&gt;
&lt;p&gt;If certain file types don’t preview correctly, you might be missing dependencies:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Check if a command is available&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;which&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ffmpegthumbnailer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;which&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; convert&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;which&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pdftoppm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install any missing tools using your package manager.&lt;/p&gt;
&lt;h3 id=&quot;9-2-terminal-compatibility&quot;&gt;9.2. Terminal Compatibility&lt;/h3&gt;
&lt;p&gt;Not all terminals support all preview methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If images don’t display, try a different &lt;code&gt;preview_images_method&lt;/code&gt; in &lt;code&gt;rc.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;For kitty terminal, make sure you’re using the kitty method&lt;/li&gt;
&lt;li&gt;For other terminals, try ueberzug or w3m&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;9-3-large-files&quot;&gt;9.3. Large Files&lt;/h3&gt;
&lt;p&gt;If ranger becomes slow when previewing large files:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add to rc.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; preview_max_size&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5242880&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Don&amp;#39;t preview files larger than 5MB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With these customizations to ranger’s preview system, you’ve enhanced your terminal file manager with rich media preview capabilities:&lt;/p&gt;
&lt;p&gt;✅ High-quality image previews
✅ Video thumbnails
✅ PDF document previews
✅ Office document text extraction
✅ Syntax highlighting for code
✅ Archive content listing
✅ Font previews&lt;/p&gt;
&lt;p&gt;This setup transforms ranger from a simple file manager into a powerful media browser that lets you quickly preview and navigate through various file types without leaving your terminal.&lt;/p&gt;
&lt;a href=&quot;https://github.com/ranger/ranger/wiki/Image-Previews&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🖼️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;RANGER IMAGE PREVIEWS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/ranger/ranger/wiki/Custom-Commands&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🔧&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;RANGER CUSTOM COMMANDS&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/seebye/ueberzug&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;UEBERZUG DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>The Ultimate Guide to Email Encryption with OpenPGP</title>
          <pubDate>Tue, 15 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/e-mail-encryption-with-openpgp/</link>
          <guid>https://criticalbasics.xyz/posts/e-mail-encryption-with-openpgp/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/e-mail-encryption-with-openpgp/">&lt;p&gt;This guide provides a comprehensive, “terminal-first” approach to setting up robust end-to-end email encryption. By creating your cryptographic keys directly with GnuPG, you build a universal and secure foundation. We will then show you how to integrate this setup seamlessly with both Thunderbird, a user-friendly graphical client, and Neomutt, a powerful terminal-based client.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-07-15&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Major Restructure (Terminal-First):&lt;/strong&gt; The entire guide was rewritten to prioritize key creation in the terminal (&lt;code&gt;gpg&lt;/code&gt;), making it more robust, universal, and secure. This resolves platform-specific client issues.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-07-15&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Initial Version:&lt;/strong&gt; Article created.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-pre-flight-check-your-system-s-foundation&quot;&gt;1. Pre-Flight Check – Your System’s Foundation&lt;/h2&gt;
&lt;p&gt;Before we create any keys, we must ensure your system is correctly configured.&lt;/p&gt;
&lt;h3 id=&quot;1-1-install-gnupg&quot;&gt;1.1. Install GnuPG&lt;/h3&gt;
&lt;p&gt;This is the core encryption engine.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Debian/Ubuntu:&lt;/strong&gt; &lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install gnupg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arch Linux:&lt;/strong&gt; &lt;code&gt;sudo pacman -Syu gnupg&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;part-1-2&quot;&gt;1.2. Install and Configure &lt;code&gt;pinentry&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;When a program needs your key’s passphrase, GPG uses a helper application called &lt;code&gt;pinentry&lt;/code&gt; to display a secure prompt. You must choose the right one for your environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Choose and Install the Right &lt;code&gt;pinentry&lt;/code&gt; for Your Environment&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;For standard Desktop Environments (GNOME, KDE, XFCE, etc.):&lt;/strong&gt;
A graphical pop-up is the default. Install the appropriate package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GNOME:&lt;/strong&gt; &lt;code&gt;sudo apt install pinentry-gnome3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KDE Plasma:&lt;/strong&gt; &lt;code&gt;sudo apt install pinentry-qt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arch Linux (most desktops):&lt;/strong&gt; &lt;code&gt;sudo pacman -S pinentry&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;For Tiling Window Managers (i3wm, sway, etc.) or Terminal-Enthusiasts (Recommended):&lt;/strong&gt;
A graphical &lt;code&gt;pinentry&lt;/code&gt; can “grab” focus and freeze your desktop. The terminal-based &lt;code&gt;pinentry-curses&lt;/code&gt; is a much better solution as it runs directly in your terminal, allowing you to switch windows normally.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Debian/Ubuntu:&lt;/strong&gt; &lt;code&gt;sudo apt install pinentry-curses&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arch Linux:&lt;/strong&gt; &lt;code&gt;pinentry&lt;/code&gt; is already included in the &lt;code&gt;pinentry&lt;/code&gt; package.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Tell the GPG Agent Which Program to Use&lt;/strong&gt;
We will now edit the GPG Agent configuration file.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the file with a terminal editor:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nano&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.gnupg/gpg-agent.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inside the &lt;code&gt;nano&lt;/code&gt; editor,&lt;/strong&gt; add &lt;strong&gt;ONE&lt;/strong&gt; of the following lines, depending on your choice in Step 1. Ensure the other line is deleted or commented out with a &lt;code&gt;#&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For a terminal-based prompt (i3wm, sway - HIGHLY RECOMMENDED for this setup)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pinentry-program /usr/bin/pinentry-curses&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# For a graphical prompt (GNOME, KDE, etc.)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# pinentry-program /usr/bin/pinentry-gnome3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;default-cache-ttl 600&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;max-cache-ttl 7200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: Verify the correct path with &lt;code&gt;which pinentry-gnome3&lt;/code&gt; or &lt;code&gt;which pinentry-curses&lt;/code&gt; if needed.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save the file and exit &lt;code&gt;nano&lt;/code&gt; (&lt;code&gt;Ctrl+X&lt;/code&gt;, then &lt;code&gt;Y&lt;/code&gt;, then &lt;code&gt;Enter&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reload the agent to apply the new configuration:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg-connect-agent&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reloadagent /bye&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2&quot;&gt;2. Creating Your Master Key in the Terminal&lt;/h2&gt;
&lt;p&gt;We will now create your OpenPGP key using the recommended interactive process.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start the key generation process:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --full-generate-key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Follow the prompts.&lt;/strong&gt; The recommended choices are secure and robust:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Key Type:&lt;/strong&gt; Select &lt;strong&gt;&lt;code&gt;(1) RSA and RSA&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key Size:&lt;/strong&gt; Enter &lt;strong&gt;&lt;code&gt;4096&lt;/code&gt;&lt;/strong&gt; bits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expiration Date:&lt;/strong&gt; Enter &lt;strong&gt;&lt;code&gt;2y&lt;/code&gt;&lt;/strong&gt; (for 2 years). Keys should expire. This is a critical safety net that limits potential damage if a key is ever lost. Don’t worry, you can easily extend the validity before it expires, as shown in Part 3.5.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confirm&lt;/strong&gt; that the expiration date is correct by typing &lt;strong&gt;&lt;code&gt;y&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Provide Your User ID:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Real name:&lt;/strong&gt; Enter your full name.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email address:&lt;/strong&gt; Enter the email address for this key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comment:&lt;/strong&gt; You can leave this blank.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confirm&lt;/strong&gt; your details by typing &lt;strong&gt;&lt;code&gt;O&lt;/code&gt;&lt;/strong&gt; (for Okay).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set Your Passphrase:&lt;/strong&gt;
A secure prompt will now appear (thanks to &lt;code&gt;pinentry&lt;/code&gt;!). This will be the master password for your new private key.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            PASSPHRASE QUALITY IS CRITICAL
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A weak passphrase makes your encrypted data vulnerable. Consider using a method like **Diceware** to generate a sequence of random words. If you lose this passphrase, you lose access to all data encrypted with this key permanently.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Congratulations, you have successfully created a secure, command-line-native OpenPGP key!&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3&quot;&gt;3. Essential Security Practices (Don’t Skip This!)&lt;/h2&gt;
&lt;p&gt;Immediately after creation, you must secure your new key for long-term use.&lt;/p&gt;
&lt;h3 id=&quot;3-1-identifying-your-key-the-key-id&quot;&gt;3.1. Identifying Your Key: The Key-ID&lt;/h3&gt;
&lt;p&gt;From this point forward, we will use your key’s unique &lt;strong&gt;Key-ID&lt;/strong&gt; to refer to it. This avoids any confusion if you ever have multiple keys for the same email address.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Find Your Key-ID:&lt;/strong&gt; Run the following command.&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --list-secret-keys --keyid-format&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; LONG&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identify the ID:&lt;/strong&gt; In the output &lt;code&gt;sec rsa4096/YOUR-KEY-ID ...&lt;/code&gt;, the &lt;code&gt;YOUR-KEY-ID&lt;/code&gt; is the long string of characters you will use in all subsequent commands.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;3-2-backup-your-private-key&quot;&gt;3.2. Backup Your Private Key&lt;/h3&gt;
&lt;p&gt;A backup is not a backup until it’s tested. Use your newly found Key-ID here.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create the Backup:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;umask 077&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --export-secret-keys --armor&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; YOUR-KEY-ID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; private-key-backup.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify the Backup:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --dry-run --import&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; private-key-backup.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;If this command runs without errors, your backup is valid. Now, store the &lt;code&gt;.asc&lt;/code&gt; file in one or more &lt;strong&gt;extremely secure, offline locations&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;3-3-create-a-revocation-certificate&quot;&gt;3.3. Create a Revocation Certificate&lt;/h3&gt;
&lt;p&gt;This is your emergency button. Use your Key-ID to specify which key to revoke.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;umask 077&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --gen-revoke --armor&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; YOUR-KEY-ID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; revocation-cert.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Store this file as securely as your private key backup.&lt;/p&gt;
&lt;h3 id=&quot;3-4-verify-keys-and-build-your-web-of-trust-the-core-of-pgp-s-security&quot;&gt;3.4. Verify Keys and Build Your Web of Trust: The Core of PGP’s Security&lt;/h3&gt;
&lt;p&gt;This section is conceptually the most important part of the entire guide. It explains how you can be sure a public key truly belongs to the person it claims to.&lt;/p&gt;
&lt;h4 id=&quot;what-is-the-fingerprint&quot;&gt;What is the Fingerprint?&lt;/h4&gt;
&lt;p&gt;When you run the command &lt;code&gt;gpg --fingerprint YOUR-KEY-ID&lt;/code&gt;, you get an output like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ gpg --fingerprint 8A738464A2144E4C&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub   rsa4096 2025-07-29 [SC] [expires: 2027-07-29]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      4A9E 9A72 85F5 F569 C17C  299B 8A73 8464 A214 4E4C&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;uid        [ultimate] Delightful Dude &amp;lt;delightfuldude@criticalbasics.xyz&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub   rsa4096 2025-07-29 [E] [expires: 2027-07-29]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;strong&gt;Fingerprint&lt;/strong&gt; is the long line of 40 hexadecimal characters (often displayed in 10 blocks of 4 characters). It is like a human fingerprint: absolutely unique to this specific key. This is your key’s “ID card.”&lt;/p&gt;
&lt;h4 id=&quot;the-verification-process-a-practical-example&quot;&gt;The Verification Process: A Practical Example&lt;/h4&gt;
&lt;p&gt;Imagine you want to communicate securely with your friend, Anna.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: You acquire Anna’s public key.&lt;/strong&gt;
Anna has published her key on her website (Method 4.1) or a keyserver (Method 4.2). You import it.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Example: You import Anna&amp;#39;s key from her website&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://anna.example.com/public.asc&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --import&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: You check the key’s status.&lt;/strong&gt;
Now, you view the fingerprint of Anna’s key in your keyring.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --fingerprint&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; anna@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output will contain a line that looks like this:
&lt;code&gt;uid [ unknown ] Anna Miller &amp;lt;anna@example.com&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;[ unknown ]&lt;/code&gt; part is critical. It means: “I have this key, but I have absolutely no idea if it really belongs to Anna or to an attacker impersonating her.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: The actual verification (the human part).&lt;/strong&gt;
To be sure, you must compare the fingerprint with Anna over a &lt;strong&gt;different, trusted channel&lt;/strong&gt;. This is the most important step to prevent man-in-the-middle attacks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You meet Anna in person.&lt;/li&gt;
&lt;li&gt;You call Anna or have a video call (with someone whose voice or face you recognize).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;During the conversation, the following happens:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You say:&lt;/strong&gt; “Anna, I’m going to read you the fingerprint I have for your key. Does it start with 1234 ABCD…?”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anna says:&lt;/strong&gt; “Yes, that’s correct. And does yours start with 0FDA EF41…?”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You say:&lt;/strong&gt; “Yes, it does.”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now you both have certainty that you possess each other’s authentic key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Sign the key (digitally record your trust).&lt;/strong&gt;
After verifying the key, you tell your GnuPG that you trust it. You do this by signing the foreign key with your own private key.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --sign-key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; anna@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GPG will show you Anna’s fingerprint again and ask if you are really sure. Confirm with &lt;code&gt;y&lt;/code&gt;. You will need to enter your passphrase to authorize the signature with your private key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Check the result.&lt;/strong&gt;
Run the fingerprint command again:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --fingerprint&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; anna@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output has now changed:
&lt;code&gt;uid [ full ] Anna Miller &amp;lt;anna@example.com&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;[ full ]&lt;/code&gt; is your personal note: “I have personally verified this key. It’s authentic. I trust it completely.”&lt;/p&gt;
&lt;p&gt;Through this process, you build your personal &lt;strong&gt;“Web of Trust”&lt;/strong&gt;. If you trust Anna’s key, and Anna in turn trusts Bob’s key, you have a reason to lend some level of trust to Bob’s key as well.&lt;/p&gt;
&lt;h3 id=&quot;3-5-extending-your-key-s-validity-key-renewal&quot;&gt;3.5. Extending Your Key’s Validity (Key Renewal)&lt;/h3&gt;
&lt;p&gt;An expiring key is a feature, not a problem. You do &lt;strong&gt;NOT&lt;/strong&gt; need to start over. You can easily extend its life before it expires.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Start the Key-Editing Process:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --edit-key&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; YOUR-KEY-ID&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extend the Expiration Date:&lt;/strong&gt;
Inside the GPG prompt, type &lt;code&gt;expire&lt;/code&gt;, enter a new duration (e.g., &lt;code&gt;2y&lt;/code&gt;), and confirm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save Your Changes:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg&amp;gt; save&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distribute Your Updated Key:&lt;/strong&gt;
You must re-publish your updated public key.&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --keyserver&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hkps://keys.openpgp.org&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --send-keys&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; YOUR-KEY-ID&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;Also, send a newly signed email with your updated public key attached to your most important contacts.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-4&quot;&gt;4. Making Your Key Discoverable (Optional)&lt;/h2&gt;
&lt;p&gt;A public key that only exists on your computer is like a phone number you never give out. For others to send you encrypted mail easily, you should distribute your public key.&lt;/p&gt;
&lt;h3 id=&quot;4-1-method-1-the-gold-standard-your-personal-website&quot;&gt;4.1. Method 1: The Gold Standard - Your Personal Website&lt;/h3&gt;
&lt;p&gt;This is the most secure and authoritative method. You establish a “source of truth” that you control, avoiding issues with public servers.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Export your public key:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --export --armor&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; YOUR-KEY-ID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; public.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upload the &lt;code&gt;public.asc&lt;/code&gt; file to your website,&lt;/strong&gt; for example, to &lt;code&gt;https://your-website.com/public.asc&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;4-2-method-2-the-convenient-way-public-keyservers&quot;&gt;4.2. Method 2: The Convenient Way - Public Keyservers&lt;/h3&gt;
&lt;p&gt;This method is more convenient but involves a trade-off with privacy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Security Risk: NO.&lt;/strong&gt; You only upload your &lt;strong&gt;public&lt;/strong&gt; key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privacy Risk: YES.&lt;/strong&gt; This publicly associates your email with PGP usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The Solution: Use a Modern, Privacy-Respecting Keyserver.&lt;/strong&gt;
This is why we exclusively recommend &lt;code&gt;keys.openpgp.org&lt;/code&gt;. It requires your consent via email verification to publish your key.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Send Your Key to the Server:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --keyserver&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; hkps://keys.openpgp.org&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --send-keys&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; YOUR-KEY-ID&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check Your Email:&lt;/strong&gt; The keyserver will send you a verification email. You &lt;strong&gt;must click the link&lt;/strong&gt; to finalize the publication.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-going-public-your-contact-page-and-email-signature&quot;&gt;5. Going Public: Your Contact Page and Email Signature&lt;/h2&gt;
&lt;p&gt;Now that you have ways to distribute your key, you need to tell people about them.&lt;/p&gt;
&lt;h3 id=&quot;5-1-on-your-website-s-contact-page&quot;&gt;5.1. On Your Website’s Contact Page&lt;/h3&gt;
&lt;p&gt;Add a section like this to your contact page. It provides clear instructions for everyone.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;h3&lt;/span&gt;&lt;span&gt;&amp;gt;Digital Contact &amp;amp; Verification&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;h3&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt;E-Mail:&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt; your.name@example.com&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt;OpenPGP Key:&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt; For encrypted communication, you can get my public key here:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;ul&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/public.asc&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; download&lt;/span&gt;&lt;span&gt;&amp;gt;Download Public Key&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt;Or import via command line:&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;code&lt;/span&gt;&lt;span&gt;&amp;gt;curl -sL https://your-website.com/public.asc | gpg --import&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;code&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;ul&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt;Fingerprint for Verification:&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;strong&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;code&lt;/span&gt;&lt;span&gt;&amp;gt;YOUR FINGERPRINT IN 4-DIGIT BLOCKS&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;code&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;em&lt;/span&gt;&lt;span&gt;&amp;gt;Policy: All legitimate emails from me will be digitally signed with this key.&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;em&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;5-2-in-your-email-signature&quot;&gt;5.2. In Your Email Signature&lt;/h3&gt;
&lt;p&gt;A compact, professional signature in every email reinforces trust and makes verification easy.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your Name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Website &amp;amp; PGP Key: https://your-website.com/contact&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GPG Fingerprint: YOUR FINGERPRINT IN 4-DIGIT BLOCKS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This signature doesn’t overload the email but provides everything a recipient needs to verify your identity and find your key.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-6&quot;&gt;6. Integration with Thunderbird&lt;/h2&gt;
&lt;p&gt;Once your key is created via the terminal, you need to tell Thunderbird to use it for your email account.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In Thunderbird, open the &lt;strong&gt;Account Settings&lt;/strong&gt; (via the “Hamburger” menu or &lt;code&gt;Tools&lt;/code&gt; -&amp;gt; &lt;code&gt;Account Settings&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;In the left-hand sidebar, select the email account you want to secure (e.g., &lt;code&gt;delightfuldude@criticalbasics.xyz&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;End-To-End Encryption&lt;/strong&gt; sub-menu for that account.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, you have two possible scenarios:&lt;/p&gt;
&lt;h4 id=&quot;scenario-a-thunderbird-automatically-finds-your-key&quot;&gt;Scenario A: Thunderbird Automatically Finds Your Key&lt;/h4&gt;
&lt;p&gt;If you’re lucky, Thunderbird has already detected the key you created in the terminal. You will see it listed and can select it directly from the dropdown menu to associate it with your account. If so, you’re done!&lt;/p&gt;
&lt;h4 id=&quot;scenario-b-the-key-is-not-listed-manual-import&quot;&gt;Scenario B: The Key is Not Listed (Manual Import)&lt;/h4&gt;
&lt;p&gt;More often, Thunderbird doesn’t immediately find externally created keys. If your key is not in the list, you must import it manually.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the same settings window, click the &lt;strong&gt;OpenPGP Key Manager…&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;A new “OpenPGP Key Manager” window will open. In its menu, go to &lt;strong&gt;File&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Import Secret Key(s) From File…&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A file dialog will open. Navigate to and select the &lt;code&gt;private.asc&lt;/code&gt; file you exported in &lt;a href=&quot;https://criticalbasics.xyz/posts/e-mail-encryption-with-openpgp/#part-4&quot;&gt;&lt;strong&gt;Part 4&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You will be prompted for the passphrase you created for your key. Enter it to complete the import.&lt;/li&gt;
&lt;li&gt;After a successful import, your new key will appear in the Key Manager list. You can now close this window.&lt;/li&gt;
&lt;li&gt;Back in the &lt;strong&gt;Account Settings&lt;/strong&gt;, your newly imported key should now be available in the dropdown menu. Select it to finalize the setup.&lt;/li&gt;
&lt;/ol&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            FURTHER HELP
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;For more detailed questions or troubleshooting, Mozilla provides an extensive FAQ page that is highly recommended:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq&quot;&gt;Official Thunderbird Help: OpenPGP HOWTO and FAQ&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-integration-with-neomutt&quot;&gt;7. Integration with Neomutt&lt;/h2&gt;
&lt;h3 id=&quot;7-1-neomutt-configuration&quot;&gt;7.1. Neomutt Configuration&lt;/h3&gt;
&lt;p&gt;Add these settings to &lt;code&gt;~/.config/neomutt/muttrc&lt;/code&gt;, using your unique Key-ID.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- GPG/PGP Settings for Neomutt ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_verify_sig&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_good_sign&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;✅ Good OpenPGP signature from&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_autosign&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_replyencrypt&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_replysign&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Für neuere Neomutt-Versionen:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_replysign_encrypted&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Für ältere Neomutt-Versionen (falls obige Option einen Fehler verursacht):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# set crypt_replysign = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Use the Key-ID followed by an exclamation mark!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# This tells GPG to use *exactly* this key.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_sign_as&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;YOUR-KEY-ID!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_timeout&lt;/span&gt;&lt;span&gt; = 300&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_show_unusable&lt;/span&gt;&lt;span&gt; = no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;8-advanced-topic-handling-multiple-accounts&quot;&gt;8. Advanced Topic: Handling Multiple Accounts&lt;/h2&gt;
&lt;p&gt;For maximum security, use &lt;strong&gt;separate OpenPGP keys for each email account&lt;/strong&gt;. This provides strong separation between your digital identities. This section covers the setup for Thunderbird and two common approaches for Neomutt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create Keys:&lt;/strong&gt; For each identity (e.g., private, work), &lt;strong&gt;repeat the process in &lt;a href=&quot;https://criticalbasics.xyz/posts/e-mail-encryption-with-openpgp/#part-2&quot;&gt;Part 2&lt;/a&gt;&lt;/strong&gt; to generate a new, dedicated key. Make sure to use the correct name and email address for each.&lt;/p&gt;
&lt;h3 id=&quot;8-1-thunderbird-integration&quot;&gt;8.1. Thunderbird Integration&lt;/h3&gt;
&lt;p&gt;For each account you have set up in Thunderbird, follow &lt;a href=&quot;https://criticalbasics.xyz/posts/e-mail-encryption-with-openpgp/#part-6&quot;&gt;&lt;strong&gt;Part 6&lt;/strong&gt;&lt;/a&gt; to assign the correct existing key to the corresponding email address. Thunderbird handles the mapping automatically.&lt;/p&gt;
&lt;h3 id=&quot;8-2-neomutt-integration-two-approaches&quot;&gt;8.2. Neomutt Integration: Two Approaches&lt;/h3&gt;
&lt;p&gt;For Neomutt, you can either switch accounts automatically based on the folder you are in, or manually via keyboard shortcuts.&lt;/p&gt;
&lt;h4 id=&quot;method-a-automatic-switching-with-folder-hooks&quot;&gt;Method A: Automatic Switching with Folder-Hooks&lt;/h4&gt;
&lt;p&gt;This method uses &lt;code&gt;folder-hook&lt;/code&gt; to automatically load the correct account configuration (including the PGP key) when you enter a specific mailbox.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Create the Directory Structure&lt;/strong&gt;
First, organize your account configurations in a dedicated directory.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/neomutt/accounts&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Configure the Main &lt;code&gt;muttrc&lt;/code&gt; for Hooks&lt;/strong&gt;
Your main &lt;code&gt;~/.config/neomutt/muttrc&lt;/code&gt; will now act as a loader. Add the PGP defaults (if not already present) and the hooks.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- PGP Defaults (add to your main muttrc) ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_timeout&lt;/span&gt;&lt;span&gt; = 300&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_verify_sig&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_good_sign&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;✅ Good OpenPGP signature from&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_show_unusable&lt;/span&gt;&lt;span&gt; = no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Für neuere Neomutt-Versionen:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_replysign_encrypted&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Für ältere Neomutt-Versionen (falls obige Option einen Fehler verursacht):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# set crypt_replysign = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Account Hooks ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Load a specific config file when you enter a folder.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Replace the imap paths with your actual server paths.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;folder-hook &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;imaps://private@mail.com/&amp;#39; &amp;#39;source ~/.config/neomutt/accounts/private.muttrc&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;folder-hook &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;imaps://work@company.com/&amp;#39;   &amp;#39;source ~/.config/neomutt/accounts/work.muttrc&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Load a default account when Neomutt starts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source ~/.config/neomutt/accounts/private.muttrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Create Per-Account Configuration Files&lt;/strong&gt;
Create a separate file for each account inside &lt;code&gt;~/.config/neomutt/accounts/&lt;/code&gt;. This is where you set the PGP key for each identity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: &lt;code&gt;~/.config/neomutt/accounts/private.muttrc&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# --- Account: Private ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;from&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;private@mail.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;realname&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Your Name (Private)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_sign_as&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;YOUR-PRIVATE-KEY-ID!&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Get ID from Part 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_autosign&lt;/span&gt;&lt;span&gt; = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ... your private imap_user, imap_pass, smtp_url, etc. go here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;method-b-manual-switching-for-mutt-wizard-users&quot;&gt;Method B: Manual Switching (for &lt;code&gt;mutt-wizard&lt;/code&gt; users)&lt;/h4&gt;
&lt;p&gt;Many users rely on the popular &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/LukeSmithxyz/mutt-wizard&quot;&gt;&lt;code&gt;mutt-wizard&lt;/code&gt;&lt;/a&gt; script, which favors manual account switching via macros. If your &lt;code&gt;muttrc&lt;/code&gt; contains lines like &lt;code&gt;macro index,pager i1 &#39;source ...&#39;&lt;/code&gt;, this method is for you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Locate Your Account Files&lt;/strong&gt;
&lt;code&gt;mutt-wizard&lt;/code&gt; creates a separate configuration file for each of your accounts, typically located in &lt;code&gt;~/.config/mutt/accounts/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Add &lt;code&gt;pgp_sign_as&lt;/code&gt; to Each Account File&lt;/strong&gt;
For each account, edit its corresponding file and add the &lt;code&gt;pgp_sign_as&lt;/code&gt; line to tell Neomutt which PGP key to use.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Get the &lt;strong&gt;Key-ID&lt;/strong&gt; for the key you want to use with this account (as described in &lt;a href=&quot;https://criticalbasics.xyz/posts/e-mail-encryption-with-openpgp/#part-3&quot;&gt;Part 3&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the account’s configuration file (e.g., &lt;code&gt;~/.config/mutt/accounts/delightfuldude@criticalbasics.xyz.muttrc&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following line, replacing &lt;code&gt;YOUR-KEY-ID!&lt;/code&gt; with the actual ID:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Inside e.g., ~/.config/mutt/accounts/delightfuldude@criticalbasics.xyz.muttrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ... existing settings like &amp;#39;set from&amp;#39;, &amp;#39;set realname&amp;#39;, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Add this line to set the default PGP signing key for this account&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pgp_sign_as&lt;/span&gt;&lt;span&gt; = YOUR-CRITICALBASICS-KEY-ID!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;
Now, when you use your keyboard macros (e.g., &lt;code&gt;i1&lt;/code&gt;, &lt;code&gt;i2&lt;/code&gt;) to switch accounts, Neomutt will load the correct email settings and automatically select the right PGP key for signing. Your existing workflow remains unchanged but is now PGP-aware.&lt;/p&gt;
&lt;h2 id=&quot;9-transferring-your-configuration-between-computers&quot;&gt;9. Transferring Your Configuration Between Computers&lt;/h2&gt;
&lt;p&gt;One of the most common questions is: “How can I use my OpenPGP setup on multiple computers without repeating this entire tutorial?” The good news is that you can transfer your configuration between computers quite easily.&lt;/p&gt;
&lt;h3 id=&quot;9-1-what-files-to-transfer&quot;&gt;9.1. What Files to Transfer&lt;/h3&gt;
&lt;p&gt;The most important directory is &lt;code&gt;~/.gnupg/&lt;/code&gt;, which contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your private and public keys&lt;/li&gt;
&lt;li&gt;GPG Agent configuration&lt;/li&gt;
&lt;li&gt;Trust database (Web of Trust)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, depending on your email client:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thunderbird&lt;/strong&gt;: Thunderbird accesses the GnuPG keyring directly, so transferring the &lt;code&gt;.gnupg&lt;/code&gt; directory is sufficient.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Neomutt&lt;/strong&gt;: You’ll also need to copy your configuration files:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.config/neomutt/muttrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/neomutt/accounts/&lt;/code&gt; (if you have multiple accounts)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;9-2-transfer-process&quot;&gt;9.2. Transfer Process&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secure Transfer&lt;/strong&gt;: Use a secure channel for transferring these files (encrypted USB drive, encrypted file transfer).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Copy the Directory&lt;/strong&gt;: Copy the entire &lt;code&gt;.gnupg&lt;/code&gt; directory to the same location on the target computer.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On the source computer, create a secure backup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -czf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gnupg-backup.tar.gz&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~ .gnupg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Transfer securely to the target computer and extract&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# On the target computer:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -xzf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; gnupg-backup.tar.gz&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fix Permissions&lt;/strong&gt;: After transferring, ensure proper permissions:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.gnupg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.gnupg/&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adjust Pinentry Configuration&lt;/strong&gt;: If the target system has a different desktop environment, you may need to modify the &lt;code&gt;pinentry-program&lt;/code&gt; path in &lt;code&gt;~/.gnupg/gpg-agent.conf&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reload GPG Agent&lt;/strong&gt;: After transferring, reload the GPG agent:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg-connect-agent&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; reloadagent /bye&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Verify the Setup&lt;/strong&gt;: Test that your keys are available:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --list-secret-keys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By following these steps, you can efficiently use your OpenPGP setup across multiple computers without repeating the entire configuration process.&lt;/p&gt;
&lt;h2 id=&quot;10-quick-troubleshooting&quot;&gt;10. Quick Troubleshooting&lt;/h2&gt;
&lt;div class=&quot;styled-table-container&quot;&gt;
  &lt;table id=&quot;custom-table&quot; &gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;40%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;60%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Problem&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Solution&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;“gpg: signing failed: Ambiguous specification”&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;You have multiple keys for one email. Use the unique &lt;strong&gt;Key-ID&lt;/strong&gt; instead of the email address in your configuration (e.g., &lt;code&gt;pgp_sign_as&lt;/code&gt; in Neomutt).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;No password prompt appears&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Your &lt;code&gt;pinentry&lt;/code&gt; program is missing or misconfigured. Go back to &lt;a href=&quot;#part-1-2&quot;&gt;&lt;strong&gt;Part 1.2&lt;/strong&gt;&lt;/a&gt; and ensure it is installed and configured correctly.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPG Agent Issues&lt;/strong&gt; (Passphrase not requested)&lt;/td&gt;&lt;td&gt;The GPG agent might have a stale cache. Force a reload with: &lt;code&gt;gpg-connect-agent reloadagent /bye&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;“Key not found” error&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;You don’t have the recipient’s public key. Ask them for it or search a keyserver.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;“gpg: signing failed: No secret key”&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Your key might be expired, or GPG cannot find the correct secret key. Check &lt;code&gt;gpg --list-secret-keys&lt;/code&gt; to ensure it’s present and valid.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Message shows “untrusted signature”&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;You have the sender’s public key, but you haven’t marked it as trusted. Verify the fingerprint and then sign it.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;11-conclusion&quot;&gt;11. Conclusion&lt;/h2&gt;
&lt;p&gt;By starting with a solid foundation—creating your keys directly in the terminal—you have built a robust and universal encryption setup. This method not only avoids platform-specific pitfalls but also equips you with a deeper understanding of how PGP works. By performing essential maintenance like backups, establishing a clear public identity, and renewing your keys, you ensure your digital identity remains secure and trustworthy for the long term.&lt;/p&gt;
&lt;a href=&quot;https://www.openpgp.org/docs/&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📚&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;OPENPGP DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
&lt;a href=&quot;https://gnupg.org/documentation/index.html&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;🛡️&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;GNUPG DOCUMENTATION&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>Tutorial: Integrating ranger and sxiv with Advanced Features</title>
          <pubDate>Sun, 06 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/ranger-sxiv-integration/</link>
          <guid>https://criticalbasics.xyz/posts/ranger-sxiv-integration/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/ranger-sxiv-integration/">&lt;p&gt;This tutorial combines all the necessary steps to seamlessly integrate &lt;strong&gt;sxiv&lt;/strong&gt; and &lt;strong&gt;ranger&lt;/strong&gt;, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launching a gallery view from ranger&lt;/li&gt;
&lt;li&gt;Configuring keybindings in ranger&lt;/li&gt;
&lt;li&gt;Creating an interactive “Open with…” menu in sxiv&lt;/li&gt;
&lt;li&gt;Opening ranger from within sxiv&lt;/li&gt;
&lt;li&gt;Navigating and using shortcuts in sxiv&lt;/li&gt;
&lt;li&gt;Increasing thumbnail sizes by recompiling sxiv&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Arch Linux&lt;/strong&gt; (or a similar distro; this guide refers to &lt;code&gt;pacman&lt;/code&gt; and the AUR)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sxiv&lt;/code&gt; and &lt;code&gt;ranger&lt;/code&gt; installed&lt;/li&gt;
&lt;li&gt;A terminal emulator (e.g., &lt;code&gt;xterm&lt;/code&gt;, &lt;code&gt;urxvt&lt;/code&gt;, &lt;code&gt;alacritty&lt;/code&gt;, &lt;code&gt;kitty&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Standard command-line tools (&lt;code&gt;file&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gtk-launch&lt;/code&gt; (usually available via &lt;code&gt;xdg-utils&lt;/code&gt; or a similar package)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-set-up-the-ranger-keybinding-launch-gallery&quot;&gt;1. Set Up the ranger Keybinding (Launch Gallery)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open your ranger configuration file: &lt;code&gt;~/.config/ranger/rc.conf&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a line to open sxiv in &lt;strong&gt;thumbnail mode&lt;/strong&gt; recursively using a key combination. For example, &lt;code&gt;gG&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Open sxiv in thumbnail mode (-t) recursively (-r) in the current directory (%d)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map gG shell sxiv -tr %d &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; enables &lt;strong&gt;thumbnail mode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; searches subdirectories recursively.&lt;/li&gt;
&lt;li&gt;The trailing &lt;code&gt;&amp;amp;&lt;/code&gt; ensures that ranger &lt;strong&gt;does not&lt;/strong&gt; wait for sxiv to close.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save the file and reload the configuration in ranger with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;:reload_config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or simply restart ranger.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-navigating-in-sxiv&quot;&gt;2. Navigating in sxiv&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open Gallery View:&lt;/strong&gt;
Use &lt;code&gt;sxiv -tr /path/to/your/folder&lt;/code&gt; to start directly in thumbnail mode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open a Single Image:&lt;/strong&gt;
Highlight an image in the gallery and press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Switch Between Images (Single-Image Mode):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt; or &lt;code&gt;Space&lt;/code&gt;: Next image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt; or &lt;code&gt;Backspace&lt;/code&gt;: Previous image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;]&lt;/code&gt;: 10 images forward&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&lt;/code&gt;: 10 images backward&lt;/li&gt;
&lt;li&gt;&lt;code&gt;g&lt;/code&gt;: First image, &lt;code&gt;G&lt;/code&gt;: Last image&lt;/li&gt;
&lt;li&gt;Right mouse click: Next image, Left mouse click: Previous image&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zoom in the Gallery:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt;: Zoom in&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;: Zoom out&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;To increase the maximum zoom level, you need to recompile sxiv (see Section 4).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-interactive-open-with-and-ranger-integration-in-sxiv&quot;&gt;3. Interactive “Open with…” and Ranger Integration in sxiv&lt;/h2&gt;
&lt;p&gt;We will create a &lt;strong&gt;key-handler script&lt;/strong&gt; that allows the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Ctrl-x r&lt;/code&gt;&lt;/strong&gt;: Opens ranger in a new terminal, selecting the current file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Ctrl-x o&lt;/code&gt;&lt;/strong&gt; (or any other key): Displays an interactive menu of all suitable applications and opens the image with the selected one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-1-create-the-script&quot;&gt;3.1. Create the Script&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create the directory:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.config/sxiv/exec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the file &lt;code&gt;~/.config/sxiv/exec/key-handler&lt;/code&gt; and paste the following content &lt;strong&gt;in its entirety&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#!/usr/bin/env sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ~/.config/sxiv/exec/key-handler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Interactive script for sxiv:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# - Ctrl-x r → opens ranger in a new terminal with the current file selected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# - Ctrl-x o (and others) → opens an &amp;quot;Open with…&amp;quot; menu to choose an application&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Robust handling of spaces, logging, and i3-compatible terminals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Logfile for debugging and tracking&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LOG&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/tmp/sxiv-open.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;=== key-handler started $(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;) ===&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Terminal emulator used to open the selection menu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Possible options: xterm, urxvt, alacritty, kitty …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TERMWIN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;${TERMWIN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:-&lt;/span&gt;&lt;span&gt;urxvt}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;TERMWIN set to: &lt;/span&gt;&lt;span&gt;$TERMWIN&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# $1 contains the key pressed after Ctrl-x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Command argument: &lt;/span&gt;&lt;span&gt;$cmd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Remove the prefix argument; all image paths follow via stdin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;shift&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Process each file individually (handles paths with spaces)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;while&lt;/span&gt;&lt;span&gt; IFS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; read -r&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; img&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Processing file: &amp;#39;&lt;/span&gt;&lt;span&gt;$img&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # === Ranger Integration (Ctrl-x r) ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$cmd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;r&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Ranger Integration: Opening ranger in terminal for &amp;#39;&lt;/span&gt;&lt;span&gt;$img&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Ranger needs a terminal, so launch it via a terminal emulator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;$TERMWIN&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ranger&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --selectfile=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$img&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # === Default Open-with… Menu (Ctrl-x o or other keys) ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 1) Determine the MIME type of the file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  mime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --mime-type -b&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$img&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; MIME-Type: &lt;/span&gt;&lt;span&gt;$mime&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 2) Find matching .desktop files for this MIME type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  mapfile&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; apps&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -Rl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;MimeType=.*&lt;/span&gt;&lt;span&gt;$mime&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      /usr/share/applications ~/.local/share/applications&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; xargs&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -r -n1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; basename&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  if&lt;/span&gt;&lt;span&gt; [ ${&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#&lt;/span&gt;&lt;span&gt;apps[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@&lt;/span&gt;&lt;span&gt;]}&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; No matching applications found for MIME &amp;#39;&lt;/span&gt;&lt;span&gt;$mime&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; Found applications: ${&lt;/span&gt;&lt;span&gt;apps&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;]}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 3) Create temporary files for the list and the choice&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  list_file&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  tmp_choice&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mktemp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  printf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;%s\n&amp;quot; &amp;quot;${&lt;/span&gt;&lt;span&gt;apps&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;]}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$list_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; List file: &lt;/span&gt;&lt;span&gt;$list_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; Choice file: &lt;/span&gt;&lt;span&gt;$tmp_choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 4) Open the terminal selection menu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span&gt;$TERMWIN&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -lc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    PS3=&amp;quot;Open with: &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    # Read all entries into an array&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    IFS=$&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39; read -rd &amp;quot;&amp;quot; -r -a options &amp;lt; &amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span&gt;$list_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    select opt in &amp;quot;${options[@]}&amp;quot;; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      # Write the choice to the temp file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      echo &amp;quot;$opt&amp;quot; &amp;gt; &amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span&gt;$tmp_choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 5) Read the choice and clean up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  choice&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$tmp_choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  rm&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$list_file&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span&gt;$tmp_choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; Selected: &lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; || continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 6) Find the full .desktop file path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  desktop&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  for&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /usr/share/applications ~/.local/share/applications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/&lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      desktop&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$d&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/&lt;/span&gt;&lt;span&gt;$choice&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;      break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; Desktop entry: &lt;/span&gt;&lt;span&gt;$desktop&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 7) Read the Exec line and remove placeholders&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exec_cmd&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -m1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;^Exec=&amp;#39; &amp;quot;&lt;/span&gt;&lt;span&gt;$desktop&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;             |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d= -f2- \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;             |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;s/ %[fFuUdDnNickvm]//g&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; Exec command: &lt;/span&gt;&lt;span&gt;$exec_cmd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # 8) Execute the program with the image path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  eval&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$exec_cmd&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&amp;quot;&lt;/span&gt;&lt;span&gt;$img&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot; Application started for &amp;#39;&lt;/span&gt;&lt;span&gt;$img&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# End of log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;=== key-handler finished ===&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make the script executable&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; +x ~/.config/sxiv/exec/key-handler&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;TERMWIN&lt;/code&gt; variable (optional)&lt;/strong&gt;:
If you want to use a terminal other than &lt;code&gt;urxvt&lt;/code&gt;, like &lt;code&gt;alacritty&lt;/code&gt;, add this to your &lt;code&gt;~/.bashrc&lt;/code&gt; / &lt;code&gt;~/.profile&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;export&lt;/span&gt;&lt;span&gt; TERMWIN&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;alacritty&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-thumbnail-sizes-optional-recompiling-sxiv&quot;&gt;4. Thumbnail Sizes (Optional: Recompiling sxiv)&lt;/h2&gt;
&lt;p&gt;By default, the available thumbnail sizes in sxiv are limited to &lt;code&gt;{ 32, 64, 96, 128, 160 }&lt;/code&gt; px. If 160px is too small, you can increase them as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Get the sources from the AUR&lt;/strong&gt; (example using &lt;code&gt;sxiv-git&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; clone https://aur.archlinux.org/sxiv-git.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sxiv-git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generate &lt;code&gt;config.h&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config.h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adjust Thumbnail Sizes&lt;/strong&gt;:
Open the &lt;code&gt;config.h&lt;/code&gt; file and find the &lt;code&gt;_THUMBS_CONFIG&lt;/code&gt; section.
Change the block to something like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#ifdef&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; _THUMBS_CONFIG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;/* thumbnail sizes in pixels (width == height): */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;static const int&lt;/span&gt;&lt;span&gt; thumb_sizes&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;[] =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 64&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 96&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 128&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 160&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 256&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 320&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 400&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;/* default thumbnail size on startup (index in thumb_sizes[]): */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;static const int&lt;/span&gt;&lt;span&gt; THUMB_SIZE &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  // starts at 256 px&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compile and install&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;make&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the New Thumbnail Sizes&lt;/strong&gt;:
In sxiv, sizes up to &lt;strong&gt;400px&lt;/strong&gt; are now available. Use &lt;code&gt;+&lt;/code&gt; to increase and &lt;code&gt;-&lt;/code&gt; to decrease the size.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-summary-of-keybindings&quot;&gt;5. Summary of Keybindings&lt;/h2&gt;
&lt;h3 id=&quot;5-1-ranger-shortcuts&quot;&gt;5.1 Ranger Shortcuts&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Start sxiv gallery in current directory&lt;/td&gt;&lt;td&gt;&lt;code&gt;gG&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h3 id=&quot;5-2-sxiv-gallery-mode-shortcuts&quot;&gt;5.2 sxiv Gallery Mode Shortcuts&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Open single-image view&lt;/td&gt;&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mark an image (for multi-selection)&lt;/td&gt;&lt;td&gt;&lt;code&gt;m&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Zoom in&lt;/td&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Zoom out&lt;/td&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“Open with…” menu (interactive)&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ctrl-x o&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Open ranger in a new terminal with file selected&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ctrl-x r&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h3 id=&quot;5-3-sxiv-single-image-mode-shortcuts&quot;&gt;5.3 sxiv Single-Image Mode Shortcuts&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Next image&lt;/td&gt;&lt;td&gt;&lt;code&gt;n&lt;/code&gt; or &lt;code&gt;Space&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Previous image&lt;/td&gt;&lt;td&gt;&lt;code&gt;p&lt;/code&gt; or &lt;code&gt;Backspace&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10 images forward&lt;/td&gt;&lt;td&gt;&lt;code&gt;]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10 images backward&lt;/td&gt;&lt;td&gt;&lt;code&gt;[&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;First image&lt;/td&gt;&lt;td&gt;&lt;code&gt;g&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Last image&lt;/td&gt;&lt;td&gt;&lt;code&gt;G&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Play/stop GIF animation&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ctrl-Space&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-debugging-logs&quot;&gt;6. Debugging &amp;amp; Logs&lt;/h2&gt;
&lt;p&gt;All actions from the &lt;code&gt;key-handler&lt;/code&gt; script are logged to &lt;code&gt;/tmp/sxiv-open.log&lt;/code&gt;. There you can see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The key that was used (&lt;code&gt;ctrl-x r&lt;/code&gt; or &lt;code&gt;ctrl-x o&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The detected &lt;strong&gt;MIME type&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The found &lt;code&gt;.desktop&lt;/code&gt; entries.&lt;/li&gt;
&lt;li&gt;The chosen application and the executed command.&lt;/li&gt;
&lt;li&gt;The ranger call.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=== key-handler started Mon Apr 28 18:01:20 CEST 2025 ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TERMWIN set to: xterm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Command argument: o&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Processing file: &amp;#39;/home/.../Example.png&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; MIME-Type: image/png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Found applications: gimp.desktop firefox.desktop ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;List file: /tmp/tmp.XXXXXX&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Choice file: /tmp/tmp.YYYYYY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Selected: gimp.desktop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Desktop entry: /usr/share/applications/gimp.desktop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Exec command: gimp-3.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Application started for &amp;#39;/home/.../Example.png&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=== key-handler finished ===&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If something goes wrong, you can check the log:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;less&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /tmp/sxiv-open.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description>
      </item>
      <item>
          <title>Vim Tip: How to Insert the Current Time with a Shortcut</title>
          <pubDate>Thu, 03 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/vim-time-insert/</link>
          <guid>https://criticalbasics.xyz/posts/vim-time-insert/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/vim-time-insert/">&lt;p&gt;When keeping a journal, logging meetings, or documenting events, an accurate timestamp is invaluable. However, manually typing the time is cumbersome and interrupts your writing flow.&lt;/p&gt;
&lt;p&gt;In this short guide, you’ll learn how to use a single, clever line in your &lt;code&gt;.vimrc&lt;/code&gt; to create a shortcut that lets you insert the current time instantly and effortlessly at any position.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;the-solution-a-shortcut-for-insert-mode&quot;&gt;The Solution: A Shortcut for Insert Mode&lt;/h2&gt;
&lt;p&gt;This method is ideal when you’re in the middle of writing and want to insert a timestamp directly into the text, for example:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;14:32 – Call from the project manager&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To do this, simply add the following line to your &lt;code&gt;~/.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Insert the current time (HH:MM) in insert mode with &amp;lt;leader&amp;gt;t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;inoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;t &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;C-R&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;strftime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;%H:%M&amp;#39;&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h3&gt;
&lt;p&gt;This single line is a perfect example of Vim’s power:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;inoremap &amp;lt;leader&amp;gt;t&lt;/code&gt;&lt;/strong&gt;: Defines a key mapping (by default &lt;code&gt;\t&lt;/code&gt;) exclusively for &lt;strong&gt;insert mode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;C-R&amp;gt;=&lt;/code&gt;&lt;/strong&gt;: This is the magic part. In insert mode, &lt;code&gt;Ctrl-R&lt;/code&gt; normally inserts the content of a register. When you add an equals sign (&lt;code&gt;=&lt;/code&gt;), Vim opens a mini-command line and evaluates the following expression.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;strftime(&#39;%H:%M&#39;)&lt;/code&gt;&lt;/strong&gt;: This is a built-in Vim function that returns the current time, formatted. &lt;code&gt;%H&lt;/code&gt; stands for the hour (24h) and &lt;code&gt;%M&lt;/code&gt; for the minute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt;&lt;/strong&gt;: Confirms the function, inserts its result (the time) at the cursor’s position, and seamlessly returns you to insert mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;How to use it:&lt;/strong&gt; The next time you’re typing in a note, just press &lt;code&gt;\&lt;/code&gt; followed by &lt;code&gt;t&lt;/code&gt;, and the current timestamp will appear instantly in the text.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;customize-it-to-your-needs&quot;&gt;Customize It to Your Needs&lt;/h2&gt;
&lt;p&gt;The best part of this method is its flexibility. You can customize the timestamp format however you like by changing the string inside the &lt;code&gt;strftime()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Here are a few popular alternatives for your &lt;code&gt;.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; -- EXAMPLE 1: Time with seconds --&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;inoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;ts&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;C-R&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;strftime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;%H:%M:%S&amp;#39;&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; -- EXAMPLE 2: Full date and time (ISO standard) --&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;inoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;dt &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;C-R&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;strftime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;%Y-%m-%d %H:%M&amp;#39;&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; -- EXAMPLE 3: US Date Format --&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;inoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;us &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;C-R&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;strftime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;%m/%d/%Y %I:%M %p&amp;#39;&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;bonus-inserting-a-timestamp-in-normal-mode&quot;&gt;Bonus: Inserting a Timestamp in Normal Mode&lt;/h2&gt;
&lt;p&gt;Sometimes you might want to insert a timestamp on its own new line. For that, a normal mode shortcut is better suited.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Insert the current time on a new line below the current one&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;nnoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;T :put &lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;strftime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;%H:%M&amp;#39;&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this mapping, you can press &lt;code&gt;\T&lt;/code&gt; in normal mode, and the time will be placed cleanly on the next line.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With this simple trick, you’ve further optimized your workflow:&lt;/p&gt;
&lt;p&gt;✅ You can insert timestamps instantly with a keystroke, without interrupting your flow.
✅ The format is fully customizable to your needs.
✅ The solution is lean, fast, and uses built-in Vim features without any extra plugins.&lt;/p&gt;
&lt;a href=&quot;https://vimhelp.org/eval.txt.html#strftime()&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📂&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;EXPLORE ALL STRFTIME() OPTIONS&lt;/span&gt;
&lt;/a&gt;
&lt;hr /&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHAT&#39;S NEXT?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Now that you’ve mastered timestamps, discover how to perfect links, navigation, and task management in our &lt;a href=&quot;/posts/vimwiki-workflow-mastered&quot;&gt;Vimwiki Workflow Guide&lt;/a&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>A Guide to Zathura: The Minimalist PDF Viewer</title>
          <pubDate>Thu, 03 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/zathura-pdf-viewer/</link>
          <guid>https://criticalbasics.xyz/posts/zathura-pdf-viewer/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/zathura-pdf-viewer/">&lt;p&gt;This tutorial will guide you through installing, configuring, and using &lt;strong&gt;Zathura&lt;/strong&gt; with the &lt;strong&gt;MuPDF backend&lt;/strong&gt; on Arch Linux, specifically tailored for an &lt;strong&gt;i3wm&lt;/strong&gt; environment. It covers installation, configuration, printing, and a comprehensive overview of the most important shortcuts.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Zathura&lt;/strong&gt; is a lightweight yet powerful PDF viewer that features a minimalist user interface, making it an excellent fit for lightweight window managers like &lt;strong&gt;i3wm&lt;/strong&gt;. By using plugin backends like &lt;strong&gt;MuPDF&lt;/strong&gt; or &lt;strong&gt;Poppler&lt;/strong&gt;, you can maintain a minimal setup without sacrificing essential features such as search, bookmarks, or printing.&lt;/p&gt;
&lt;p&gt;Advantages of Zathura:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Very few dependencies&lt;/strong&gt; (only Girara/GTK, and a backend like MuPDF or Poppler)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keyboard-centric control&lt;/strong&gt; (ideal for i3wm)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensible via plugins&lt;/strong&gt; (e.g., for Synctex or annotations)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Highly configurable&lt;/strong&gt; through a simple text file&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-installation&quot;&gt;2. Installation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install Zathura &amp;amp; the MuPDF Backend&lt;/strong&gt;
Open a terminal and execute the following command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zathura zathura-pdf-mupdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Launch Zathura&lt;/strong&gt;
After installation, you can open a PDF file like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zathura&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; document.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-setting-zathura-as-the-default-pdf-viewer&quot;&gt;3. Setting Zathura as the Default PDF Viewer&lt;/h2&gt;
&lt;p&gt;If you were previously using a different viewer like &lt;strong&gt;Evince&lt;/strong&gt; (e.g., in &lt;code&gt;mimeapps.list&lt;/code&gt;), your configuration might look like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;application/&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pdf&lt;/span&gt;&lt;span&gt;=org.gnome.Evince.desktop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make Zathura the new default for PDF files, you need to add or edit the following line in your &lt;code&gt;~/.config/mimeapps.list&lt;/code&gt; (or &lt;code&gt;~/.local/share/applications/mimeapps.list&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;[Default Applications]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;application/&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pdf&lt;/span&gt;&lt;span&gt;=org.pwmt.zathura.desktop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sets Zathura as the default application for the &lt;code&gt;application/pdf&lt;/code&gt; MIME type.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-configuring-zathura&quot;&gt;4. Configuring Zathura&lt;/h2&gt;
&lt;p&gt;Zathura reads its configuration from &lt;code&gt;~/.config/zathura/zathurarc&lt;/code&gt;. Here is an example of a minimal configuration:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ~/.config/zathura/zathurarc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 1. Set the default backend to MuPDF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set pdf-mupdf true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 2. Adjust page to fit width on open&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set adjust-open &amp;quot;fit-width&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 3. Set default zoom level (100%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set zoom 1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 4. Remap keys (optional)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map &amp;lt;C-f&amp;gt; search-forward&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map &amp;lt;C-b&amp;gt; search-backward&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 5. Set bookmark file path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set bookmark-path &amp;quot;~/.config/zathura/bookmarks&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;explanation-of-key-options&quot;&gt;Explanation of Key Options&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;set pdf-mupdf true&lt;/code&gt;: Specifies that Zathura should use the MuPDF backend instead of Poppler.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set adjust-open &quot;fit-width&quot;&lt;/code&gt;: Automatically fits the page to the window’s width when opening a document.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set zoom 1.0&lt;/code&gt;: Sets the default zoom level to 100%.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;map &amp;lt;C-f&amp;gt; search-forward&lt;/code&gt;: Remaps &lt;code&gt;Ctrl+f&lt;/code&gt; for searching forward.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;map &amp;lt;C-b&amp;gt; search-backward&lt;/code&gt;: Remaps &lt;code&gt;Ctrl+b&lt;/code&gt; for searching backward.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set bookmark-path &quot;...&quot;&lt;/code&gt;: Defines the directory where bookmark files are stored.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-printing-functionality&quot;&gt;5. Printing Functionality&lt;/h2&gt;
&lt;p&gt;Zathura supports printing directly via GTK. To print a PDF:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the PDF in Zathura:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zathura&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; document.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;In the viewer, simply press &lt;code&gt;P&lt;/code&gt; or enter the command:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:print&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;The standard &lt;strong&gt;GTK print dialog&lt;/strong&gt; will open, allowing you to select a printer, page range, scaling, and other options.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Internally, GTK generates a temporary PDF (using Cairo) and sends it to &lt;strong&gt;CUPS&lt;/strong&gt;, so no additional plugins are usually necessary.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you prefer to print directly from the shell, you can always use:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;lp&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; document.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works independently of your chosen PDF viewer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-overview-of-essential-keyboard-shortcuts&quot;&gt;6. Overview of Essential Keyboard Shortcuts&lt;/h2&gt;
&lt;p&gt;Zathura is heavily designed for keyboard control. Below are the most useful shortcuts organized by category.&lt;/p&gt;
&lt;h3 id=&quot;6-1-navigation&quot;&gt;6.1 Navigation&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Next Page&lt;/td&gt;&lt;td&gt;&lt;code&gt;j&lt;/code&gt; or &lt;code&gt;↓&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Previous Page&lt;/td&gt;&lt;td&gt;&lt;code&gt;k&lt;/code&gt; or &lt;code&gt;↑&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;First Page&lt;/td&gt;&lt;td&gt;&lt;code&gt;gg&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Last Page&lt;/td&gt;&lt;td&gt;&lt;code&gt;G&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Go to Specific Page&lt;/td&gt;&lt;td&gt;&lt;code&gt;:page &amp;lt;number&amp;gt;&lt;/code&gt; (e.g., &lt;code&gt;:page 10&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h3 id=&quot;6-2-zoom-view&quot;&gt;6.2 Zoom &amp;amp; View&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Zoom In&lt;/td&gt;&lt;td&gt;&lt;code&gt;zi&lt;/code&gt; or &lt;code&gt;+&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Zoom Out&lt;/td&gt;&lt;td&gt;&lt;code&gt;zo&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Original Size&lt;/td&gt;&lt;td&gt;&lt;code&gt;zr&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Fit to Width&lt;/td&gt;&lt;td&gt;&lt;code&gt;zb&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Fit to Height&lt;/td&gt;&lt;td&gt;&lt;code&gt;zh&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Toggle Fullscreen&lt;/td&gt;&lt;td&gt;&lt;code&gt;f&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h3 id=&quot;6-3-search-bookmarks&quot;&gt;6.3 Search &amp;amp; Bookmarks&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Search Forward&lt;/td&gt;&lt;td&gt;&lt;code&gt;/&lt;/code&gt; followed by search term&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Search Backward&lt;/td&gt;&lt;td&gt;&lt;code&gt;?&lt;/code&gt; followed by search term&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Next Search Result&lt;/td&gt;&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Previous Search Result&lt;/td&gt;&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Add Bookmark&lt;/td&gt;&lt;td&gt;&lt;code&gt;m&lt;/code&gt; (then choose a letter)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Open Bookmark List&lt;/td&gt;&lt;td&gt;&lt;code&gt;:bookmarks&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Jump to Bookmark&lt;/td&gt;&lt;td&gt;&lt;code&gt;`&lt;/code&gt; followed by the letter&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h3 id=&quot;6-4-document-operations&quot;&gt;6.4 Document Operations&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Print&lt;/td&gt;&lt;td&gt;&lt;code&gt;P&lt;/code&gt; or &lt;code&gt;:print&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Reload Document&lt;/td&gt;&lt;td&gt;&lt;code&gt;R&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Open Console (Command line in viewer)&lt;/td&gt;&lt;td&gt;&lt;code&gt;:&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h3 id=&quot;6-5-general-commands&quot;&gt;6.5 General Commands&lt;/h3&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Show Help&lt;/td&gt;&lt;td&gt;&lt;code&gt;H&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Reload Configuration&lt;/td&gt;&lt;td&gt;&lt;code&gt;:config-reload&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Quit&lt;/td&gt;&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Many of these commands can be remapped in &lt;code&gt;~/.config/zathura/zathurarc&lt;/code&gt;. See Section 4 for examples.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-summary&quot;&gt;7. Summary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zathura zathura-pdf-mupdf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;```&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;   **&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;Set as Default PDF Viewer:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;In&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;~/.config/mimeapps.list&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;```&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ini&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Default Applications]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;application/pdf&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;=org.pwmt.zathura.desktop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; Via &lt;code&gt;~/.config/zathura/zathurarc&lt;/code&gt; (see example file).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usage:&lt;/strong&gt; Keyboard-centric, with quick access to search, zoom, bookmarks, and printing (&lt;code&gt;P&lt;/code&gt; / &lt;code&gt;:print&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Printing:&lt;/strong&gt; Opens the GTK print dialog, using CUPS via Cairo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Zathura is ideal for users who want a lean, fast-starting PDF viewer with essential features, without the heavy dependencies of large desktop environments like GNOME or KDE.&lt;/p&gt;
&lt;p&gt;Enjoy reading with Zathura on i3wm&lt;/p&gt;
</description>
      </item>
      <item>
          <title>Dual Journaling with Vimwiki: How to Separate Personal and Business Notes</title>
          <pubDate>Wed, 02 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/vimwiki-dual-journaling/</link>
          <guid>https://criticalbasics.xyz/posts/vimwiki-dual-journaling/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/vimwiki-dual-journaling/">&lt;p&gt;In the &lt;a href=&quot;https://criticalbasics.xyz/posts/vimwiki-journaling-tutorial/&quot;&gt;previous post&lt;/a&gt;, we built a powerful journaling system using Vimwiki. It’s a fantastic setup, but as you use it more, a common problem emerges: professional meeting notes mix with personal reflections, and work to-dos get tangled with weekend plans.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-07-02&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Created a direct workflow for general notes:&lt;/strong&gt; Added a new custom function (&lt;code&gt;CreateGeneralNote&lt;/code&gt;) and corresponding shortcuts (&lt;code&gt;\nb&lt;/code&gt;, &lt;code&gt;\np&lt;/code&gt;) to directly create topic-based notes with a filename prompt, addressing a major workflow flaw.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-20&lt;/td&gt;&lt;td&gt;Major Revision: Clarified Wiki vs. Journal distinction, improved naming consistency for directories, and created more intuitive shortcuts.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-19&lt;/td&gt;&lt;td&gt;Initial version of the article.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;p&gt;This guide will show you how to build a &lt;strong&gt;dual-wiki system&lt;/strong&gt; to cleanly separate your personal and business notes. We will cover how to create both daily &lt;strong&gt;Journal Entries&lt;/strong&gt; and topic-based &lt;strong&gt;General Notes&lt;/strong&gt; in their correct contexts.&lt;/p&gt;
&lt;h2 id=&quot;step-1-understanding-the-structure&quot;&gt;Step 1: Understanding the Structure&lt;/h2&gt;
&lt;p&gt;Before we configure anything, let’s understand the hierarchy we are building. A &lt;strong&gt;Wiki&lt;/strong&gt; is the main container for a context (e.g., “Business”). Within that wiki, there are two types of notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;General Notes:&lt;/strong&gt; Topic-based pages like “Project Alpha Ideas” or “Meeting Checklists”. They live in the root of the wiki.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Journal Entries:&lt;/strong&gt; Date-based, daily logs. They live in the &lt;code&gt;diary/&lt;/code&gt; subdirectory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the structure we will create:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;~/Nextcloud/Notes/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── wiki-business/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── diary/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   └── 2025-07-04.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── Project Alpha.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── index.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── template-business-journal.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── wiki-personal/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── diary/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └── 2025-07-04.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── Holiday Plans.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── index.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── template-personal-journal.md&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This clean separation is the key to an organized system.&lt;/p&gt;
&lt;h2 id=&quot;step-2-update-your-vimwiki-configuration&quot;&gt;Step 2: Update Your Vimwiki Configuration&lt;/h2&gt;
&lt;p&gt;First, configure your &lt;code&gt;~/.vimrc&lt;/code&gt; to define the two wikis. Using &lt;code&gt;expand(&#39;~&#39;)&lt;/code&gt; makes the configuration robust.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Vimwiki Configuration for multiple wikis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_list&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  \&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;path&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;expand&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;~&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;/Nextcloud/Notes/wiki-business/&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;diary_template&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;template-business-journal.md&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;syntax&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;markdown&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;ext&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.md&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  \&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  \&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;path&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;expand&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;~&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;/Nextcloud/Notes/wiki-personal/&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;diary_template&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;template-personal-journal.md&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;syntax&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;markdown&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;ext&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.md&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  \&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;\&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Optional: Set a default wiki (1=first, 2=second).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_start_wiki&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &amp;quot; Make the personal wiki the default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; These settings apply to all wikis in the list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_markdown_link_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_auto_diary_index&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, create the necessary directories in your terminal:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/Nextcloud/Notes/wiki-business/diary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/Nextcloud/Notes/wiki-personal/diary&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;step-3-create-context-specific-journal-templates&quot;&gt;Step 3: Create Context-Specific Journal Templates&lt;/h2&gt;
&lt;p&gt;Create a unique template for each journal. Each template file must be placed in the &lt;strong&gt;root directory of its corresponding wiki&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;business-journal-template&quot;&gt;Business Journal Template&lt;/h4&gt;
&lt;p&gt;Create the file &lt;code&gt;~/Nextcloud/Notes/wiki-business/template-business-journal.md&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;# %Y-%m-%d — Business Journal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 🎯 Today&amp;#39;s Top 3 Priorities&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;personal-journal-template&quot;&gt;Personal Journal Template&lt;/h4&gt;
&lt;p&gt;Create the file &lt;code&gt;~/Nextcloud/Notes/wiki-personal/template-personal-journal.md&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;# %Y-%m-%d — Personal Journal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 🙏 Gratitude&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 💡 Ideas &amp;amp; Thoughts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;step-4-the-core-solution-custom-vim-functions&quot;&gt;Step 4: The Core Solution: Custom Vim Functions&lt;/h2&gt;
&lt;p&gt;A standard Vimwiki installation has two limitations for our workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;:VimwikiMakeDiaryNote&lt;/code&gt; does not automatically apply templates.&lt;/li&gt;
&lt;li&gt;There is no direct command to create a new, named topic note.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We will solve both issues with two dedicated functions in our &lt;code&gt;~/.vimrc&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;in-your-vimrc&quot;&gt;In Your &lt;code&gt;.vimrc&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Add these two functions and their corresponding shortcuts to your Vim configuration.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; ----- FUNCTION 1: FOR DAILY JOURNAL ENTRIES -----&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;function!&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; OpenJournalWithTemplate&lt;/span&gt;&lt;span&gt;(wiki_index)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Switch to the correct wiki context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  execute&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;VimwikiTabIndex &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span&gt;a:wiki_index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Create or open today&amp;#39;s diary note&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  VimwikiMakeDiaryNote&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; CRITICAL: Force Vim to update its state before we check the file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  redraw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Check if the file is new and empty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; line&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;getline&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;/span&gt;&lt;span&gt; l:wiki_config&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; g:vimwiki_list[a:wiki_index&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; - &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;/span&gt;&lt;span&gt; l:template_path&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; l:wiki_config.path&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span&gt;l:wiki_config.diary_template&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &amp;quot; If the template file exists, read its content into our new file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; filereadable&lt;/span&gt;&lt;span&gt;(l:template_path)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      execute&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;0read &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span&gt;l:template_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      1delete&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &amp;quot; Delete the initial empty line&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;      normal!&lt;/span&gt;&lt;span&gt; gg&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &amp;quot; Go to the top&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;endfunction&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; ----- FUNCTION 2: FOR GENERAL TOPIC NOTES -----&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;function!&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CreateGeneralNote&lt;/span&gt;&lt;span&gt;(wiki_index)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Switch to the correct wiki context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  execute&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;VimwikiTabIndex &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span&gt;a:wiki_index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Open the index page of that wiki&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  VimwikiIndex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Prompt the user for the name of the new note&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  let&lt;/span&gt;&lt;span&gt; l:note_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; input&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;Enter name for new note: &amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Proceed only if a name was entered&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  if !&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;empty&lt;/span&gt;&lt;span&gt;(l:note_name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &amp;quot; Go to the end of the index file and add a new link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;line&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;* [[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span&gt;l:note_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; . &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;]]&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &amp;quot; Move the cursor to the newly created line&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cursor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;line&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &amp;quot; &amp;#39;Press Enter&amp;#39; on the link to create and open the new file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    VimwikiFollowLink&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;endfunction&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; ----- KEYBOARD SHORTCUTS -----&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; For Journals (e.g., \jb for Journal-Business)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;nnoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;jb :&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; OpenJournalWithTemplate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;nnoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;jp :&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; OpenJournalWithTemplate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;2&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; For General Notes (e.g., \nb for Note-Business)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;nnoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;nb :&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CreateGeneralNote&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;nnoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;leader&lt;/span&gt;&lt;span&gt;&amp;gt;np :&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CreateGeneralNote&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;2&lt;/span&gt;&lt;span&gt;)&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;CR&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;in-your-shell-bashrc-or-zshrc&quot;&gt;In Your Shell (&lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;)&lt;/h4&gt;
&lt;p&gt;Create a full set of aliases in your shell configuration to call these functions directly.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Aliases for Journal Entries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; journalb&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;vim -c &amp;quot;call OpenJournalWithTemplate(1)&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; journalp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;vim -c &amp;quot;call OpenJournalWithTemplate(2)&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Aliases for General Topic Notes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; noteb&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;vim -c &amp;quot;call CreateGeneralNote(1)&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; notep&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;vim -c &amp;quot;call CreateGeneralNote(2)&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Optional: Shorter aliases&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; jb&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;journalb&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; jp&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;journalp&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; nb&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;noteb&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;notep&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reload your shell (&lt;code&gt;source ~/.bashrc&lt;/code&gt; or &lt;code&gt;source ~/.zshrc&lt;/code&gt;) to activate them.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-5-how-to-use-your-dual-system&quot;&gt;Step 5: How to Use Your Dual System&lt;/h2&gt;
&lt;p&gt;Your workflow is now clean, logical, and direct for both use cases.&lt;/p&gt;
&lt;h3 id=&quot;workflow-1-create-a-daily-journal-entry&quot;&gt;Workflow 1: Create a Daily Journal Entry&lt;/h3&gt;
&lt;p&gt;Use this for date-based, chronological logs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;From inside Vim:&lt;/strong&gt; Press &lt;code&gt;\jb&lt;/code&gt; (Business) or &lt;code&gt;\jp&lt;/code&gt; (Personal).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;From your terminal:&lt;/strong&gt; Run &lt;code&gt;journalb&lt;/code&gt; or &lt;code&gt;jb&lt;/code&gt; (Business) / &lt;code&gt;journalp&lt;/code&gt; or &lt;code&gt;jp&lt;/code&gt; (Personal).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Today’s journal file is created in the &lt;code&gt;diary/&lt;/code&gt; folder, and the correct template is applied.&lt;/p&gt;
&lt;h3 id=&quot;workflow-2-create-a-general-topic-note&quot;&gt;Workflow 2: Create a General Topic Note&lt;/h3&gt;
&lt;p&gt;Use this for any non-daily, topic-based note like a project plan, a checklist, or meeting notes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;From inside Vim:&lt;/strong&gt; Press &lt;code&gt;\nb&lt;/code&gt; (Business) or &lt;code&gt;\np&lt;/code&gt; (Personal).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;From your terminal:&lt;/strong&gt; Run &lt;code&gt;noteb&lt;/code&gt; or &lt;code&gt;nb&lt;/code&gt; (Business) / &lt;code&gt;notep&lt;/code&gt; or &lt;code&gt;np&lt;/code&gt; (Personal).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; You will be prompted in Vim to &lt;strong&gt;enter a name for the new note&lt;/strong&gt;. After you type a name and press Enter, the new file is created in the root of the correct wiki, and a link to it is automatically added to your &lt;code&gt;index.md&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-6-linking-between-wikis&quot;&gt;Step 6: Linking Between Wikis&lt;/h2&gt;
&lt;p&gt;The concept of linking between wikis is now much clearer. Imagine you’re in your &lt;strong&gt;personal journal&lt;/strong&gt; and have an idea for a business project.&lt;/p&gt;
&lt;p&gt;In your personal journal file, you can write:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 💡 Ideas &amp;amp; Thoughts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; I just had an idea for work, I&amp;#39;ll start a new note for it in my business wiki.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; To create it, I can just write the link here and press Enter: [[wiki1:My New Business Idea]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wiki1:&lt;/code&gt; tells Vimwiki to use the first wiki in your list (your business-wiki).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you press &lt;code&gt;Enter&lt;/code&gt;, Vimwiki creates the file &lt;code&gt;My New Business Idea.md&lt;/code&gt; in the root of your &lt;code&gt;wiki-business/&lt;/code&gt; and opens it.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;By creating two dedicated functions, you have built a powerful, intuitive, and robust system:&lt;/p&gt;
&lt;p&gt;✅ A clean separation between your &lt;strong&gt;wiki-business&lt;/strong&gt; and &lt;strong&gt;wiki-personal&lt;/strong&gt;.
✅ A clear, direct workflow for creating both daily &lt;strong&gt;Journals&lt;/strong&gt; and topic-based &lt;strong&gt;General Notes&lt;/strong&gt;.
✅ Custom &lt;strong&gt;journal templates&lt;/strong&gt; that are correctly and automatically applied.
✅ Lightning-fast, unambiguous shortcuts (&lt;code&gt;jb&lt;/code&gt;, &lt;code&gt;jp&lt;/code&gt;, &lt;code&gt;nb&lt;/code&gt;, &lt;code&gt;np&lt;/code&gt;) for both Vim and your shell.
✅ The power to intelligently link between worlds when needed.&lt;/p&gt;
&lt;p&gt;This setup transforms a simple note-taking tool into a comprehensive life management system.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/vimwiki/vimwiki&quot;&gt;Explore Vimwiki Further&lt;/a&gt; 📂&lt;/p&gt;
&lt;hr /&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHAT&#39;S NEXT?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Now that your wikis are separated and working reliably, we can explore advanced task management. In a future post, we’ll look at how to aggregate tasks from both journals into a single, unified dashboard.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Mastering the Vimwiki Workflow: A Guide to Links, Navigation, and Tasks</title>
          <pubDate>Wed, 02 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/vimwiki-workflow/</link>
          <guid>https://criticalbasics.xyz/posts/vimwiki-workflow/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/vimwiki-workflow/">&lt;p&gt;In previous guides, we built a robust foundation for our note-taking and journaling system with Vimwiki. But the best configuration is useless without a fluid, daily workflow. So, how exactly do you work with it now?&lt;/p&gt;
&lt;p&gt;This guide is your daily companion. You will learn the core concepts of Vimwiki that will elevate your productivity to a new level—from the magic of linking and lightning-fast navigation to integrated task management.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;the-heart-of-your-wiki-the-index-md&quot;&gt;The Heart of Your Wiki: The &lt;code&gt;index.md&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Each of your Vim wikis has a central homepage: the &lt;code&gt;index.md&lt;/code&gt; file located in the root directory. Think of it as your personal dashboard or table of contents for that wiki.&lt;/p&gt;
&lt;p&gt;From here, you should link to all of your important, topic-based notes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How to open the index page:&lt;/strong&gt; From anywhere in Vim, press &lt;code&gt;&amp;lt;leader&amp;gt;ww&lt;/code&gt; (usually &lt;code&gt;\ww&lt;/code&gt;) to instantly jump to the index page of the current wiki.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A well-maintained index might look like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;# Business Wiki Index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## Projects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;*&lt;/span&gt;&lt;span&gt; [[Project Alpha]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;*&lt;/span&gt;&lt;span&gt; [[Q4 Strategy Planning]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## Processes &amp;amp; Checklists&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;*&lt;/span&gt;&lt;span&gt; [[Meeting Checklist]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;*&lt;/span&gt;&lt;span&gt; [[New Employee Onboarding]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## References&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;*&lt;/span&gt;&lt;span&gt; [[Important Contacts]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;the-magic-of-linking&quot;&gt;The Magic of Linking&lt;/h2&gt;
&lt;p&gt;Creating notes and linking ideas is the core of Vimwiki. The process is brilliantly simple.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write a Link:&lt;/strong&gt; Anywhere in a wiki file, write the name of a new or existing note in double square brackets.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;I had an idea for [[Project Alpha]].&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Follow the Link:&lt;/strong&gt; Move your cursor over the link and press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;What happens?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the file &lt;code&gt;Project Alpha.md&lt;/code&gt; already exists, Vimwiki opens it.&lt;/li&gt;
&lt;li&gt;If the file &lt;strong&gt;does not&lt;/strong&gt; exist, Vimwiki automatically creates it for you and opens the new, empty file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means you never have to worry about manually creating files. You simply write down your thoughts, link concepts, and let Vimwiki build the structure in the background.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro-Tip:&lt;/strong&gt; You can also create subdirectories by using a forward slash: &lt;code&gt;[[projects/New Project]]&lt;/code&gt; will create the file &lt;code&gt;New Project.md&lt;/code&gt; inside the &lt;code&gt;projects/&lt;/code&gt; folder.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;effortless-navigation-how-to-jump-back-and-forth&quot;&gt;Effortless Navigation: How to Jump Back and Forth&lt;/h2&gt;
&lt;p&gt;Switching between notes quickly is crucial. Vimwiki primarily uses Vim’s brilliant, built-in commands for this.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Jump back to the previous note:&lt;/strong&gt; Press &lt;code&gt;Ctrl-O&lt;/code&gt;. This is the most important navigation command. It takes you right back to where you came from after following a link.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jump forward again:&lt;/strong&gt; Press &lt;code&gt;Ctrl-I&lt;/code&gt; to reverse the jump.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go back to the index page:&lt;/strong&gt; &lt;code&gt;&amp;lt;leader&amp;gt;ww&lt;/code&gt; is your “home button,” always taking you back to the main index of the current wiki.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go back to today’s journal:&lt;/strong&gt; &lt;code&gt;&amp;lt;leader&amp;gt;w&amp;lt;leader&amp;gt;w&lt;/code&gt; (or your custom mappings like &lt;code&gt;\jb&lt;/code&gt;/&lt;code&gt;\jp&lt;/code&gt;) will instantly take you to your daily journal entry.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;more-than-just-notes-practical-task-management&quot;&gt;More Than Just Notes: Practical Task Management&lt;/h2&gt;
&lt;p&gt;Vimwiki has fantastic built-in support for to-do lists. Anytime you create a checklist in Markdown format, you can change its status directly in Vim.&lt;/p&gt;
&lt;p&gt;Write a list like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] Open task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] Another task that needs to be done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, move your cursor onto one of these lines and press &lt;strong&gt;&lt;code&gt;g&amp;lt;Space&amp;gt;&lt;/code&gt;&lt;/strong&gt; (that’s &lt;code&gt;g&lt;/code&gt; followed by the spacebar).&lt;/p&gt;
&lt;p&gt;Vimwiki will cycle through the task’s status:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[ ]&lt;/code&gt; → Open&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[.]&lt;/code&gt; → Started / In Progress (optional)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[X]&lt;/code&gt; → Completed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[-]&lt;/code&gt; → Canceled / Irrelevant&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is an incredibly fast and satisfying way to manage tasks without ever leaving Vim.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;important-tips-and-tricks-for-daily-use&quot;&gt;Important Tips and Tricks for Daily Use&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rename Files (and update all links!):&lt;/strong&gt; Move your cursor onto a link to a file and run &lt;code&gt;:VimwikiRenameLink&lt;/code&gt;. Enter the new name, and Vimwiki will not only rename the file but also &lt;strong&gt;automatically update all other files&lt;/strong&gt; that link to that note.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Format Tables:&lt;/strong&gt; Create a simple table using pipes (&lt;code&gt;|&lt;/code&gt;):&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Column 1 | Column 2 |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|---|---|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| a | b |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| longer text | c |&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;Then, with your cursor inside the table, run the command &lt;code&gt;:VimwikiTable&lt;/code&gt;. Vimwiki will format it perfectly for you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Find Anything:&lt;/strong&gt; Use &lt;code&gt;:VimwikiSearch [keyword]&lt;/code&gt; to search your entire current wiki. The results are displayed in a handy quickfix list that you can navigate through quickly.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;You now have the tools to not just own Vimwiki, but to truly master it:&lt;/p&gt;
&lt;p&gt;✅ You use the &lt;strong&gt;&lt;code&gt;index.md&lt;/code&gt;&lt;/strong&gt; as your central dashboard.
✅ You seamlessly create and connect notes with the &lt;strong&gt;&lt;code&gt;[[Link]]&lt;/code&gt;&lt;/strong&gt; syntax.
✅ You navigate at lightning speed with &lt;strong&gt;&lt;code&gt;Ctrl-O&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;&amp;lt;leader&amp;gt;ww&lt;/code&gt;&lt;/strong&gt;.
✅ You manage tasks directly in your notes with &lt;strong&gt;&lt;code&gt;g&amp;lt;Space&amp;gt;&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This fluid workflow transforms Vimwiki from a simple note-taking tool into a powerful “second brain.”&lt;/p&gt;
&lt;a href=&quot;https://github.com/vimwiki/vimwiki&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📂&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;EXPLORE VIMWIKI ON GITHUB&lt;/span&gt;
&lt;/a&gt;
&lt;hr /&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            WHAT&#39;S NEXT?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Now that you’ve mastered the basic workflow, you’re ready for the ultimate organizational boost. In the next article, you’ll learn how to cleanly separate private and business notes with our &lt;a href=&quot;/posts/vimwiki-dual-journaling&quot;&gt;dual-journaling system&lt;/a&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Getting Started with Vim Plugins: A Beginner&#39;s Guide to vim-plug</title>
          <pubDate>Thu, 26 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/vim-setup-vim-plug/</link>
          <guid>https://criticalbasics.xyz/posts/vim-setup-vim-plug/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/vim-setup-vim-plug/">&lt;p&gt;So you’ve found an exciting Vim plugin—perhaps for journaling with &lt;a href=&quot;https://criticalbasics.xyz/posts/vimwiki-journaling-tutorial/&quot;&gt;Vimwiki&lt;/a&gt;—and you’re ready to supercharge your editor. This guide will walk you through setting up &lt;strong&gt;&lt;code&gt;vim-plug&lt;/code&gt;&lt;/strong&gt;, a fast, minimalist, and incredibly popular plugin manager. Once you’ve completed these steps, you’ll have a solid foundation to install any plugin you want, unlocking the true power of Vim.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-plugin-manager-and-why-vim-plug&quot;&gt;What is a Plugin Manager and Why &lt;code&gt;vim-plug&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;A plugin manager automates the tedious process of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Downloading plugin files from sources like GitHub.&lt;/li&gt;
&lt;li&gt;Placing them in the correct directories.&lt;/li&gt;
&lt;li&gt;Loading them when Vim starts.&lt;/li&gt;
&lt;li&gt;Updating and removing them easily.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I recommend &lt;strong&gt;&lt;code&gt;vim-plug&lt;/code&gt;&lt;/strong&gt; because it is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Minimalist:&lt;/strong&gt; It’s just a single file, making installation trivial.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast:&lt;/strong&gt; It can install and update plugins in parallel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy to Use:&lt;/strong&gt; The commands are simple and memorable.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-1-install-vim-plug&quot;&gt;Step 1: Install &lt;code&gt;vim-plug&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;vim-plug&lt;/code&gt; itself needs to be downloaded first. The official and easiest way is to run a single command in your terminal. This command downloads the &lt;code&gt;plug.vim&lt;/code&gt; file and places it in Vim’s &lt;code&gt;autoload&lt;/code&gt; directory, which ensures it’s loaded automatically when Vim starts.&lt;/p&gt;
&lt;p&gt;Open your terminal and execute:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fLo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/.vim/autoload/plug.vim&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --create-dirs \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. The plugin manager is now “installed.”&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-2-structure-your-vimrc-for-plugins&quot;&gt;Step 2: Structure Your &lt;code&gt;.vimrc&lt;/code&gt; for Plugins&lt;/h2&gt;
&lt;p&gt;Next, you need to tell Vim which plugins you want to use. This is done in your &lt;code&gt;~/.vimrc&lt;/code&gt; file inside a special block.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your &lt;code&gt;~/.vimrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following structure. All your plugin declarations must go &lt;strong&gt;between&lt;/strong&gt; the &lt;code&gt;call plug#begin()&lt;/code&gt; and &lt;code&gt;call plug#end()&lt;/code&gt; lines.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; 1. VIM-PLUG SECTION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; This block must be at the top of your .vimrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; plug#begin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;~/.vim/plugged&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; List your plugins here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Example:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Plug&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;vimwiki/vimwiki&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Plug&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;dracula/vim&amp;#39;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;as&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;dracula&amp;#39;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &amp;quot; A popular theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; plug#end&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; 2. YOUR CONFIGURATIONS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; All other settings go AFTER the vim-plug block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;syntax enable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;colorscheme&lt;/span&gt;&lt;span&gt; dracula&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_list&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [{ &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;~/vimwiki/&amp;#39;&lt;/span&gt;&lt;span&gt; }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; ... and so on&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;plug#begin()&lt;/code&gt;: Initializes the plugin manager. The argument (&lt;code&gt;&#39;~/.vim/plugged&#39;&lt;/code&gt;) is the directory where &lt;code&gt;vim-plug&lt;/code&gt; will download and store all your plugins.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Plug &#39;author/repository&#39;&lt;/code&gt;: This is the command to declare a plugin.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;plug#end()&lt;/code&gt;: Finalizes the list and loads the plugins.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-3-install-the-plugins-with-pluginstall&quot;&gt;Step 3: Install the Plugins with &lt;code&gt;:PlugInstall&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Now that your &lt;code&gt;.vimrc&lt;/code&gt; is configured, you can tell &lt;code&gt;vim-plug&lt;/code&gt; to fetch and install the plugins you’ve listed.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Save your &lt;code&gt;~/.vimrc&lt;/code&gt; file and &lt;strong&gt;restart Vim&lt;/strong&gt;, or source the file with &lt;code&gt;:so ~/.vimrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run the &lt;code&gt;vim-plug&lt;/code&gt; installation command inside Vim:&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:PlugInstall&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;A new window will open, showing the installation progress for each plugin. Once you see “Finished!”, you can close the status window (&lt;code&gt;:q&lt;/code&gt;) and start using your new plugins.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;your-plugin-management-cheat-sheet&quot;&gt;Your Plugin Management Cheat Sheet&lt;/h2&gt;
&lt;p&gt;Managing plugins is now simple. Here are the essential commands you’ll use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:PlugInstall&lt;/code&gt;: Install any new plugins you’ve added to your &lt;code&gt;.vimrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:PlugUpdate&lt;/code&gt;: Update all installed plugins to their latest versions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:PlugClean&lt;/code&gt;: Remove any plugins that are in your &lt;code&gt;plugged&lt;/code&gt; directory but no longer listed in your &lt;code&gt;.vimrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:PlugStatus&lt;/code&gt;: Show the status of all your plugins.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary-your-foundation-is-ready&quot;&gt;Summary: Your Foundation is Ready&lt;/h2&gt;
&lt;p&gt;Congratulations! You have successfully set up a robust system for managing Vim plugins. You now understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to install &lt;code&gt;vim-plug&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;How to structure your &lt;code&gt;.vimrc&lt;/code&gt; to declare plugins.&lt;/li&gt;
&lt;li&gt;How to install, update, and manage them with simple commands.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You are now fully equipped to customize Vim to your heart’s content and can confidently follow tutorials like our guides to &lt;a href=&quot;https://criticalbasics.xyz/posts/vimwiki-journaling-tutorial/&quot;&gt;setting up a Vimwiki journal&lt;/a&gt; or creating a &lt;a href=&quot;https://criticalbasics.xyz/posts/vimwiki-dual-journaling/&quot;&gt;dual-journaling system&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            A NOTE ON THE &lt;LEADER&gt; KEY
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Many Vim tutorials (including ours) use shortcuts like &lt;code&gt;&amp;lt;leader&amp;gt;wp&lt;/code&gt;. The &lt;code&gt;&amp;lt;leader&amp;gt;&lt;/code&gt; key is a placeholder that you can map to any key you want, preventing conflicts with Vim’s built-in commands. By default, it’s the backslash (&lt;code&gt;\&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;You can set it to a more convenient key, like the comma, by adding this to your &lt;code&gt;.vimrc&lt;/code&gt;:
&lt;code&gt;let mapleader = &quot;,&quot;&lt;/code&gt;
Now, &lt;code&gt;&amp;lt;leader&amp;gt;wp&lt;/code&gt; would be typed as &lt;code&gt;,wp&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Spell Checking in Vim: A Comprehensive Guide</title>
          <pubDate>Wed, 25 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/vim-spell-check/</link>
          <guid>https://criticalbasics.xyz/posts/vim-spell-check/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/vim-spell-check/">&lt;p&gt;Spell checking is an essential feature for any editor, and Vim comes with a powerful built-in solution. This guide will walk you through everything you need—from basic activation to advanced customization and keyboard-layout considerations.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-06-25&lt;/td&gt;&lt;td&gt;Added QWERTZ key mappings and &lt;code&gt;.sug&lt;/code&gt; file clarification.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-25&lt;/td&gt;&lt;td&gt;Initial version of the guide.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;enabling-spell-checking&quot;&gt;Enabling Spell Checking&lt;/h2&gt;
&lt;p&gt;To enable Vim’s spell checker, use the &lt;code&gt;:set spell&lt;/code&gt; command. You can type this directly into Vim for the current session, or add it to your &lt;code&gt;~/.vimrc&lt;/code&gt; file for permanent activation.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; spell&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;            &amp;quot; Turn on spell checking&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; spelllang&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;en_us&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Set the default language (e.g., US English)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first time you set a language, Vim may offer to download the dictionary file for you. This is a one-time setup for each language.&lt;/p&gt;
&lt;p&gt;For German, switch to:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; spelllang&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;de_de&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &amp;quot; Set German dictionary&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can list multiple languages, and Vim will check against all of them:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; spelllang&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;de_de,en_us&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pro-tip: Vim supports regional variants like &lt;code&gt;en_gb&lt;/code&gt; (British), &lt;code&gt;en_ca&lt;/code&gt; (Canadian), and &lt;code&gt;en_au&lt;/code&gt; (Australian).&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;managing-spell-files&quot;&gt;Managing Spell Files&lt;/h2&gt;
&lt;p&gt;Vim uses two main types of files for spell checking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The main dictionary (&lt;code&gt;.spl&lt;/code&gt; file), a compressed word list used for all checks.&lt;/li&gt;
&lt;li&gt;A supplementary suggestions file (&lt;code&gt;.sug&lt;/code&gt; file), which pre-computes lists of similar words to provide fast suggestions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;benefits-and-trade-offs-of-the-sug-file&quot;&gt;Benefits and Trade-offs of the &lt;code&gt;.sug&lt;/code&gt; file&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;With&lt;/strong&gt; &lt;code&gt;.sug&lt;/code&gt; &lt;strong&gt;downloaded&lt;/strong&gt;: &lt;code&gt;z=&lt;/code&gt; suggestion requests are fast and comprehensive, as Vim doesn’t need to calculate similarities on the fly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Without&lt;/strong&gt; &lt;code&gt;.sug&lt;/code&gt;: Vim computes suggestions at runtime, saving disk space and RAM until a suggestion is needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;on-demand-loading&quot;&gt;On-Demand Loading&lt;/h4&gt;
&lt;p&gt;Vim &lt;strong&gt;only loads&lt;/strong&gt; the &lt;code&gt;.sug&lt;/code&gt; file into memory when you invoke suggestions (e.g., by pressing &lt;code&gt;z=&lt;/code&gt;). Simply enabling spell check and navigating errors with &lt;code&gt;]s&lt;/code&gt;/&lt;code&gt;[s&lt;/code&gt; won’t load the larger &lt;code&gt;.sug&lt;/code&gt; file, keeping your memory footprint minimal until you request corrections.&lt;/p&gt;
&lt;h2 id=&quot;quick-navigation-and-corrections&quot;&gt;Quick Navigation and Corrections&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;]s&lt;/code&gt; : Jump to the next misspelled word&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[s&lt;/code&gt; : Jump to the previous misspelled word&lt;/li&gt;
&lt;li&gt;&lt;code&gt;z=&lt;/code&gt; : On a highlighted word, opens the suggestion list&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zg&lt;/code&gt; : Add word to &lt;strong&gt;g&lt;/strong&gt;ood list (your personal dictionary)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zw&lt;/code&gt; : Mark word as &lt;strong&gt;w&lt;/strong&gt;rong&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Example vimrc settings:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; spell&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; spelllang&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span&gt;de_de,en_us&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Optional: Define a custom file for your personal dictionary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; spellfile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=~&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt;/.vim/&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;spell&lt;/span&gt;&lt;span&gt;/en.utf-&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;8&lt;/span&gt;&lt;span&gt;.add&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;keyboard-layouts-and-key-mappings&quot;&gt;Keyboard Layouts and Key Mappings&lt;/h2&gt;
&lt;p&gt;Vim’s navigation commands rely on specific characters (&lt;code&gt;]&lt;/code&gt;, &lt;code&gt;[&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt;), not on physical keys. Below we cover the standard QWERTY layout and the German QWERTZ variant.&lt;/p&gt;
&lt;h3 id=&quot;international-qwerty-default-mapping&quot;&gt;International QWERTY (Default Mapping)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;]&lt;/code&gt; then &lt;code&gt;s&lt;/code&gt; to go to the next misspelling.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;[&lt;/code&gt; then &lt;code&gt;s&lt;/code&gt; to go to the previous misspelling.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No special configuration is needed on US/UK keyboards, where &lt;code&gt;[&lt;/code&gt; and &lt;code&gt;]&lt;/code&gt; are directly accessible.&lt;/p&gt;
&lt;h3 id=&quot;german-qwertz-layout&quot;&gt;German QWERTZ Layout&lt;/h3&gt;
&lt;p&gt;On German keyboards, the square brackets require &lt;code&gt;AltGr&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[&lt;/code&gt;: &lt;code&gt;AltGr + 8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;]&lt;/code&gt;: &lt;code&gt;AltGr + 9&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thus, to navigate spelling corrections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AltGr + 9&lt;/code&gt;, then &lt;code&gt;s&lt;/code&gt; → &lt;code&gt;]s&lt;/code&gt; (next error)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AltGr + 8&lt;/code&gt;, then &lt;code&gt;s&lt;/code&gt; → &lt;code&gt;[s&lt;/code&gt; (previous error)&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            QUICK KEY MAPPINGS ON QWERTZ
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;To simplify this, add these mappings to your &lt;code&gt;~/.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; F7: Next misspelling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;nnoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;F7&lt;/span&gt;&lt;span&gt;&amp;gt; ]s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; F6: Previous misspelling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;nnoremap&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;F6&lt;/span&gt;&lt;span&gt;&amp;gt; [s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use &lt;code&gt;nnoremap&lt;/code&gt; to create a non-recursive mapping in Normal mode, which is the safest way to define custom shortcuts. Now a single press of &lt;code&gt;F7&lt;/code&gt; or &lt;code&gt;F6&lt;/code&gt; navigates errors without needing &lt;code&gt;AltGr&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Vim’s spell checker is both versatile and efficient. By understanding its core commands and how to adapt them to your keyboard layout, you can keep your writing error-free across multiple languages. Incorporate these settings into your Vim configuration for a seamless workflow.&lt;/p&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            KEY COMMANDS AT A GLANCE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Quick reference: Navigate Errors with &lt;code&gt;]s&lt;/code&gt; (next) and &lt;code&gt;[s&lt;/code&gt; (previous); get suggestions with &lt;code&gt;z=&lt;/code&gt;; add to dictionary with &lt;code&gt;zg&lt;/code&gt;; mark as wrong with &lt;code&gt;zw&lt;/code&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;For a deeper dive into all available options, the official documentation is an excellent resource.&lt;/p&gt;
&lt;a href=&quot;https://vimhelp.org/spell.txt.html&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📖&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;READ THE OFFICIAL DOCS&lt;/span&gt;
&lt;/a&gt;
</description>
      </item>
      <item>
          <title>How to Keep a Structured Markdown Journal Using Vimwiki</title>
          <pubDate>Thu, 19 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/vimwiki-journaling-tutorial/</link>
          <guid>https://criticalbasics.xyz/posts/vimwiki-journaling-tutorial/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/vimwiki-journaling-tutorial/">&lt;p&gt;Journaling has long been an effective way to reflect, track tasks, and document ideas or conversations. But if you’re a terminal-based user who enjoys the minimalism of Vim, Markdown, and data ownership — you’re in luck. In this post, you’ll learn how to set up a &lt;strong&gt;lightweight, private, and highly productive journaling system&lt;/strong&gt; using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/vimwiki/vimwiki&quot;&gt;&lt;code&gt;vimwiki&lt;/code&gt;&lt;/a&gt;, all in plain text files synced via Nextcloud.&lt;/p&gt;
&lt;p&gt;Whether you’re logging calls, capturing thoughts, or tracking your daily wins, this setup will help you keep everything organized — without giving up control to a third-party app.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-06-19&lt;/td&gt;&lt;td&gt;Restructured article to move quick access methods into Step 3 for better visibility.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-18&lt;/td&gt;&lt;td&gt;Major revision: Added to-do lists, improved configuration, and corrected template/alias usage.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-17&lt;/td&gt;&lt;td&gt;Initial version of this article.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;why-use-vimwiki-for-journaling&quot;&gt;Why Use Vimwiki for Journaling?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;vimwiki&lt;/code&gt; is a Vim plugin that transforms your editor into a personal wiki. It’s lightweight, fast, and supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Daily journal entries (diary mode)&lt;/li&gt;
&lt;li&gt;Linked notes for projects or topics&lt;/li&gt;
&lt;li&gt;To-do lists and simple task tracking&lt;/li&gt;
&lt;li&gt;Markdown syntax for compatibility&lt;/li&gt;
&lt;li&gt;Full offline access — works with Nextcloud or any sync service&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re already storing notes in Markdown, this is a perfect upgrade.&lt;/p&gt;
&lt;h2 id=&quot;step-1-install-vimwiki&quot;&gt;Step 1: Install &lt;code&gt;vimwiki&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/junegunn/vim-plug&quot;&gt;&lt;code&gt;vim-plug&lt;/code&gt;&lt;/a&gt; (or your plugin manager of choice), add this to your &lt;code&gt;.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;Plug&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;vimwiki/vimwiki&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then launch Vim and run:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:PlugInstall&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re not using &lt;code&gt;vim-plug&lt;/code&gt;, check the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/vimwiki/vimwiki&quot;&gt;installation instructions here&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-2-configure-vimwiki-to-use-markdown&quot;&gt;Step 2: Configure Vimwiki to Use Markdown&lt;/h2&gt;
&lt;p&gt;In your &lt;code&gt;~/.vimrc&lt;/code&gt;, configure &lt;code&gt;vimwiki&lt;/code&gt; to store files in a Markdown format inside your Nextcloud folder. This configuration is cleaner and easier to maintain.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Vimwiki Configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_list&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;path&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;~/Nextcloud/Notes/wiki/&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &amp;quot; Path to your wiki&amp;#39;s root folder&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;syntax&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;markdown&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;             &amp;quot; Use Markdown syntax&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  \&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;ext&amp;#39;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;.md&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;                      &amp;quot; Use .md as the file extension&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;\&lt;/span&gt;&lt;span&gt;}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Ensures that created links include the .md extension for better compatibility&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_markdown_link_ext&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Automatically creates an index of all diary entries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_auto_diary_index&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the necessary folders manually if they don’t exist:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ~/Nextcloud/Notes/wiki/diary&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-3-creating-and-accessing-your-daily-journal&quot;&gt;Step 3: Creating and Accessing Your Daily Journal&lt;/h2&gt;
&lt;p&gt;The core of your journaling workflow is creating or opening the note for the current day. Here are the best ways to do it.&lt;/p&gt;
&lt;h3 id=&quot;the-basic-command&quot;&gt;The Basic Command&lt;/h3&gt;
&lt;p&gt;The fundamental command to create or open today’s journal entry is:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:VimwikiMakeDiaryNote&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will create a file like &lt;code&gt;~/Nextcloud/Notes/wiki/diary/2025-06-21.md&lt;/code&gt; if it doesn’t exist, and open it otherwise.&lt;/p&gt;
&lt;h3 id=&quot;recommended-methods-for-quick-access&quot;&gt;Recommended Methods for Quick Access&lt;/h3&gt;
&lt;p&gt;While the basic command works, typing it every time is impractical. For a fast and efficient workflow, use these shortcuts instead.&lt;/p&gt;
&lt;h4 id=&quot;method-1-from-inside-vim-the-fastest-way&quot;&gt;Method 1: From Inside Vim (The Fastest Way)&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;vimwiki&lt;/code&gt; comes with a built-in keyboard shortcut that is perfect for daily use. While in Vim’s normal mode, simply press:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;leader&amp;gt;w&amp;lt;leader&amp;gt;w&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is the most efficient way to open your journal when you are already working in Vim. The &lt;code&gt;&amp;lt;leader&amp;gt;&lt;/code&gt; key is typically the backslash (&lt;code&gt;\&lt;/code&gt;) by default.&lt;/p&gt;
&lt;h4 id=&quot;method-2-from-your-terminal&quot;&gt;Method 2: From Your Terminal&lt;/h4&gt;
&lt;p&gt;For moments when you want to jump directly into your journal from the command line, a shell alias is the perfect tool. Add this line to your &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;alias&lt;/span&gt;&lt;span&gt; journal&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;vim -c &amp;quot;VimwikiMakeDiaryNote&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After reloading your shell, you can now simply type &lt;code&gt;journal&lt;/code&gt; in your terminal. This will launch Vim and immediately open today’s diary entry, applying your template if it’s a new day.&lt;/p&gt;
&lt;h3 id=&quot;example-entry&quot;&gt;Example Entry&lt;/h3&gt;
&lt;p&gt;Regardless of which method you use to open it, your daily note will look something like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;# 2025-06-21&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 09:02 – Call with Sarah&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Discussed the project milestones. Need to follow up next Tuesday.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 13:45 – Idea&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Use &lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;`jrnl`&lt;/span&gt;&lt;span&gt; CLI for quick journal entries via terminal.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 20:15 – Reflection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Today was productive. Really enjoying the new Vim-based workflow.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-4-create-and-follow-internal-links&quot;&gt;Step 4: Create and Follow Internal Links&lt;/h2&gt;
&lt;p&gt;Link to another page in your wiki using &lt;code&gt;vimwiki&lt;/code&gt;’s native syntax:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[[Project Alpha]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pressing &lt;code&gt;Enter&lt;/code&gt; on this link will create and navigate to &lt;code&gt;Project Alpha.md&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For universal compatibility with other Markdown editors (like Obsidian or QOwnNotes), you can use a standard Markdown link. &lt;code&gt;vimwiki&lt;/code&gt; will still follow it if you press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF;text-decoration: underline;&quot;&gt;Project Alpha&lt;/span&gt;&lt;span&gt;](&lt;/span&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;Project%20Alpha.md&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key difference is that &lt;code&gt;[[Project Alpha]]&lt;/code&gt; is deeply integrated into &lt;code&gt;vimwiki&lt;/code&gt;’s features (like backlinking), while the standard link is more portable across different applications.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;step-5-create-a-diary-template-optional&quot;&gt;Step 5: Create a Diary Template (Optional)&lt;/h2&gt;
&lt;p&gt;Add a default template for your daily entries. It’s best practice to store the template in your wiki’s root directory.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create the template file: &lt;code&gt;~/Nextcloud/Notes/wiki/template.md&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; &lt;code&gt;vimwiki&lt;/code&gt; uses &lt;code&gt;strftime&lt;/code&gt; format codes, not &lt;code&gt;{{placeholders}}&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;# %Y-%m-%d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## ☎️ Calls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 💡 Ideas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## ✅ Tasks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 📌 Notes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;## 🔁 Reflection&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add this line to your &lt;code&gt;.vimrc&lt;/code&gt;. Using a relative path makes your config more robust.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;span&gt; g:vimwiki_diary_template&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;template.md&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Every new diary file created with &lt;code&gt;:VimwikiMakeDiaryNote&lt;/code&gt; (or the shortcuts) will now use this layout.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;bonus-tips&quot;&gt;Bonus Tips&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Manage To-Do Lists:&lt;/strong&gt; &lt;code&gt;vimwiki&lt;/code&gt; has excellent support for task lists. Use &lt;code&gt;g&amp;lt;Space&amp;gt;&lt;/code&gt; on a list item in Vim to cycle through states.&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] An open task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF;text-decoration: underline;&quot;&gt;.&lt;/span&gt;&lt;span&gt;] A task in progress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #DBEDFF;text-decoration: underline;&quot;&gt;X&lt;/span&gt;&lt;span&gt;] A completed task&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quick Navigation:&lt;/strong&gt; After following a link, press &lt;code&gt;Ctrl-O&lt;/code&gt; to go back to the previous location and &lt;code&gt;Ctrl-I&lt;/code&gt; to go forward.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diary Index:&lt;/strong&gt; Use &lt;code&gt;:VimwikiDiaryIndex&lt;/code&gt; to open the &lt;code&gt;diary/index.md&lt;/code&gt; — a central view of all your entries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search:&lt;/strong&gt; Use &lt;code&gt;:VimwikiSearch KEYWORD&lt;/code&gt; to find entries across your entire wiki.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Syncing:&lt;/strong&gt; Sync your &lt;code&gt;wiki/&lt;/code&gt; folder with &lt;strong&gt;Nextcloud&lt;/strong&gt;, and view or edit it from mobile apps like &lt;strong&gt;Markor (Android)&lt;/strong&gt; or &lt;strong&gt;1Writer (iOS)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With &lt;code&gt;vimwiki&lt;/code&gt;, you can build a minimal yet powerful journaling system:&lt;/p&gt;
&lt;p&gt;✅ Fully Markdown-compatible
✅ Terminal- and Vim-native
✅ Works offline and syncs via Nextcloud
✅ Extendable with links, to-do lists, templates, and more&lt;/p&gt;
&lt;p&gt;No bloated app, no subscription, no cloud lock-in.&lt;/p&gt;
&lt;a href=&quot;https://github.com/vimwiki/vimwiki&quot; class=&quot;retro-button&quot;&gt;
    &lt;span class=&quot;emoji&quot;&gt;📂&lt;/span&gt;&lt;span class=&quot;button-text&quot;&gt;TRY VIMWIKI NOW&lt;/span&gt;
&lt;/a&gt;
&lt;hr /&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            LOOKING FOR MORE VIM TIPS?
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;In a future post, we’ll explore how to integrate &lt;code&gt;jrnl&lt;/code&gt; CLI with &lt;code&gt;vimwiki&lt;/code&gt;, add backlinks support, and create a task dashboard — all using plain Markdown.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</description>
      </item>
      <item>
          <title>Retro-Compatible Zola Theme Showcase</title>
          <pubDate>Mon, 16 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://criticalbasics.xyz/posts/theme-showcase/</link>
          <guid>https://criticalbasics.xyz/posts/theme-showcase/</guid>
          <description xml:base="https://criticalbasics.xyz/posts/theme-showcase/">&lt;p&gt;Welcome to this comprehensive showcase of the Retro-Compatible Zola Theme! This article demonstrates all the features, elements, shortcodes, and styling options available in this unique theme designed for maximum backward compatibility with browsers dating back to the 90s.&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;styled-table-container changelog-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-09-08&lt;/td&gt;&lt;td&gt;Added optional individual article images, a cookie-free page-load counter, and JavaScript-calculated system uptime.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-07-11&lt;/td&gt;&lt;td&gt;Improved accessibility with skip links, focus indicators, and screenreader support&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-16&lt;/td&gt;&lt;td&gt;Initial version of the theme showcase&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-16&lt;/td&gt;&lt;td&gt;Added code block styling with retro terminal look&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-16&lt;/td&gt;&lt;td&gt;Integration of additional fonts (Visitor, PixelOperator, Petiote, Virtual DJ, 5x5, Ambitsek, AddStandardBitmap)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-16&lt;/td&gt;&lt;td&gt;Headings highlighted with color (Purple)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2025-06-16&lt;/td&gt;&lt;td&gt;Added changelog table&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;what-is-zola&quot;&gt;What is Zola?&lt;/h1&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.getzola.org/&quot;&gt;Zola&lt;/a&gt; is a blazing-fast static site generator (SSG) written in Rust. It takes your content written in Markdown, applies templates, and generates a complete HTML website that can be served by any web server. Some key features of Zola include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Speed&lt;/strong&gt;: Built with Rust for exceptional performance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: Easy to use with a single binary&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: Powerful templating with Tera&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in Features&lt;/strong&gt;: Syntax highlighting, search, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live Reload&lt;/strong&gt;: Instant preview of changes during development&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;about-this-theme&quot;&gt;About This Theme&lt;/h1&gt;
&lt;p&gt;The Retro-Compatible Zola Theme combines nostalgic aesthetics with modern functionality, offering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maximum Backward Compatibility&lt;/strong&gt;: Support for browsers dating back to the 90s&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responsive Design&lt;/strong&gt;: Optimized for desktop, tablet, and mobile devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retro Shortcodes&lt;/strong&gt;: Special retro-style formatting elements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pixel Fonts&lt;/strong&gt;: VT323 and Perfect DOS VGA 437 for the authentic look&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Three-Column Layout&lt;/strong&gt;: Classic web design with modern responsiveness&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            THEME PURPOSE
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This theme was specifically designed to provide a nostalgic web experience while maintaining compatibility with both vintage and modern browsers. It’s perfect for retro computing enthusiasts, digital preservation projects, or anyone who appreciates the aesthetic of early web design.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;compatibility-features&quot;&gt;Compatibility Features&lt;/h1&gt;
&lt;h2 id=&quot;browser-compatibility&quot;&gt;Browser Compatibility&lt;/h2&gt;
&lt;p&gt;This theme is designed to work with browsers dating back to the 90s, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Netscape Navigator 3.0 and earlier&lt;/li&gt;
&lt;li&gt;Internet Explorer 3.0 and earlier&lt;/li&gt;
&lt;li&gt;Opera 3.0 and earlier&lt;/li&gt;
&lt;li&gt;Early WebTV browsers&lt;/li&gt;
&lt;li&gt;Text-based browsers like Lynx&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;technical-compatibility-features&quot;&gt;Technical Compatibility Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTML 4.01 Strict Doctype&lt;/strong&gt;: For maximum compatibility&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Table-based layouts&lt;/strong&gt;: Instead of Flexbox or Grid&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simple color definitions&lt;/strong&gt;: Using hexadecimal color codes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive JavaScript&lt;/strong&gt;: Core content works without JavaScript; the visitor counter and uptime display enhance themselves when it is available&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email-based forms&lt;/strong&gt;: For guestbook and contact functionality&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;font-showcase&quot;&gt;Font Showcase&lt;/h1&gt;
&lt;p&gt;This theme uses special pixel fonts to create an authentic retro look. Here’s a showcase of the main fonts used:&lt;/p&gt;
&lt;h2 id=&quot;main-fonts&quot;&gt;Main Fonts&lt;/h2&gt;
&lt;div style=&quot;margin: 30px 0; padding: 20px; background-color: #1e1e1e; border: 1px solid #333;&quot;&gt;
  &lt;p style=&quot;font-family: &#39;VT323&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;VT323&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Perfect DOS VGA 437&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Perfect DOS VGA 437&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Commodore 64&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Commodore 64&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Consolas&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Consolas&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Courier New&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Courier New&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Visitor&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Visitor&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;PixelOperator&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;PixelOperator&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Petiote&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Petiote&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Virtual DJ&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Virtual DJ&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;5x5&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;5x5&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Ambitsek&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Ambitsek&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;AddStandardBitmap&#39;, monospace; font-size: 24px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;AddStandardBitmap&lt;/strong&gt;: The quick brown fox jumps over the lazy dog. 1234567890 !@#$%^&amp;*()
  &lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;special-font-serenityos-emoji&quot;&gt;Special Font: SerenityOS-Emoji&lt;/h2&gt;
&lt;div style=&quot;margin: 30px 0; padding: 20px; background-color: #1e1e1e; border: 1px solid #333;&quot;&gt;
  &lt;p style=&quot;font-family: &#39;SerenityOS-Emoji&#39;; font-size: 32px; line-height: 1.5; letter-spacing: 5px;&quot;&gt;
    😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 😚 😋 😛 😝 😜
  &lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;font-combinations&quot;&gt;Font Combinations&lt;/h2&gt;
&lt;div style=&quot;margin: 30px 0; padding: 20px; background-color: #1e1e1e; border: 1px solid #333;&quot;&gt;
  &lt;h3 style=&quot;font-family: &#39;VT323&#39;, &#39;Perfect DOS VGA 437&#39;, monospace; margin-bottom: 15px;&quot;&gt;
    Header Style (VT323, Perfect DOS VGA 437)
  &lt;/h3&gt;
  &lt;p style=&quot;font-family: &#39;VT323&#39;, monospace; margin-bottom: 15px;&quot;&gt;
    This is a paragraph in VT323 font. It&#39;s designed to look like old terminal text but with better readability for longer content blocks.
  &lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;Perfect DOS VGA 437&#39;, monospace; margin-bottom: 15px; font-size: 16px;&quot;&gt;
    &lt;code&gt;This is code text in Perfect DOS VGA 437 font.&lt;/code&gt;
  &lt;/p&gt;
&lt;p&gt;&lt;button class=&quot;retro-button&quot; style=&quot;margin-bottom: 10px; display: block;&quot;&gt;Button Text&lt;/button&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;font-sizes-comparison&quot;&gt;Font Sizes Comparison&lt;/h2&gt;
&lt;div style=&quot;margin: 30px 0; padding: 20px; background-color: #1e1e1e; border: 1px solid #333;&quot;&gt;
  &lt;h1 style=&quot;font-family: &#39;VT323&#39;, &#39;Perfect DOS VGA 437&#39;, monospace;&quot;&gt;Heading 1 (26px)&lt;/h1&gt;
  &lt;h2 style=&quot;font-family: &#39;VT323&#39;, &#39;Perfect DOS VGA 437&#39;, monospace;&quot;&gt;Heading 2 (22px)&lt;/h2&gt;
  &lt;h3 style=&quot;font-family: &#39;VT323&#39;, &#39;Perfect DOS VGA 437&#39;, monospace;&quot;&gt;Heading 3 (20px)&lt;/h3&gt;
  &lt;p style=&quot;font-family: &#39;VT323&#39;, monospace;&quot;&gt;Regular paragraph text (20px)&lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;VT323&#39;, monospace; font-size: 16px;&quot;&gt;Small text (16px)&lt;/p&gt;
  &lt;p style=&quot;font-family: &#39;VT323&#39;, monospace; font-size: 14px;&quot;&gt;Extra small text (14px)&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;shortcodes&quot;&gt;Shortcodes&lt;/h1&gt;
&lt;p&gt;The theme includes various shortcodes to enhance your content with retro-style elements.&lt;/p&gt;
&lt;h2 id=&quot;infoboxes&quot;&gt;Infoboxes&lt;/h2&gt;
&lt;p&gt;Infoboxes are used to highlight important information in different styles:&lt;/p&gt;
&lt;h3 id=&quot;information-box&quot;&gt;Information Box&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            INFORMATION
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This is a standard information box for general notices and information.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;warning-box&quot;&gt;Warning Box&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            WARNING
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This is a warning box for important notices and potential issues.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id=&quot;tip-box&quot;&gt;Tip Box&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            TIP
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;This is a helpful tip to improve your experience with the theme.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&quot;retro-dividers&quot;&gt;Retro Dividers&lt;/h2&gt;
&lt;p&gt;Dividers help separate content sections with retro-style lines:&lt;/p&gt;
&lt;h3 id=&quot;single-line-divider&quot;&gt;Single Line Divider&lt;/h3&gt;
&lt;hr size=&quot;1&quot; noshade color=&quot;#666666&quot; style=&quot;margin: 15px 0;&quot;&gt;
&lt;h3 id=&quot;double-line-divider&quot;&gt;Double Line Divider&lt;/h3&gt;
&lt;hr size=&quot;2&quot; noshade color=&quot;#666666&quot; style=&quot;margin: 15px 0; border-style: double;&quot;&gt;
&lt;h3 id=&quot;dashed-line-divider&quot;&gt;Dashed Line Divider&lt;/h3&gt;
&lt;hr size=&quot;1&quot; noshade color=&quot;#666666&quot; style=&quot;margin: 15px 0; border-style: dashed;&quot;&gt;
&lt;h2 id=&quot;ascii-art&quot;&gt;ASCII Art&lt;/h2&gt;
&lt;p&gt;The theme supports ASCII art through a dedicated shortcode:&lt;/p&gt;
&lt;pre style=&quot;font-family: &#39;Perfect DOS VGA 437&#39;, monospace; 
            line-height: 1.0; 
            color: #e0e0e0; 
            background-color: #121212; 
            padding: 15px; 
            border: 1px solid #666666; 
            overflow: auto; 
            white-space: pre; 
            font-size: 14px;&quot;&gt;
  ____      _             ____            _          
 / ___|_ __(_) |_ _   _  | __ )  __ _ ___(_) ___ ___ 
| |   | &#39;__| | __| | | | |  _ \ / _` / __| |/ __/ __|
| |___| |  | | |_| |_| | | |_) | (_| \__ \ | (__\__ \
 \____|_|  |_|\__|\__, | |____/ \__,_|___/_|\___|___/
                  |___/                              
&lt;/pre&gt;
&lt;pre style=&quot;font-family: &#39;Perfect DOS VGA 437&#39;, monospace; 
            line-height: 1.0; 
            color: #e0e0e0; 
            background-color: #121212; 
            padding: 15px; 
            border: 1px solid #666666; 
            overflow: auto; 
            white-space: pre; 
            font-size: 14px;&quot;&gt;
 _____  _____  _____  _____  _____  _____  _____  _____  _____  _____ 
|_____||_____||_____||_____||_____||_____||_____||_____||_____||_____|
                                                                      
 _____                                                         _____ 
|_____|  _____ _____ _____ _____ _____ _____ _____ _____      |_____|
        |_____||_____||_____||_____||_____||_____||_____|            
 _____                                                         _____ 
|_____|  _____ _____ _____ _____ _____ _____ _____ _____      |_____|
        |_____||_____||_____||_____||_____||_____||_____|            
 _____                                                         _____ 
|_____||_____||_____||_____||_____||_____||_____||_____||_____||_____|
&lt;/pre&gt;
&lt;pre style=&quot;font-family: &#39;Perfect DOS VGA 437&#39;, monospace; 
            line-height: 1.0; 
            color: #e0e0e0; 
            background-color: #121212; 
            padding: 15px; 
            border: 1px solid #666666; 
            overflow: auto; 
            white-space: pre; 
            font-size: 14px;&quot;&gt;
  _______ _    _ ______  __  __  ______      _______ _    _ _____  ______          _______ ______ 
 |__   __| |  | |  ____|/_ |/_ |/ __ \ \    / / ____| |  | |  __ \|  ____|   /\   |__   __|  ____|
    | |  | |__| | |__    | | | | |  | \ \  / / (___ | |__| | |  | | |__     /  \     | |  | |__   
    | |  |  __  |  __|   | | | | |  | |\ \/ / \___ \|  __  | |  | |  __|   / /\ \    | |  |  __|  
    | |  | |  | | |____  | | | | |__| | \  /  ____) | |  | | |__| | |____ / ____ \   | |  | |____ 
    |_|  |_|  |_|______| |_| |_|\____/   \/  |_____/|_|  |_|_____/|______/_/    \_\  |_|  |______|
                                                                                                  
  _______ _    _ ______  __  __  ______      _______ _    _ _____  ______          _______ ______ 
 |__   __| |  | |  ____|/_ |/_ |/ __ \ \    / / ____| |  | |  __ \|  ____|   /\   |__   __|  ____|
    | |  | |__| | |__    | | | | |  | \ \  / / (___ | |__| | |  | | |__     /  \     | |  | |__   
    | |  |  __  |  __|   | | | | |  | |\ \/ / \___ \|  __  | |  | |  __|   / /\ \    | |  |  __|  
    | |  | |  | | |____  | | | | |__| | \  /  ____) | |  | | |__| | |____ / ____ \   | |  | |____ 
    |_|  |_|  |_|______| |_| |_|\____/   \/  |_____/|_|  |_|_____/|______/_/    \_\  |_|  |______|
                                                                                                  
  _______ _    _ ______  __  __  ______      _______ _    _ _____  ______          _______ ______ 
 |__   __| |  | |  ____|/_ |/_ |/ __ \ \    / / ____| |  | |  __ \|  ____|   /\   |__   __|  ____|
    | |  | |__| | |__    | | | | |  | \ \  / / (___ | |__| | |  | | |__     /  \     | |  | |__   
    | |  |  __  |  __|   | | | | |  | |\ \/ / \___ \|  __  | |  | |  __|   / /\ \    | |  |  __|  
    | |  | |  | | |____  | | | | |__| | \  /  ____) | |  | | |__| | |____ / ____ \   | |  | |____ 
    |_|  |_|  |_|______| |_| |_|\____/   \/  |_____/|_|  |_|_____/|______/_/    \_\  |_|  |______|
&lt;/pre&gt;
&lt;h2 id=&quot;additional-code-examples&quot;&gt;Additional Code Examples&lt;/h2&gt;
&lt;h3 id=&quot;rust-example-zola-is-written-in-rust&quot;&gt;Rust Example (Zola is written in Rust!)&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;collections&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;HashMap&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    // Create a new HashMap to store user scores&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let mut&lt;/span&gt;&lt;span&gt; scores&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    // Insert some values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    scores&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Blue&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    scores&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Yellow&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 50&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    scores&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Red&amp;quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 25&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    // Access a value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;/span&gt;&lt;span&gt; team_name&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Blue&amp;quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; scores&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;team_name)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;unwrap_or&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Team {} score: {}&amp;quot;&lt;/span&gt;&lt;span&gt;, team_name, score);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    // Iterate over all key-value pairs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (key, value)&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in &amp;amp;&lt;/span&gt;&lt;span&gt;scores {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;{}: {}&amp;quot;&lt;/span&gt;&lt;span&gt;, key, value);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;html-example&quot;&gt;HTML Example&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;!&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;DOCTYPE&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; HTML PUBLIC&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;-//W3C//DTD HTML 4.01//EN&amp;quot; &amp;quot;http://www.w3.org/TR/html4/strict.dtd&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;html&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;head&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;title&lt;/span&gt;&lt;span&gt;&amp;gt;Retro Web Page&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;title&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; http-equiv&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; content&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;text/html; charset=utf-8&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        body&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            background-color&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; #000000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            color&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; #33ff33&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            font-family&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Courier New&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; monospace&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        table&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            border-collapse&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; collapse&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            width&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        td&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            border&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; solid #444444&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            padding&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;head&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;body&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;h1&lt;/span&gt;&lt;span&gt;&amp;gt;Welcome to My Retro Website&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;h1&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;This is a simple example of HTML 4.01 Strict.&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;table&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;tr&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;Row 1, Cell 1&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;Row 1, Cell 2&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;tr&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;tr&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;Row 2, Cell 1&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;Row 2, Cell 2&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;td&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;tr&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;table&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;body&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;html&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;layout-features&quot;&gt;Layout Features&lt;/h1&gt;
&lt;p&gt;The theme uses a three-column layout:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Left Sidebar&lt;/strong&gt;: Navigation, search, and status panels&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Main Content&lt;/strong&gt;: Articles and primary content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Right Sidebar&lt;/strong&gt;: Additional links, visitor counter, and GIF panels&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The layout automatically collapses on mobile devices for better readability.&lt;/p&gt;
&lt;h2 id=&quot;retro-panels&quot;&gt;Retro Panels&lt;/h2&gt;
&lt;p&gt;The theme includes various retro-style panels:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Status Panel&lt;/strong&gt;: Displays an animated GIF showing the current status&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Links Panel&lt;/strong&gt;: List of useful web links with matching emojis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Obligatory GIFs Panel&lt;/strong&gt;: Display of animated GIFs in retro style&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visitor Counter&lt;/strong&gt;: Cookie-free page-load counter with a digital display&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;visitor-counter-and-system-uptime&quot;&gt;Visitor Counter and System Uptime&lt;/h2&gt;
&lt;p&gt;The visitor panel is intentionally small and old-web styled, but it uses two different mechanisms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System uptime&lt;/strong&gt; is calculated in the browser from the configured &lt;code&gt;site_launch_date&lt;/code&gt;. It needs no cookies or network request.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visitors&lt;/strong&gt; is a page-load counter. The browser requests an invisible static pixel once per page load. A systemd timer on the host reads only these Nginx log entries every minute and writes the accumulated total to &lt;code&gt;visitor-count.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The counter does not set cookies and its counter script does not store IP addresses, user agents, referrers, or other visitor profiles. It measures page loads since the counter was activated, rather than unique people.&lt;/p&gt;
&lt;p&gt;The supporting host files live in &lt;code&gt;visitor-counter/&lt;/code&gt;: &lt;code&gt;count-visits.sh&lt;/code&gt;, &lt;code&gt;criticalbasics-visitor-counter.service&lt;/code&gt;, and &lt;code&gt;criticalbasics-visitor-counter.timer&lt;/code&gt;. They are infrastructure for the deployed static site, not files interpreted by Zola.&lt;/p&gt;
&lt;h2 id=&quot;featured-article-images&quot;&gt;Featured Article Images&lt;/h2&gt;
&lt;p&gt;Posts may opt into a featured image with three optional values in their &lt;code&gt;[extra]&lt;/code&gt; front matter. When no &lt;code&gt;featured_image&lt;/code&gt; is supplied, no image is rendered.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;extra&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;featured_image =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;pics/posts/my-image.png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;featured_image_alt =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Concise description of the image&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;featured_image_caption =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Optional caption&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Featured images appear below the article metadata and open at full size when clicked. On the homepage, an explicitly configured image becomes the right-hand thumbnail beside the article excerpt.&lt;/p&gt;
&lt;h1 id=&quot;improved-accessibility&quot;&gt;Improved Accessibility&lt;/h1&gt;
&lt;p&gt;The theme has been equipped with numerous accessibility improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Skip Links&lt;/strong&gt;: Allow skipping the navigation to get directly to the main content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Focus Indicators&lt;/strong&gt;: Clearly visible focus styles for all interactive elements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Screen Reader Support&lt;/strong&gt;: Use of ARIA attributes and semantic HTML.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Contrast&lt;/strong&gt;: High-contrast color scheme for better readability.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;customization-options&quot;&gt;Customization Options&lt;/h1&gt;
&lt;p&gt;The theme offers extensive customization options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Central configuration&lt;/strong&gt; in &lt;code&gt;sass/partials/_variables.scss&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customizable header&lt;/strong&gt; with background image&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adjustable logo sizes&lt;/strong&gt; for desktop and mobile&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configurable GIF panels&lt;/strong&gt; in different areas of the page&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Button styling&lt;/strong&gt; and appearance settings&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            CUSTOMIZATION TIP
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;All design elements can be configured centrally in the file &lt;code&gt;sass/partials/_variables.scss&lt;/code&gt;, making it easy to maintain a consistent look throughout your site.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h1 id=&quot;form-elements&quot;&gt;Form Elements&lt;/h1&gt;
&lt;p&gt;The theme includes retro-styled form elements:&lt;/p&gt;
&lt;div style=&quot;margin: 30px 0; padding: 20px; background-color: #1e1e1e; border: 1px solid #333;&quot;&gt;
  &lt;input type=&quot;text&quot; class=&quot;retro-input-unset&quot; placeholder=&quot;Input field text&quot; style=&quot;margin-bottom: 10px; display: block;&quot;&gt;
&lt;p&gt;&lt;button class=&quot;retro-button&quot; style=&quot;margin-bottom: 10px; display: block;&quot;&gt;Button Text&lt;/button&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;tables&quot;&gt;Tables&lt;/h1&gt;
&lt;p&gt;The Retro-Compatible Zola Theme offers three different table shortcodes, each optimized for different use cases.&lt;/p&gt;
&lt;h2 id=&quot;table-with-custom-column-widths&quot;&gt;Table with Custom Column Widths&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;table&lt;/code&gt; shortcode allows you to set the width of each column individually. The column widths are specified as percentages and must add up to 100%.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Syntax:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% table(cols=&amp;quot;30%,70%&amp;quot;) %​}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Property | Description |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|----------|-------------|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Name     | The name of the property |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Value    | A longer description that needs more space |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% end %​}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;styled-table-container&quot;&gt;
  &lt;table id=&quot;custom-table&quot; &gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;30%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;70%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Property&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;tr&gt;&lt;td&gt;Name&lt;/td&gt;&lt;td&gt;The name of the property&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Value&lt;/td&gt;&lt;td&gt;A longer description that needs more space&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;h3 id=&quot;example-with-4-columns-of-different-sizes&quot;&gt;Example with 4 Columns of Different Sizes&lt;/h3&gt;
&lt;p&gt;You can define any number of columns with different widths:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% table(cols=&amp;quot;15%,25%,20%,40%&amp;quot;) %​}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| ID | Category | Priority | Description |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|----|----------|----------|-------------|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| 001 | Hardware | High | New graphics card for workstation |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| 002 | Software | Medium | Operating system update |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| 003 | Network  | Low      | Office Wi-Fi optimization |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% end %​}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result looks like this:&lt;/p&gt;
&lt;div class=&quot;styled-table-container&quot;&gt;
  &lt;table id=&quot;custom-table&quot; &gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;15%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;25%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;20%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;col width=&amp;quot;40%&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/colgroup&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;ID&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Category&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Priority&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;tr&gt;&lt;td&gt;001&lt;/td&gt;&lt;td&gt;Hardware&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;td&gt;New graphics card for workstation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;002&lt;/td&gt;&lt;td&gt;Software&lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;td&gt;Operating system update&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;003&lt;/td&gt;&lt;td&gt;Network&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Office Wi-Fi optimization&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;h2 id=&quot;shortcut-table&quot;&gt;Shortcut Table&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;shortcut_table&lt;/code&gt; shortcode is specifically optimized for displaying keyboard shortcuts. It uses fixed column widths (40% for the first column, 60% for the second) to ensure a consistent presentation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Syntax:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% shortcut_table() %​}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Action | Shortcut |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|--------|----------|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Copy | Ctrl+C |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Paste | Ctrl+V |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% end %​}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;styled-table-container shortcut-table&quot;&gt;
   &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Shortcut&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;Ctrl+C&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Paste&lt;/td&gt;&lt;td&gt;Ctrl+V&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Save&lt;/td&gt;&lt;td&gt;Ctrl+S&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Open&lt;/td&gt;&lt;td&gt;Ctrl+O&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
 &lt;/div&gt;
&lt;h2 id=&quot;changelog-table&quot;&gt;Changelog Table&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;changelog_table&lt;/code&gt; shortcode is optimized for changelogs. It gives the date column a fixed width (100px) so that dates are displayed uniformly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Syntax:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% changelog_table() %​}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| Date | Changes |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|------|--------|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| 2025-01-01 | Initial release |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| 2025-01-15 | Bug fixes |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{​% end %​}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;
The changelog table at the beginning of this page uses the &lt;code&gt;changelog_table&lt;/code&gt; shortcode.&lt;/p&gt;
&lt;h2 id=&quot;note-on-displaying-shortcode-examples&quot;&gt;Note on Displaying Shortcode Examples&lt;/h2&gt;
&lt;p&gt;To display shortcode examples in the documentation without them being executed, a special trick is used: invisible spaces (Zero-Width Spaces &lt;code&gt;\u200b&lt;/code&gt;) are inserted between the curly braces and the percent signs. This prevents Zola from recognizing and executing the shortcodes, but they are not visible to the user.&lt;/p&gt;
&lt;p&gt;Example: &lt;code&gt;{\u200b% shortcode %\u200b}&lt;/code&gt; instead of &lt;code&gt;{% shortcode %}&lt;/code&gt; (with an invisible space between &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;%&lt;/code&gt; and between &lt;code&gt;%&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt;)&lt;/p&gt;
&lt;h1 id=&quot;markdown-troubleshooting&quot;&gt;Markdown Troubleshooting&lt;/h1&gt;
&lt;h2 id=&quot;common-layout-issues&quot;&gt;Common Layout Issues&lt;/h2&gt;
&lt;p&gt;When working with this theme (or any Markdown-based system), certain formatting issues can break your layout. Here are some common problems and solutions:&lt;/p&gt;
&lt;h3 id=&quot;html-like-syntax-in-markdown&quot;&gt;HTML-Like Syntax in Markdown&lt;/h3&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ffcccc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ⚠️ 
            AVOID RAW HTML TAGS IN TEXT
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;Using angle brackets (&lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt;) in your Markdown text can cause layout problems because they might be interpreted as HTML tags. This can break the entire page layout if the “tag” is never closed.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id=&quot;problem-example&quot;&gt;Problem Example:&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Select &lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;font-weight: bold;&quot;&gt;Yes&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;&amp;gt;**&lt;/span&gt;&lt;span&gt; to enable automatic updates.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;&amp;lt;Yes&amp;gt;&lt;/code&gt; might be interpreted as an HTML tag named “Yes”, causing layout issues.&lt;/p&gt;
&lt;h4 id=&quot;solutions&quot;&gt;Solutions:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use quotes instead of angle brackets:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Select &lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**&amp;quot;Yes&amp;quot;**&lt;/span&gt;&lt;span&gt; to enable automatic updates.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use backticks to format as code:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Select &lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;font-weight: bold;&quot;&gt;`&amp;lt;Yes&amp;gt;`&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt; to enable automatic updates.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use HTML entities:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Select &lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**&amp;amp;lt;Yes&amp;amp;gt;**&lt;/span&gt;&lt;span&gt; to enable automatic updates.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use escape characters:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Select &lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**\&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;font-weight: bold;&quot;&gt;Yes\&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;&amp;gt;**&lt;/span&gt;&lt;span&gt; to enable automatic updates.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;other-common-markdown-issues&quot;&gt;Other Common Markdown Issues&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unclosed code blocks&lt;/strong&gt;: Always ensure your code blocks have opening and closing backticks on their own lines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Malformed tables&lt;/strong&gt;: Tables require a specific format with headers and separators.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nested HTML&lt;/strong&gt;: Be careful when nesting HTML elements inside Markdown content.&lt;/li&gt;
&lt;/ul&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#ccffcc&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            💡 
            DEBUGGING LAYOUT ISSUES
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;If your page layout breaks, try removing sections of content one by one until the layout displays correctly. This can help identify which specific content is causing the problem.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr size=&quot;2&quot; noshade color=&quot;#666666&quot; style=&quot;margin: 15px 0; border-style: double;&quot;&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h1&gt;
&lt;table class=&quot;retro-infobox&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot; cellpadding=&quot;10&quot; border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#eeeeee&quot; style=&quot;color: #000000; font-weight: bold;&quot;&gt;
            ℹ️ 
            GETTING STARTED
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td bgcolor=&quot;#000000&quot; style=&quot;color: #ffffff;&quot;&gt;
&lt;p&gt;To get started with this theme:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repository into your Zola &lt;code&gt;themes&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;Activate the theme in your &lt;code&gt;config.toml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;zola serve&lt;/code&gt; to see a preview&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For detailed instructions, see the &lt;a href=&quot;../../docs/README.md&quot;&gt;Main Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;The Retro-Compatible Zola Theme offers a unique combination of nostalgic design and modern functionality. It’s perfect for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retro computing enthusiasts&lt;/li&gt;
&lt;li&gt;Digital preservation projects&lt;/li&gt;
&lt;li&gt;Personal websites with a nostalgic touch&lt;/li&gt;
&lt;li&gt;Anyone who appreciates the aesthetic of early web design&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    </channel>
</rss>
