overhauls of most service docs
All checks were successful
Podman DDNS Image / build-and-push-ddns (push) Successful in 33s

This commit is contained in:
2025-07-22 18:29:07 -04:00
parent 3f3a03ee05
commit 5184c84d50
57 changed files with 1726 additions and 551 deletions

3
.gitignore vendored
View File

@@ -6,4 +6,5 @@ volumes/
__pycache__/
.pytest_cache/
.venv/
.mypy_cache
.mypy_cache
TODO.md

View File

@@ -14,6 +14,8 @@ Status](https://gitea.reeseapps.com/services/homelab/actions/workflows/distoolbo
- [Homelab](#homelab)
- [Table of Contents](#table-of-contents)
- [Fun Facts](#fun-facts)
- [Keyboard Shortcuts](#keyboard-shortcuts)
- [SSH Setup](#ssh-setup)
- [Important Dates and Times](#important-dates-and-times)
- [Project Lifecycle](#project-lifecycle)
- [Project Types](#project-types)
@@ -25,33 +27,77 @@ Status](https://gitea.reeseapps.com/services/homelab/actions/workflows/distoolbo
## Fun Facts
### Keyboard Shortcuts
On linux, <kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>u</kbd>, then, while holding
<kbd>ctrl</kbd>+<kbd>shift</kbd>, typing <kbd>b</kbd>+<kbd>0</kbd> will type a
° (degree) symbol. Also you can enter any unicode symbol this way.
To generate an SSH key with the correct comment and type run:
In vim: `esc + o` will take you to the end of a file and insert a new line.
## SSH Setup
```bash
export KEYGEN_USER=myuser
export KEYGEN_HOST=something.com
ssh-keygen -C ${KEYGEN_USER}@${KEYGEN_HOST} -f ~/.ssh/id_${KEYGEN_HOST} -t ed25519
export REMOTE_USER=${USER}
export REMOTE_HOST=something.com
export REMOTE_PORT=22
# The following is generated by the above variables. No tweaks necessary.
export KEY_NAME=~/.ssh/id_${REMOTE_USER}_${REMOTE_HOST}
export KEY_COMMENT="${USER}@${HOSTNAME}:${REMOTE_USER}@${REMOTE_HOST}"
# Pick one of the below key types
# ed25519
ssh-keygen -C ${KEY_COMMENT} -f ${KEY_NAME} -t ed25519
# rsa 4096
ssh-keygen -C ${KEY_COMMENT} -f ${KEY_NAME} -t rsa -b 4096
cat <<EOF >> ~/.ssh/config
Host ${KEYGEN_HOST}
Hostname ${KEYGEN_HOST}
IdentityFile ~/.ssh/id_${KEYGEN_HOST}
User ${KEYGEN_USER}
Port 22
EOF
```
In vim: `esc + o` will take you to the end of a file and insert a new line.
Host ${REMOTE_HOST}
Hostname ${REMOTE_HOST}
IdentityFile ${KEY_NAME}
User ${REMOTE_USER}
Port ${REMOTE_PORT}
EOF
# Copy the generated key to the server using password auth. Assumes password auth enabled.
ssh-copy-id -o PubkeyAuthentication=no -i ${KEY_NAME} ${REMOTE_USER}@${REMOTE_HOST}
# Log into the server with your key
ssh -i ${KEY_NAME} ${KEY_COMMENT}
# Copy authorized_keys to root
sudo cp ~/.ssh/authorized_keys /root/.ssh/authorized_keys
exit
# login and disable password auth
ssh ${REMOTE_HOST}
echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/01-prohibit-password.conf
systemctl restart sshd
# OPTIONAL: Disable sudo password
echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/01-nopasswd-wheel
exit
# Test if you can SSH with a password
ssh -o PubkeyAuthentication=no ducoterra@${SSH_HOST}.reeselink.com
# Test that you can log into the server with ssh config
ssh $SSH_HOST
```
## Important Dates and Times
- Machine updates happen at 4am on on Saturday
- VM updates happen at 5am on Saturday
- Backups happen at 6am every day
| Time | Day | Description |
| ----- | -------- | ------------------------------ |
| 00:00 | All | Automated builds |
| 00:00 | All | NAS Snapshots |
| 02:00 | All | Backups |
| 04:00 | Saturday | Server Hardware Updates |
| 05:00 | Saturday | Server VM Updates |
| 05:00 | All | Unifi Protect Firmware Updates |
| 06:00 | All | Unifi Network Firmware Updates |
## Project Lifecycle

Binary file not shown.

View File

@@ -5,11 +5,16 @@
- [Schlage Door Lock](#schlage-door-lock)
- [Philips Hue Lights](#philips-hue-lights)
- [Shelly](#shelly)
- [Relative Humidity Calculator](#relative-humidity-calculator)
- [Barometer](#barometer)
- [Relative Humidity Calculator](#relative-humidity-calculator)
- [Font Colors](#font-colors)
- [Light Indicator for Voice Assistant](#light-indicator-for-voice-assistant)
- [Blank Button (Spacer)](#blank-button-spacer)
- [Roku Remote](#roku-remote)
- [Flair Vent Battery](#flair-vent-battery)
- [Voice](#voice)
- [Custom Sentences](#custom-sentences)
- [Notifications](#notifications)
## Setup and Configuration
@@ -48,7 +53,51 @@ is quicker to pick up and transmit device information. Note that "gateway mode"
just enable bluetooth and rpc or select "active" from the configuration menu for the shelly
device.
### Relative Humidity Calculator
#### Barometer
<https://www.thoughtco.com/how-to-read-a-barometer-3444043>
A barometric reading over 30.20 inHg is generally considered high, and high pressure is associated with clear skies and calm weather.
If the reading is over 30.20 inHg (102268.9 Pa or 1022.689 mb):
- Rising or steady pressure means continued fair weather.
- Slowly falling pressure means fair weather.
- Rapidly falling pressure means cloudy and warmer conditions.
A barometric reading in the range of 29.80 and 30.20 inHg can be considered normal, and normal pressure is associated with steady weather.
If the reading falls between 29.80 and 30.20 inHg (100914.4102268.9 Pa or 1022.6891009.144 mb):
- Rising or steady pressure means present conditions will continue.
- Slowly falling pressure means little change in the weather.
- Rapidly falling pressure means that rain is likely, or snow if it is cold enough.
A barometric reading below 29.80 inHg is generally considered low, and low pressure is associated with warm air and rainstorms.
If the reading is under 29.80 inHg (100914.4 Pa or 1009.144 mb):
- Rising or steady pressure indicates clearing and cooler weather.
- Slowly falling pressure indicates rain.
- Rapidly falling pressure indicates a storm is coming.
A basic automation would look like
```yaml
It's {{ int(states("sensor.grouse_temp")) }} degrees and {{ states("weather.grouse_weather") }}. The relative humidity is {{ states("sensor.grouse_humidity") }}%. I'm seeing {{ int(states("sensor.grouse_wind_speed")) }}mph wind with gusts up to {{ int(states("sensor.grouse_wind_gust")) }}mph.
{% set pressure = float(states("sensor.grouse_rel_pressure")) %}
The barometer reads {{ pressure }}inHg.
{% if pressure > 30.20 %}
Fair weather is expected
{% elif pressure > 29.80 %}
Rain is possible
{% else %}
Rain is coming.
{% endif %}
```
#### Relative Humidity Calculator
<https://www.wikihow.com/Calculate-Humidity>
@@ -335,4 +384,32 @@ cards:
hold_action:
action: none
title: Left Living Room TV
```
```
### Flair Vent Battery
Flair vents report low battery at 2.4v. 3v is nominal/full.
```yaml
{% set volt_min=2.4 %}
{% set volt_max=3.0 %}
{% set volt_diff_max=0.6 %}
{{ (min(float(states("sensor.main_bedroom_29bf_voltage")) - volt_min, volt_diff_max) / volt_diff_max) * 100 }}
```
## Voice
### Custom Sentences
<https://developers.home-assistant.io/docs/voice/intent-recognition/template-sentence-syntax/#sentence-templates-syntax>
## Notifications
Notification Information:
<https://www.home-assistant.io/docs/automation/templating/>
```yaml
Triggered by {{ trigger.entity_id }}, Date: {{ now().strftime('%Y-%m-%d') }}, Time: {{ now().strftime('%H:%M') }}
```

View File

@@ -0,0 +1,21 @@
# Freedesktop Notes
Notes pertaining to the `.desktop` extension and desktop entries.
## Keys
<https://specifications.freedesktop.org/desktop-entry-spec/1.5/recognized-keys.html>
## Icons
<https://freedesktop.org/wiki/Specifications/icon-theme-spec/>
By default, apps should look in $HOME/.icons (for backwards compatibility), in $XDG_DATA_DIRS/icons and in /usr/share/pixmaps (in that order).
## Testing
Run a `.desktop` file from terminal with this:
```bash
gtk-launch gnome-system-monitor.desktop
```

View File

@@ -210,35 +210,7 @@ Now the status should be correct even after connecting/disconnecting when the co
## SSH
Generate a key with password protection:
```bash
# Omit "-N 'password'" to have it prompt you
ssh-keygen -f ~/.ssh/test-key -N 'PASSWORD'
```
Change the password for an ssh key:
```bash
# Use "-N ''" to remove the password
ssh-keygen -p -N 'PASSWORD' -f ~/.ssh/test-key
```
This is an example config entry in `~/.ssh/config`:
```conf
Host my-host
Hostname my-host.reeselink.com
User root
ProxyCommand none
ForwardAgent no
ForwardX11 no
Port 22
KeepAlive yes
IdentityFile ~/.ssh/id_my-host_rsa
```
You can ssh to that host with `ssh my-host` after adding a config entry.
See [README](/README.md#ssh-setup)
## Templates
@@ -652,7 +624,6 @@ Custom profiles are located at
Sync this with something like Nextcloud.
## Orca Slicer
<https://github.com/SoftFever/OrcaSlicer>

View File

@@ -14,55 +14,7 @@ and the operator will store information about each server.
## Setup SSH
On the operator:
```bash
export SSH_HOST=kube
ssh-keygen -t rsa -b 4096 -C ${USER}@${HOSTNAME} -f ~/.ssh/id_${SSH_HOST}_rsa
# Note: If you get "too many authentication failures" it's likely because you have too many private
# keys in your ~/.ssh directory. Use `-o PubkeyAuthentication` to fix it.
ssh-copy-id -o PubkeyAuthentication=no -i ~/.ssh/id_${SSH_HOST}_rsa.pub ducoterra@${SSH_HOST}.reeselink.com
ssh -i ~/.ssh/id_${SSH_HOST}_rsa -o 'PubkeyAuthentication=yes' ducoterra@${SSH_HOST}.reeselink.com
```
On the server:
```bash
# Copy authorized_keys to root
sudo cp ~/.ssh/authorized_keys /root/.ssh/authorized_keys
# Change your password
passwd
sudo su -
echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/01-prohibit-password.conf
echo '%sudo ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/01-nopasswd-sudo
systemctl restart ssh
```
On the operator:
```bash
cat <<EOF >> ~/.ssh/config
Host $SSH_HOST
Hostname ${SSH_HOST}.reeselink.com
User root
ProxyCommand none
ForwardAgent no
ForwardX11 no
Port 22
KeepAlive yes
IdentityFile ~/.ssh/id_${SSH_HOST}_rsa
EOF
# Test if you can SSH with a password
ssh -o PubkeyAuthentication=no ducoterra@${SSH_HOST}.reeselink.com
# Test that you can log into the server with ssh config
ssh $SSH_HOST
```
See [README](/README.md#ssh-setup)
## Fail2Ban

View File

@@ -285,4 +285,4 @@ output.eDP-2.enable \
output.eDP-2.mode.1920x1080@60 \
output.eDP-2.scale.1 \
output.eDP-2.position.0,0
```
```

View File

@@ -7,6 +7,7 @@
- [Fail2Ban](#fail2ban)
- [BTRFS Parent Volumes](#btrfs-parent-volumes)
- [BTRFS Snapshots](#btrfs-snapshots)
- [BTRFS Maintenance](#btrfs-maintenance)
- [TPM2 Luks Decryption](#tpm2-luks-decryption)
- [Change your password](#change-your-password)
- [Automatic Updates](#automatic-updates)
@@ -73,48 +74,7 @@ and the operator will store information about each server.
## Setup SSH
In this setup we'll allow ssh to the root user via key and keep the admin user for cockpit.
On the operator:
```bash
export SSH_HOST=kube
ssh-keygen -C ${USER}@${HOSTNAME} -f ~/.ssh/id_${SSH_HOST}_rsa
# Note: If you get "too many authentication failures" it's likely because you have too many private
# keys in your ~/.ssh directory. Use `-o PubkeyAuthentication` to fix it.
ssh-copy-id -o PubkeyAuthentication=no -i ~/.ssh/id_${SSH_HOST}_rsa.pub ducoterra@${SSH_HOST}.reeselink.com
ssh -i ~/.ssh/id_${SSH_HOST}_rsa ducoterra@${SSH_HOST}.reeselink.com
# Copy authorized_keys to root
sudo cp ~/.ssh/authorized_keys /root/.ssh/authorized_keys
exit
cat <<EOF >> ~/.ssh/config
Host ${SSH_HOST}
Hostname ${SSH_HOST}.reeselink.com
User root
Port 22
KeepAlive yes
IdentityFile ~/.ssh/id_${SSH_HOST}_rsa
EOF
ssh ${SSH_HOST}
# Disable password auth
echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/01-prohibit-password.conf
systemctl restart sshd
# OPTIONAL: Disable sudo password
echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/01-nopasswd-wheel
exit
# Test if you can SSH with a password
ssh -o PubkeyAuthentication=no ducoterra@${SSH_HOST}.reeselink.com
# Test that you can log into the server with ssh config
ssh $SSH_HOST
```
See [README](/README.md#ssh-setup)
## DNF
@@ -224,6 +184,13 @@ snapper -c root delete 1
Note - you probably don't want to keep yearly snapshots.
Edit `/etc/snapper/configs/root` and change `TIMELINE_LIMIT_YEARLY=` to `0`.
## BTRFS Maintenance
```bash
# Start a scrub in the foreground (-B) at /
btrfs scrub start -B /
```
## TPM2 Luks Decryption
Mostly taken from here:
@@ -324,7 +291,7 @@ TODO
## Common Storage Mounts
Note: mount these before you install the relavant package!
Note: mount these before you install the relevant package!
1. For virtual machines: `/var/lib/libvirt`
2. For podman: `/var/lib/containers`

View File

@@ -1,6 +1,7 @@
# Apps
- [Apps](#apps)
- [Common CLI Apps](#common-cli-apps)
- [Gear Lever](#gear-lever)
- [VSCode](#vscode)
- [DNF](#dnf)
@@ -47,6 +48,11 @@
- [KDiskMark](#kdiskmark)
- [Local Send](#local-send)
- [Evolution](#evolution)
- [Virtualization](#virtualization)
- [NVM](#nvm)
- [Ollama](#ollama)
- [UV](#uv)
- [Pipenv](#pipenv)
Flatpak installs are from Flathub unless otherwise noted.
@@ -58,6 +64,66 @@ flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.f
When prompted, prefer flathub.
## Common CLI Apps
Some common apps you'll probably want available.
```bash
sudo dnf install \
# Advanced text editor for code editing and other tasks.
vim \
# Network bandwidth measuring tool.
iperf3 \
# Command-line interface for managing Kubernetes clusters.
kubectl \
# Package manager and deployment tool for Kubernetes.
helm \
# Utility to monitor real-time network usage of processes.
nethogs \
# DevOps configuration management tool.
ansible \
# Terminal multiplexer.
tmux \
# Multimedia player with support for a wide range of codecs and file formats.
ffmpeg \
# Microsoft Windows compatibility layer.
wine \
# Archive utility similar to GNU tar, used to package files into single archive files.
unzip \
# A terminal activity monitor (top clone).
btop \
# Command-line JSON processor.
jq \
# YAML-based configuration-as-code tool for command-line interfaces written in Go, Rust, Python, and more.
yq \
# An image manipulation software suite based on ImageMagick.
ImageMagick \
# The Go programming language environment including a toolchain (gc) and libraries.
go \
# Rust package manager and compiler installation utility.
rust rustup \
# Distributed version control system, Git extension that adds support for large files like multimedia assets.
git git-lfs \
# Provides traditional network tools such as ifconfig, netstat, hostname, etc., in a single package.
net-tools \
# Document conversion tool and markup language converter.
pandoc \
# Comprehensive LaTeX distribution for high-quality typesetting of documents.
texlive-latex \
# Generate strong passwords.
pwgen \
# Reattach to running processes
reptyr \
# Netcat, for basic tcp/udp operations
netcat \
# 7zip support
p7zip \
# Make
make \
# GCC for compile
gcc
```
## Gear Lever
I would recommend you install Gear Lever to manage App Images:
@@ -296,6 +362,12 @@ At the very top of the config you can add a pin for a printer permanently with:
}
```
You'll need to open port 2021 udp
```bash
firewall-cmd --add-port=2021/udp --permanent
```
## Freecad
Benchy benchy benchy oh no, I can't do that, this is hard.
@@ -402,10 +474,11 @@ flatpak install io.github.thetumultuousunicornofdarkness.cpu-x
## Ungoogled Chromium
Chrom
<https://github.com/ungoogled-software/ungoogled-chromium?tab=readme-ov-file#automated-or-maintained-builds>
```bash
flatpak install io.github.ungoogled_software.ungoogled_chromium
sudo dnf copr enable wojnilowicz/ungoogled-chromium
sudo dnf install ungoogled-chromium
```
## Signal
@@ -507,4 +580,36 @@ You still use email? I still use email.
```bash
flatpak install org.gnome.Evolution
```
```
## Virtualization
```bash
# Virtualization
sudo dnf group install --with-optional virtualization
```
## NVM
<https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating>
## Ollama
<https://ollama.com/download>
Run the installation script as normal. Make sure you have the [ROCM](#rocm)
drivers installed for GPU acceleration. The script *should* automatically pull
the ROCM drivers after installing the base packages. If not, you should install
them manually.
For starting ollama as a service, follow the link below:
<https://github.com/ollama/ollama/blob/main/docs/linux.md#adding-ollama-as-a-startup-service-recommended>
## UV
<https://docs.astral.sh/uv/getting-started/installation/>
## Pipenv
<https://pipenv.pypa.io/en/latest/installation.html#installing-pipenv>

View File

@@ -4,37 +4,28 @@
- [Framework 16 Fixes](#framework-16-fixes)
- [Wake from Sleep](#wake-from-sleep)
- [Wrong keys pressed in the browser](#wrong-keys-pressed-in-the-browser)
- [Fix wifi disconnecting and reconnecting repeatedly on reboot/resume](#fix-wifi-disconnecting-and-reconnecting-repeatedly-on-rebootresume)
- [Wifi Powersave](#wifi-powersave)
- [Podman](#podman)
- [Autostarting services with quadlets](#autostarting-services-with-quadlets)
- [Toolbox](#toolbox)
- [Network](#network)
- [Firewall](#firewall)
- [VLAN Setup with nmcli](#vlan-setup-with-nmcli)
- [ZRAM](#zram)
- [Libraries](#libraries)
- [Common Libraries](#common-libraries)
- [Apps](#apps)
- [Common CLI Apps](#common-cli-apps)
- [Ungoogled Chromium](#ungoogled-chromium)
- [VSCode](#vscode)
- [Virtualization](#virtualization)
- [NVM](#nvm)
- [Ollama](#ollama)
- [UV](#uv)
- [Pipenv](#pipenv)
- [Backups](#backups)
- [BTRFS Snapshots](#btrfs-snapshots)
- [ROCM](#rocm)
- [Display](#display)
- [Scripted Display Modes](#scripted-display-modes)
- [Fixing generic Wayland icons on task alt tab](#fixing-generic-wayland-icons-on-task-alt-tab)
## Framework 16 Fixes
### Wake from Sleep
The keyboard/mouse can be pressed through the lid while in a backpack. Disable them to
prevent wake from sleep.
The keyboard/mouse can be pressed through the lid while in a backpack. Disable
them to prevent wake from sleep.
`/etc/udev/rules.d/69-suspend.rules`
@@ -55,61 +46,15 @@ sudo udevadm control --reload-rules && sudo udevadm trigger
### Wrong keys pressed in the browser
Sometimes keys will stop working when using search bars or do strange things like move the page around. This seems to be caused by some "alt" keypress combination. Pressing "alt" twice fixes it.
### Fix wifi disconnecting and reconnecting repeatedly on reboot/resume
Create a file in `/etc/systemd/system/reset-iwlwifi.service` with the following content:
```conf
[Unit]
Description=Reload iwlwifi on wake-up
After=suspend.target
After=multi-user.target
[Service]
ExecStartPre=rmmod iwlmvm iwlwifi
ExecStart=modprobe iwlwifi
[Install]
WantedBy=suspend.target
WantedBy=multi-user.target
```
```bash
systemctl daemon-reload
systemctl enable reset-iwlwifi.service
```
### Wifi Powersave
**NOTE: THIS DOESN'T WORK. IT CAUSES WIFI DISCONNECT AND RECONNECT ISSUES.**
<https://www.networkmanager.dev/docs/api/latest/settings-802-11-wireless.html>
<https://gist.github.com/jcberthon/ea8cfe278998968ba7c5a95344bc8b55>
<https://askubuntu.com/questions/1230525/ubuntu-20-04-network-performance-extremely-slow>
```bash
vim /etc/NetworkManager/conf.d/wifi-powersave-off.conf
```
```conf
[connection]
# Values are 0 (use default), 1 (ignore/don't touch), 2 (disable) or 3 (enable).
wifi.powersave = 2
```
```bash
systemctl restart NetworkManager
```
Sometimes keys will stop working when using search bars or do strange things
like move the page around. This seems to be caused by some "alt" keypress
combination. Pressing "alt" twice fixes it.
## Podman
Since you'll be using podman for most container-based services, you'll want to set the
the podman auth file to somewhere persistent, otherwise it'll get deleted every time you
reboot.
Since you'll be using podman for most container-based services, you'll want to
set the the podman auth file to somewhere persistent, otherwise it'll get
deleted every time you reboot.
Add this to your `.bashrc`:
@@ -122,8 +67,8 @@ Source that and then run `podman login` to create the file.
### Autostarting services with quadlets
If you want to run something as your user at boot (like a systemd process, think ollama) you can
create a user quadlets like so:
If you want to run something as your user at boot (like a systemd process,
think ollama) you can create a user quadlets like so:
```bash
# Generate the .container file
@@ -153,6 +98,65 @@ toolbox enter
## Network
### Firewall
Set the default firewall to `drop`
```bash
firewall-cmd --set-default-zone=drop
firewall-cmd --reload
```
Allow KDE Connect via 1714-1764 tcp/udp
```bash
firewall-cmd --add-port=1714-1764/udp --add-port=1714-1764/tcp --permanent
```
You can check if the firewall is working via `nmap` from another machine
Note, add `-r` to scan ports in order.
Note, add `-vv` to increase verbosity.
Note, add `-A` to perform OS detection, host lookup, etc.
Note, use `-F` to perform a quick scan against common ports.
```bash
export NMAP_HOST=10.2.0.49
# Scan for common ports on TCP
nmap -sT $NMAP_HOST
# Scan all ports on TCP
nmap -sT -p- $NMAP_HOST
# Scan specific port on TCP
nmap -sT -p5432 $NMAP_HOST
# Scan range of ports on TCP
nmap -sT -p1024-9999 $NMAP_HOST
# Scan for common ports on UDP
nmap -sU $NMAP_HOST
# Skip host up checking
nmap -Pn -sT $NMAP_HOST
# Scan all ports for everything (takes a really really long time)
nmap -Pn -sT -sU -p- $NMAP_HOST
# Scan using TCP ACK Ping (More serious check that attempts to bypass firewall, See nmap man page)
nmap -PA -p- $NMAP_HOST
```
Then, while running a scan:
v / V: Increase / decrease the verbosity level d / D: Increase / decrease the
debugging Level p / P: Turn on / off packet tracing ?: Print a runtime
interaction help screen
### VLAN Setup with nmcli
```bash
@@ -199,106 +203,6 @@ xz-devel \
libgle-devel
```
## Apps
### Common CLI Apps
```bash
sudo dnf install \
# Advanced text editor for code editing and other tasks.
vim \
# Network bandwidth measuring tool.
iperf3 \
# Command-line interface for managing Kubernetes clusters.
kubectl \
# Package manager and deployment tool for Kubernetes.
helm \
# Utility to monitor real-time network usage of processes.
nethogs \
# DevOps configuration management tool.
ansible \
# Terminal multiplexer.
tmux \
# Multimedia player with support for a wide range of codecs and file formats.
ffmpeg \
# Microsoft Windows compatibility layer.
wine \
# Archive utility similar to GNU tar, used to package files into single archive files.
unzip \
# A terminal activity monitor (top clone).
btop \
# Command-line JSON processor.
jq \
# YAML-based configuration-as-code tool for command-line interfaces written in Go, Rust, Python, and more.
yq \
# An image manipulation software suite based on ImageMagick.
ImageMagick \
# The Go programming language environment including a toolchain (gc) and libraries.
go \
# Rust package manager and compiler installation utility.
rust rustup \
# Distributed version control system, Git extension that adds support for large files like multimedia assets.
git git-lfs \
# Provides traditional network tools such as ifconfig, netstat, hostname, etc., in a single package.
net-tools \
# Document conversion tool and markup language converter.
pandoc \
# Comprehensive LaTeX distribution for high-quality typesetting of documents.
texlive-latex \
# Generate strong passwords.
pwgen \
# Reattach to running processes
reptyr \
# Netcat, for basic tcp/udp operations
netcat \
# 7zip support
p7zip
```
### Ungoogled Chromium
<https://github.com/ungoogled-software/ungoogled-chromium?tab=readme-ov-file#automated-or-maintained-builds>
```bash
sudo dnf copr enable wojnilowicz/ungoogled-chromium
sudo dnf install ungoogled-chromium
```
### VSCode
<https://code.visualstudio.com/docs/setup/linux#_rhel-fedora-and-centos-based-distributions>
### Virtualization
```bash
# Virtualization
sudo dnf group install --with-optional virtualization
```
### NVM
<https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating>
### Ollama
<https://ollama.com/download>
Run the installation script as normal. Make sure you have the [ROCM](#rocm) drivers installed
for GPU acceleration. The script *should* automatically pull the ROCM drivers after installing
the base packages. If not, you should install them manually.
For starting ollama as a service, follow the link below:
<https://github.com/ollama/ollama/blob/main/docs/linux.md#adding-ollama-as-a-startup-service-recommended>
### UV
<https://docs.astral.sh/uv/getting-started/installation/>
### Pipenv
<https://pipenv.pypa.io/en/latest/installation.html#installing-pipenv>
## Backups
### BTRFS Snapshots
@@ -307,7 +211,8 @@ For starting ollama as a service, follow the link below:
<http://snapper.io/manpages/snapper-configs.html>
We'll be using snapper, a tool for automating and controlling snapshot behavior.
We'll be using snapper, a tool for automating and controlling snapshot
behavior.
```bash
dnf install snapper dnf-plugin-snapper
@@ -335,8 +240,8 @@ snapper -c root create --description "test snapshot"
snapper -c root delete 1
```
Note - you probably don't want to keep yearly snapshots.
Edit `/etc/snapper/configs/root` and change `TIMELINE_LIMIT_YEARLY=` to `0`.
Note - you probably don't want to keep yearly snapshots. Edit
`/etc/snapper/configs/root` and change `TIMELINE_LIMIT_YEARLY=` to `0`.
## ROCM
@@ -400,4 +305,41 @@ output.eDP-2.position.0,0 \
output.eDP-2.primary \
output.eDP-2.mode.1920x1080@165 \
output.eDP-2.scale.1'
```
```
## Fixing generic Wayland icons on task alt tab
<https://epergo.com/posts/fix-generic-wayland-icon/>
1. Access Window Rules
Go to “System Settings > Window Management > Window Rules”.
2. Create a New Rule (If None Exist)
If the application does not have any rules already, create a new one:
1. Click on “Add New…”
2. Add a description (e.g., “Application settings for sublime_merge”)
3. Specify the “Window class (application)”
If youre unsure of the value for the window class, click “Detect Window
Properties”, then click on the application window. A pop-up with the
detected properties will be shown, and you can select the correct value.
3. Add Property
1. Click on “Add Property” and select “Desktop File Name”.
4. Find the Correct Desktop File Name
Standard Applications: If the application is installed using your distros
repositories, check the name in /usr/share/applications/. Flatpak
Applications: If its a Flatpak package, check the name in
/var/lib/flatpak/exports/share/applications/. For example, for Obsidian, it
will be md.obsidian.Obsidian (do not include the .desktop suffix).
5. Apply Settings
Apply the new settings and close the application if it was open. The next
time you open the application, it should show the correct icon.

View File

@@ -1,8 +0,0 @@
#!/bin/bash
kscreen-doctor \
output.eDP-2.enable \
output.eDP-2.position.0,0 \
output.eDP-2.primary \
output.eDP-2.mode.1920x1080@60 \
output.eDP-2.scale.1

View File

@@ -1,8 +0,0 @@
#!/bin/bash
kscreen-doctor \
output.eDP-2.enable \
output.eDP-2.position.0,0 \
output.eDP-2.primary \
output.eDP-2.mode.2560x1600@165 \
output.eDP-2.scale.1.25

View File

@@ -161,4 +161,4 @@ p = Path(\"%\"); \
realpath = (str(p.parent) + '/' if str(p.parent) != '.' else '') + p.stem + '.mp4'; \
subprocess.run(['mkdir', '-p', to_folder + str(Path(realpath).parent)]); \
subprocess.run(['ffmpeg', '-i', '%', '-c', 'copy', to_folder + realpath])"
```
```

View File

@@ -17,9 +17,9 @@
- [Cleaning up old snapshots](#cleaning-up-old-snapshots)
- [Creating and restoring snapshots](#creating-and-restoring-snapshots)
- [Filesystem ACLs](#filesystem-acls)
- [ISCSI Backup Volumes](#iscsi-backup-volumes)
- [Create Backup ZVOL](#create-backup-zvol)
- [Create Backup ISCSI Target](#create-backup-iscsi-target)
- [ISCSI](#iscsi)
- [Create ZVOL](#create-zvol)
- [Create ISCSI Target](#create-iscsi-target)
- [VMs](#vms)
- [Converting zvol to qcow2](#converting-zvol-to-qcow2)
- [Converting qcow2 to zvol](#converting-qcow2-to-zvol)
@@ -41,7 +41,7 @@
- [UPS Monitoring](#ups-monitoring)
- [ZFS Size Data](#zfs-size-data)
- [ZFS Rename](#zfs-rename)
- [ISCSI](#iscsi)
- [ISCSI](#iscsi-1)
- [ISCSI Base Name](#iscsi-base-name)
- [Archiving](#archiving)
- [Deleting snapshots](#deleting-snapshots)
@@ -247,9 +247,9 @@ Dataset -> Dataset details (edit) -> Advanced Options -> ACL Type (inherit)
setfacl -b -R /mnt/enc0/smb/media
```
## ISCSI Backup Volumes
## ISCSI
### Create Backup ZVOL
### Create ZVOL
1. Create a new dataset called "iscsi" and then a dataset under that called "backups"
1. Set sync to always
@@ -258,18 +258,22 @@ setfacl -b -R /mnt/enc0/smb/media
2. Create a new dataset under backups with the same name as your server hostname
3. Set the size to something reasonable (Note you may need to "force size")
### Create Backup ISCSI Target
### Create ISCSI Target
1. In System -> Services -> ISCSI set the Base Name following [these rules](#iscsi-base-name)
2. In Shared -> ISCSI -> Authorized Access -> Create a new authorized access
In Shared -> Block (iSCSI) Shares Targets
1. Global Target Configuration -> Base Name
1. set the Base Name following [these rules](#iscsi-base-name)
2. Authorized Access -> Add
1. Group ID arbitrary - just pick a number you haven't used
2. User: The connecting machine's ISCSI Base Name
3. Secret: A 16 character password with no special characters
3. Wizard -> Create New
1. Extent Name: `backup-<hostname>`
2. Extent Type: `Device`
3. Extent Device: The ZVOL you just created
4. Extent Sharing Platform: `Modern OS`
2. Discovery Authentication: Chap
3. User: The connecting machine's ISCSI Base Name
4. Secret: A 16 character password with no special characters
3. Extents -> Add
1. Name: `some-name`
2. Type: `Device`
3. Device: The ZVOL you just created
4. Sharing Platform: `Modern OS`
5. Protocol Options Portal: Either create new (0.0.0.0 and ::) or select your existing portal
6. Protocol Options Initiators: The base name of the connecting machine following [these rules](#iscsi-base-name)
4. Targets -> Select the backup-<hostname> target -> Edit

View File

@@ -16,55 +16,7 @@ and the operator will store information about each server.
## Setup SSH
On the operator:
```bash
export SSH_HOST=kube
ssh-keygen -t rsa -b 4096 -C ducoterra@${SSH_HOST}.reeselink.com -f ~/.ssh/id_${SSH_HOST}_rsa
# Note: If you get "too many authentication failures" it's likely because you have too many private
# keys in your ~/.ssh directory. Use `-o PubkeyAuthentication` to fix it.
ssh-copy-id -o PubkeyAuthentication=no -i ~/.ssh/id_${SSH_HOST}_rsa.pub ducoterra@${SSH_HOST}.reeselink.com
ssh -i ~/.ssh/id_${SSH_HOST}_rsa -o 'PubkeyAuthentication=yes' ducoterra@${SSH_HOST}.reeselink.com
```
On the server:
```bash
# Copy authorized_keys to root
sudo cp ~/.ssh/authorized_keys /root/.ssh/authorized_keys
# Change your password
passwd
sudo su -
echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/01-prohibit-password.conf
echo '%sudo ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/01-nopasswd-sudo
systemctl restart ssh
```
On the operator:
```bash
cat <<EOF >> ~/.ssh/config
Host $SSH_HOST
Hostname ${SSH_HOST}.reeselink.com
User root
ProxyCommand none
ForwardAgent no
ForwardX11 no
Port 22
KeepAlive yes
IdentityFile ~/.ssh/id_${SSH_HOST}_rsa
EOF
# Test if you can SSH with a password
ssh -o PubkeyAuthentication=no ducoterra@${SSH_HOST}.reeselink.com
# Test that you can log into the server with ssh config
ssh $SSH_HOST
```
See [README](/README.md#ssh-setup)
## Fail2Ban

View File

@@ -1,5 +0,0 @@
# Podman Server
## Notes
- create a btrfs subvolume for each user

View File

@@ -0,0 +1,68 @@
# Brick Tracker
<https://gitea.baerentsen.space/FrederikBaerentsen/BrickTracker/src/branch/master/docs/quickstart.md>
## Setup
1. Copy the `.env.sample` from <https://gitea.baerentsen.space/FrederikBaerentsen/BrickTracker/src/branch/master/.env.sample> to `.env`
2. Set the following:
1. `BK_AUTHENTICATION_PASSWORD`
2. `BK_AUTHENTICATION_KEY`
3. `BK_DATABASE_PATH`
4. `BK_INSTRUCTIONS_FOLDER`
5. `BK_MINIFIGURES_FOLDER`
6. `BK_PARTS_FOLDER`
7. `BK_REBRICKABLE_API_KEY`
8. `BK_SETS_FOLDER`
3. Create the docker compose yaml
```yaml
services:
bricktracker:
container_name: BrickTracker
restart: unless-stopped
image: gitea.baerentsen.space/frederikbaerentsen/bricktracker:1.2.2
ports:
- "3333:3333"
volumes:
- ./data:/var/lib/bricktracker
- ./static/instructions:/app/static/instructions
- ./static/minifigures:/app/static/minifigures
- ./static/parts:/app/static/parts
- ./static/sets:/app/static/sets
env_file: ".env"
```
4. Start the service: `docker compose up -d`
## Caddy
1. Create the new DNS record for your website
2. Create the Caddyfile at `./Caddyfile`
```conf
https://connors-legos.reeseapps.com:443 {
reverse_proxy 127.0.0.1:3333
}
```
3. Create the Caddy compose.yaml
```yaml
services:
caddy:
image: caddy:<version>
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
```

View File

@@ -0,0 +1,16 @@
services:
bricktracker:
container_name: BrickTracker
restart: unless-stopped
image: gitea.baerentsen.space/frederikbaerentsen/bricktracker:1.2.2
ports:
- "3333:3333"
volumes:
- /home/connorbricktracker/data:/var/lib/bricktracker
- /home/connorbricktracker/static/instructions:/app/static/instructions
- /home/connorbricktracker/static/minifigures:/app/static/minifigures
- /home/connorbricktracker/static/parts:/app/static/parts
- /home/connorbricktracker/static/sets:/app/static/sets
env_file: "/home/connorbricktracker/.env"
security_opt:
- label=disable

View File

@@ -0,0 +1,17 @@
[Container]
ContainerName=BrickTracker
EnvironmentFile=/home/connorbricktracker/.env
Image=gitea.baerentsen.space/frederikbaerentsen/bricktracker:1.2.2
PublishPort=3333:3333
SecurityLabelDisable=true
Volume=/home/connorbricktracker/data:/var/lib/bricktracker
Volume=/home/connorbricktracker/static/instructions:/app/static/instructions
Volume=/home/connorbricktracker/static/minifigures:/app/static/minifigures
Volume=/home/connorbricktracker/static/parts:/app/static/parts
Volume=/home/connorbricktracker/static/sets:/app/static/sets
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -1,20 +1,10 @@
# Caddy Reverse Proxy
- [Caddy Reverse Proxy](#caddy-reverse-proxy)
- [DNS Records](#dns-records)
- [Install Caddy](#install-caddy)
- [Ansible](#ansible)
- [Manual](#manual)
## DNS Records
Before you can create a Caddyfile you need records that point to your server.
You can either create them manually in your DNS provider of choice or use the provided
ddns service:
1. Update the [ddns caddy records](/active/podman_ddns/secrets/caddy_records.yaml)
2. Run the [caddy ansible playbook](/active/podman_ddns/ddns.md#ansible-caddy-records)
- [Adding a new Caddy Record](#adding-a-new-caddy-record)
## Install Caddy
@@ -101,4 +91,15 @@ WantedBy=default.target
```bash
systemctl daemon-reload
systemctl restart caddy
```
```
## Adding a new Caddy Record
Before you can create a Caddyfile you need records that point to your server.
You can either create them manually in your DNS provider of choice or use the provided
ddns service:
1. Update the [ddns caddy records](/active/podman_ddns/secrets/caddy_records.yaml)
2. (Optional) Update the Caddyfile at `active/podman_caddy/secrets/Caddyfile`
3. Run the [caddy ansible playbook](/active/podman_ddns/ddns.md#ansible-caddy-records)

View File

@@ -1,26 +1,32 @@
# DDNS for Route53
- [DDNS for Route53](#ddns-for-route53)
- [Install](#install)
- [As a Systemd Service](#as-a-systemd-service)
- [Ansible Caddy Records](#ansible-caddy-records)
- [Ansible Git Record](#ansible-git-record)
- [Ansible Unifi External Records](#ansible-unifi-external-records)
- [Ansible Hostname reeselink records](#ansible-hostname-reeselink-records)
- [Quickly Update DDNS Records](#quickly-update-ddns-records)
- [Install a New DDNS Service](#install-a-new-ddns-service)
- [Ansible 3D Server Records](#ansible-3d-server-records)
- [Ansible Podman Record](#ansible-podman-record)
- [Ansible Unifi External Records](#ansible-unifi-external-records)
- [Ansible Hostname reeselink records](#ansible-hostname-reeselink-records)
- [Development](#development)
- [Testing](#testing)
- [Building Container Image](#building-container-image)
This service will automatically keep ipv4 and ipv6 records updated in AWS Route53.
This service will automatically keep ipv4 and ipv6 records updated in AWS
Route53.
**NOTE**: This requires the aws cli to be installed on each node with
credentials that can modify records in route53. See
[aws_iam](/active/aws_iam/aws_iam.md) and
[aws_cli](/active/aws_cli/aws_cli.md)
[aws_iam](/active/aws_iam/aws_iam.md) and [aws_cli](/active/aws_cli/aws_cli.md)
## Install
## Quickly Update DDNS Records
### As a Systemd Service
In the event of a record change you can quickly trigger the ddns services with
```bash
systemctl start --all ddns*.service
```
## Install a New DDNS Service
You need two files:
@@ -45,7 +51,12 @@ records:
hosted_zone_id: ABC123456789
```
Then you can install the ddns service with something like
Then you'll need to pick a server responsible for keeping those records
updated. Whichever host you run the service on will also be the host which
provides the public IP. Choose the host accordingly if it will be updating a
public IP on behalf of another server, as the IPv6 address will not be correct.
Now you can install the DDNS service with something like:
```bash
ansible-playbook \
@@ -60,27 +71,32 @@ active/podman_ddns/install_ddns.yaml \
See ansible playbook [install_ddns.yaml](/install_ddns.yaml)
#### Ansible Caddy Records
It's recommended that you have multiple secret `foobar-records.yaml` files for
multiple servers. If you have a podman server, it'll have its own
`podman-records.yaml`. If you have a docker server, it'll have its own
`docker-records.yaml`. Etc. etc.
### Ansible 3D Server Records
```bash
ansible-playbook \
-i ansible/inventory.yaml \
-l 3dserver \
active/podman_ddns/install_ddns.yaml \
-e "@active/podman_ddns/secrets/caddy_records.yaml"
-e "@active/podman_ddns/secrets/3dserver_records.yaml"
```
#### Ansible Git Record
### Ansible Podman Record
```bash
ansible-playbook \
-i ansible/inventory.yaml \
-l podman \
active/podman_ddns/install_ddns.yaml \
-e "@active/podman_ddns/secrets/git_record.yaml"
-e "@active/podman_ddns/secrets/podman_records.yaml"
```
#### Ansible Unifi External Records
### Ansible Unifi External Records
```bash
ansible-playbook \
@@ -90,7 +106,7 @@ active/podman_ddns/install_ddns.yaml \
-e "@active/podman_ddns/secrets/unifi_external_record.yaml"
```
#### Ansible Hostname reeselink records
### Ansible Hostname reeselink records
```bash
export PLAYBOOK_PATH=active/podman_ddns

View File

@@ -5,8 +5,6 @@ services:
image: docker.gitea.com/gitea:1.24
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=postgres:5432
- GITEA__database__NAME=gitea
@@ -16,15 +14,13 @@ services:
networks:
- gitea
volumes:
- /home/gitea/gitea_data:/data
- /home/gitea/gitea_data:/data:Z
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:2222"
depends_on:
- postgres
security_opt:
- label=disable
labels:
- "io.containers.autoupdate=registry"
@@ -39,9 +35,9 @@ services:
networks:
- gitea
volumes:
- /home/gitea/gitea_postgres:/var/lib/postgresql/data
security_opt:
- label=disable
- /home/gitea/gitea_postgres:/var/lib/postgresql/data:Z
labels:
- "io.containers.autoupdate=registry"
networks:
gitea:

View File

@@ -2,6 +2,7 @@
- [Gitea](#gitea)
- [Gitea on Rootless Podman](#gitea-on-rootless-podman)
- [A note on directories](#a-note-on-directories)
- [Create the gitea user](#create-the-gitea-user)
- [Convert Compose to Quadlet](#convert-compose-to-quadlet)
- [Install Quadlets](#install-quadlets)
@@ -15,6 +16,18 @@
## Gitea on Rootless Podman
### A note on directories
```bash
RunMode: prod
AppPath: /usr/local/bin/gitea
WorkPath: /data/gitea
CustomPath: /data/gitea
ConfigFile: /data/gitea/conf/app.ini
Data: /data/gitea/data/
```
### Create the gitea user
```bash

View File

@@ -4,13 +4,11 @@ Requires=postgres.service
[Container]
AutoUpdate=registry
ContainerName=gitea
Environment=USER_UID=1000 USER_GID=1000 GITEA__database__DB_TYPE=postgres GITEA__database__HOST=postgres:5432 GITEA__database__NAME=gitea GITEA__database__USER=gitea GITEA__database__PASSWD=gitea
Image=docker.gitea.com/gitea:1.24
Network=gitea.network
PublishPort=3000:3000
PublishPort=2222:2222
SecurityLabelDisable=true
Volume=/home/gitea/gitea_data:/data
Volume=/home/gitea/gitea_data:/data:Z
Volume=/etc/localtime:/etc/localtime:ro
[Service]

View File

@@ -1,10 +1,10 @@
[Container]
AutoUpdate=registry
ContainerName=postgres
Environment=POSTGRES_USER=gitea POSTGRES_PASSWORD=gitea POSTGRES_DB=gitea
Image=docker.io/library/postgres:15
Network=gitea.network
SecurityLabelDisable=true
Volume=/home/gitea/gitea_postgres:/var/lib/postgresql/data
Volume=/home/gitea/gitea_postgres:/var/lib/postgresql/data:Z
[Service]
Restart=always

View File

@@ -0,0 +1,31 @@
services:
testcraft:
image: gitea.reeseapps.com/services/minecraft:c1ca80b09b4645888e550efb0a2700b2ec1f1645
stdin_open: true
tty: true
volumes:
- /home/minecraft/testcraft:/mc_data
ports:
- 25565:25565
environment:
- MAX_RAM=4
- MIN_RAM=1
security_opt:
- "label=disable"
userns_mode: keep-id
restart: always
nimcraft:
image: gitea.reeseapps.com/services/minecraft:c1ca80b09b4645888e550efb0a2700b2ec1f1645
stdin_open: true
tty: true
volumes:
- /home/minecraft/nimcraft:/mc_data
ports:
- 25566:25565
environment:
- MAX_RAM=4
- MIN_RAM=1
security_opt:
- "label=disable"
userns_mode: keep-id
restart: always

View File

@@ -0,0 +1,108 @@
# Podman Template
- [Podman Template](#podman-template)
- [Install minecraft](#install-minecraft)
- [Create the minecraft user](#create-the-minecraft-user)
- [Convert Compose to Quadlet](#convert-compose-to-quadlet)
- [Install Quadlets](#install-quadlets)
- [Upgrade Quadlets](#upgrade-quadlets)
- [Expose minecraft](#expose-minecraft)
- [Backup minecraft](#backup-minecraft)
## Install minecraft
Find and replace minecraft with the name of the service.
### Create the minecraft user
```bash
useradd minecraft
su - minecraft
ssh-keygen
exit
cp ~/.ssh/authorized_keys /home/minecraft/.ssh/authorized_keys
chown minecraft:minecraft /home/minecraft/.ssh/authorized_keys
loginctl enable-linger $(id -u minecraft)
```
SSH into the server as minecraft
```bash
systemctl --user enable podman-restart
systemctl --user enable --now podman.socket
mkdir -p ~/.config/containers/systemd
```
### Convert Compose to Quadlet
Create a folder called `quadlets` in your podman_minecraft project.
```bash
# Generate the systemd service
podman run \
--security-opt label=disable \
--rm \
-v $(pwd)/active/podman_minecraft:/compose \
-v $(pwd)/active/podman_minecraft/quadlets:/quadlets \
quay.io/k9withabone/podlet \
-f /quadlets \
-i \
--overwrite \
compose /compose/compose.yaml
# Copy the files to the server
scp -r active/podman_minecraft/quadlets/. minecraft:~/.config/containers/systemd/
```
### Install Quadlets
```bash
ssh minecraft
export GAME_SERVER_NAME=testcraft
mkdir $GAME_SERVER_NAME
# Download the server jar (only needed once)
podman run \
-it \
--rm \
-e SERVER_VERSION=1.21.8 \
-v $(pwd)/$GAME_SERVER_NAME:/downloads \
--security-opt label=disable \
--userns keep-id \
docker.io/ducoterra/get-minecraft:latest
systemctl --user daemon-reload
systemctl --user restart $GAME_SERVER_NAME
```
### Upgrade Quadlets
```bash
scp -r quadlets/. minecraft:~/.config/containers/systemd/
ssh minecraft systemctl --user daemon-reload
ssh minecraft systemctl --user restart minecraft
```
## Expose minecraft
1. Create your minecraft ddns record first [following these docs](/active/podman_ddns/ddns.md#)
2. Create a SRV record in your DNS provider like the following:
| Field | Value |
| ----------- | -------------------------------------- |
| Record name | _minecraft._tcp.testcraft.reeseapps.com |
| Value | 0 5 25566 minecraft.reeseapps.com |
3. Test your record with `nslookup`
```bash
nslookup -q=srv _minecraft._tcp.testcraft.reeseapps.com
```
4. Access your server at your domain "testcraft.reeseapps.com"
## Backup minecraft
Follow the Borg [Create a Backup Service Docs](/active/systemd_borg/borg.md#create-a-backup-service)

View File

@@ -0,0 +1,14 @@
[Container]
Environment=MAX_RAM=4 MIN_RAM=1
Image=gitea.reeseapps.com/services/minecraft:c1ca80b09b4645888e550efb0a2700b2ec1f1645
PodmanArgs=--interactive --tty
PublishPort=25566:25565
SecurityLabelDisable=true
UserNS=keep-id
Volume=/home/minecraft/nimcraft:/mc_data
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,14 @@
[Container]
Environment=MAX_RAM=4 MIN_RAM=1
Image=gitea.reeseapps.com/services/minecraft:c1ca80b09b4645888e550efb0a2700b2ec1f1645
PodmanArgs=--interactive --tty
PublishPort=25565:25565
SecurityLabelDisable=true
UserNS=keep-id
Volume=/home/minecraft/testcraft:/mc_data
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,26 @@
[Unit]
Description=Nextcloud AIO Master Container
Documentation=https://github.com/nextcloud/all-in-one/blob/main/docker-rootless.md
After=local-fs.target
Requires=podman.socket
[Container]
ContainerName=nextcloud-aio-mastercontainer
Image=docker.io/nextcloud/all-in-one:latest
PublishPort=0.0.0.0:11001:8080
Volume=nextcloud_aio_mastercontainer:/mnt/docker-aio-config
Volume=/run/user/1001/podman/podman.sock:/var/run/docker.sock:Z
Network=bridge
SecurityLabelDisable=true
Environment=APACHE_PORT=11000
Environment=APACHE_IP_BINDING=0.0.0.0
Environment=WATCHTOWER_DOCKER_SOCKET_PATH=/run/user/1001/podman/podman.sock
Environment=NEXTCLOUD_DATADIR="/home/nextcloud/nextcloud_data"
Environment=SKIP_DOMAIN_VALIDATION=true
[Service]
Restart=always
[Install]
WantedBy=multi-user.target default.target

View File

@@ -55,7 +55,9 @@ systemctl --user enable --now podman.socket
### Create the container autostart service
As the nextcloud user.
Edit the autostart service to include "unless-stopped" containers.
As the nextcloud user:
`systemctl --user edit podman-restart.service`
@@ -63,7 +65,6 @@ As the nextcloud user.
[Service]
ExecStart=
ExecStart=/usr/bin/podman $LOGGING start --all --filter restart-policy=always --filter restart-policy=unless-stopped
ExecStop=
ExecStop=/bin/sh -c '/usr/bin/podman $LOGGING stop $(/usr/bin/podman container ls --filter restart-policy=always --filter restart-policy=unless-stopped -q)'
```
@@ -73,42 +74,21 @@ systemctl --user daemon-reload
### Install Nextcloud
`mkdir -p ~/.config/containers/systemd`
`vim ~/.config/containers/systemd/nextcloud-aio-mastercontainer.container`
```conf
[Unit]
Description=Nextcloud AIO Master Container
Documentation=https://github.com/nextcloud/all-in-one/blob/main/docker-rootless.md
After=local-fs.target
Requires=podman.socket
[Container]
ContainerName=nextcloud-aio-mastercontainer
Image=docker.io/nextcloud/all-in-one:latest
PublishPort=0.0.0.0:11001:8080
Volume=nextcloud_aio_mastercontainer:/mnt/docker-aio-config
Volume=/run/user/1001/podman/podman.sock:/var/run/docker.sock:Z
Network=bridge
SecurityLabelDisable=true
Environment=APACHE_PORT=11000
Environment=APACHE_IP_BINDING=0.0.0.0
Environment=WATCHTOWER_DOCKER_SOCKET_PATH=/run/user/1001/podman/podman.sock
Environment=NEXTCLOUD_DATADIR="/home/nextcloud/nextcloud_data"
Environment=SKIP_DOMAIN_VALIDATION=true
[Service]
Restart=always
[Install]
WantedBy=multi-user.target default.target
```
```bash
systemctl --user daemon-reload
systemctl --user start nextcloud-aio-mastercontainer
# Make the container systemd directory (if needed)
ssh nextcloud mkdir -p ~/.config/containers/systemd
# Create the nextcloud network with ipv6
ssh nextcloud podman network create --ipv6 nextcloud-aio
# Copy the quadlet files
scp \
active/podman_nextcloud/nextcloud-aio-mastercontainer.container \
nextcloud:.config/containers/systemd/
# Reload and restart the service
ssh nextcloud systemctl --user daemon-reload
ssh nextcloud systemctl --user restart nextcloud-aio-mastercontainer
```
### Install Caddy
@@ -167,7 +147,6 @@ systemctl daemon-reload
systemctl start caddy
```
### Firewall
Allow traffic to 11000 from your reverse proxy

View File

@@ -51,4 +51,4 @@ Compile and flash.
{+KC_ENT}{-KC_ENT}{1000}
// full screen
{+KC_LGUI}{+KC_PGUP}{-KC_PGUP}{-KC_LGUI}
```
```

View File

@@ -0,0 +1,12 @@
[Unit]
Description=Runs backup script for {{ repo_name }}
After=network.target
Wants=network-online.target
[Service]
Restart=no
Type=oneshot
ExecStart=/usr/local/script/backup-{{ repo_name }}.sh
[Install]
WantedBy=multi-user.target

View File

@@ -33,6 +33,7 @@ borg create \
--exclude-caches \
--exclude 'home/*/.cache/*' \
--exclude 'var/tmp/*' \
--exclude 'home/*/.snapshots/*' \
{% for dir in exclude_dirs %}
--exclude '{{ dir }}' \
{% endfor %}

View File

@@ -1,11 +1,11 @@
[Unit]
Description=Run Backup backup_{{ repo_name }}.service every hour
Description=Run Backup backup-{{ repo_name }}.service every day
[Timer]
OnCalendar=hourly
OnCalendar=*-*-* 2:00:00
AccuracySec=10min
Persistent=true
Unit=ddns.{{ item.record }}.service
Unit=backup-{{ repo_name }}.service
[Install]
WantedBy=timers.target

View File

@@ -1,13 +1,14 @@
# Borg Backup
- [Borg Backup](#borg-backup)
- [Server Setup](#server-setup)
- [Adding a Client](#adding-a-client)
- [Installing the Backup Service](#installing-the-backup-service)
- [Adding Nextcloud](#adding-nextcloud)
- [Manual Client Use](#manual-client-use)
- [Install Borg](#install-borg)
- [Set up a new root client](#set-up-a-new-root-client)
- [Create a Backup Service](#create-a-backup-service)
- [Check backup service logs](#check-backup-service-logs)
- [Run a Manual Backup](#run-a-manual-backup)
- [Back up and Entire System](#back-up-and-entire-system)
## Server Setup
## Install Borg
<https://borgbackup.readthedocs.io/en/stable/deployment/central-backup-server.html#user-and-group>
@@ -28,14 +29,16 @@ touch /home/backup/.ssh/authorized_keys
chown -R backup:backup /home/backup/.ssh
```
### Adding a Client
## Set up a new root client
Note: See [adding nextcloud](#adding-nextcloud) for nextcloud instructions here.
Backups will be run as the root user. Generate them an SSH key to
On the server as root:
```bash
export BACKUP_HOST=""
export BACKUP_HOST="borg.reeselink.com"
ssh-keygen -C ${USER}@${HOSTNAME} -f ~/.ssh/id_${BACKUP_HOST}
ssh-keygen -C root@${HOSTNAME} -f ~/.ssh/id_${BACKUP_HOST}
cat <<EOF >> ~/.ssh/config
Host ${BACKUP_HOST}
@@ -43,39 +46,20 @@ Host ${BACKUP_HOST}
IdentityFile ~/.ssh/id_${BACKUP_HOST}
User backup
Port 22
KeepAlive yes
EOF
```
Now on the server:
Now on borg.reeselink.com as root:
```bash
export CLIENT_FQDN=""
# Should look like ssh-rsa abcd1234 backup@fqdn.something.com
export SSH_PUBKEY=""
export AUTHKEY_ENTRY="command=\"cd /home/backup/repos/${CLIENT_FQDN}; borg serve --restrict-to-path /home/backup/repos/${CLIENT_FQDN}\",restrict ${SSH_PUBKEY}"
export CLIENT_FQDN="fqdn.reeseapps.com"
export SSH_PUBKEY="ssh-rsa abcd1234 backup@fqdn.something.com"
export BORG_COMMAND="cd /home/backup/repos/${CLIENT_FQDN}; borg serve --restrict-to-path /home/backup/repos/${CLIENT_FQDN}"
export AUTHKEY_ENTRY="command=\"${BORG_COMMAND}\",restrict ${SSH_PUBKEY}"
echo $AUTHKEY_ENTRY >> /home/backup/.ssh/authorized_keys
mkdir /home/backup/repos/${CLIENT_FQDN}
chown backup:backup /home/backup/repos/${CLIENT_FQDN}
```
Then back on the client:
```bash
ssh borg.reeselink.com
# root
borg init --encryption none backup@${BACKUP_HOST}:root
# home
borg init --encryption none backup@${BACKUP_HOST}:home
# app
borg init --encryption none backup@${BACKUP_HOST}:gitea
# another app
borg init --encryption none backup@${BACKUP_HOST}:nextcloud
```
### Installing the Backup Service
## Create a Backup Service
Create your vars file in `secrets/host_vars.yaml`
@@ -97,30 +81,29 @@ stop_user_services:
```
```bash
# Update all existing backup services for podman
for var_file in $(ls active/systemd_borg/secrets); do
ansible-playbook \
-i active/ansible/inventory.yaml \
-i ansible/inventory.yaml \
-l podman \
active/systemd_borg/install_backup.yaml \
-e "@active/systemd_borg/secrets/gitea_vars.yaml"
-e "@active/systemd_borg/secrets/$var_file"
done
```
#### Adding Nextcloud
## Check backup service logs
Rather than creating a client, just set the borg backup location to:
```text
backup@borg.reeselink.com:nextcloud
```bash
ssh podman journalctl -u 'backup-*' -f
```
Then run the backup. It will generate a pubkey. Copy this into the authorized_keys file.
## Manual Client Use
## Run a Manual Backup
```bash
borg list borg.reeselink.com:home
# Do not include the first / in the path
export PATH_TO_BACKUP=var/home/ducoterra
export PATH_TO_BACKUP=home/ducoterra
export BORG_REPO=borg.reeselink.com:home
# If not initialized, do that now
@@ -148,6 +131,10 @@ borg create \
-e "pp:/${PATH_TO_BACKUP}/.config/libvirt" \
-e "pp:/${PATH_TO_BACKUP}/.local/share/containers" \
-e "pp:/${PATH_TO_BACKUP}/.local/share/docker" \
-e "pp:/${PATH_TO_BACKUP}/.npm" \
-e "pp:/${PATH_TO_BACKUP}/.ollama" \
-e "pp:/${PATH_TO_BACKUP}/Downloads" \
-e "pp:/${PATH_TO_BACKUP}/Nextcloud" \
${BORG_REPO}::$(date +"%F-%H-%M-%S") \
/${PATH_TO_BACKUP}
@@ -156,4 +143,31 @@ borg mount $BORG_REPO::2025-05-14-00-44-05 /mnt/
# Restore a borg archive to a location (dry run)
borg extract --dry-run --list --strip-components 1 $BORG_REPO::my-files home/USERNAME
```
```
### Back up and Entire System
```bash
export BORG_REPO=borg.reeselink.com:root
borg create \
--verbose \
--filter AME \
--list \
--stats \
--progress \
--show-rc \
--compression lz4 \
--exclude root/.cache \
--exclude var/lib/docker \
--exclude var/lib/containers \
--exclude usr/share/ollama \
--exclude home \
--exclude proc \
--exclude dev \
--exclude sys \
--exclude tmp \
--exclude .snapshots \
${BORG_REPO}::$(date +"%F-%H-%M-%S") \
/
```

View File

@@ -8,36 +8,32 @@
path: /usr/local/script
state: directory
mode: '0755'
- name: Copy backup.service
- name: Copy backup-{{ repo_name }}.service
template:
src: backup.service
dest: /etc/systemd/system/backup-{{ repo_name }}.service
owner: root
group: root
mode: '0644'
- name: Copy backup.timer
- name: Copy backup-{{ repo_name }}.timer
template:
src: backup.timer
dest: /etc/systemd/system/backup-{{ repo_name }}.timer
owner: root
group: root
mode: '0644'
- name: Template backup.sh
- name: Template backup-{{ repo_name }}.sh
template:
src: backup.sh.j2
dest: /usr/local/script/backup-{{ repo_name }}.sh
owner: root
group: root
mode: '0744'
# - name: Reload ddns timer
# ansible.builtin.systemd_service:
# state: restarted
# name: ddns.{{ item.record }}.timer
# enabled: true
# daemon_reload: true
# loop: "{{ records }}"
# - name: Run ddns service
# ansible.builtin.systemd_service:
# state: restarted
# name: ddns.{{ item.record }}.service
# loop: "{{ records }}"
- name: Initialize Repo {{ borg_user }}@{{ borg_host }}:{{ repo_name }}
script: /usr/bin/borg init -e none {{ borg_user }}@{{ borg_host }}:{{ repo_name }}
ignore_errors: yes
- name: Reload backup timer backup-{{ repo_name }}.timer
ansible.builtin.systemd_service:
name: backup-{{ repo_name }}.timer
enabled: true
daemon_reload: true

View File

@@ -0,0 +1,8 @@
FROM alpine:latest
RUN apk add -U wireguard-tools
COPY wg0.conf /etc/wireguard/wg0.conf
CMD wg-quick up wg0 && \
wg set wg0 peer 'lvghTtIHSXzOfpruVHtRnnAiZJeUi8A6lzhE21GSJjA=' allowed-ips 10.10.0.2/32 && \
watch -n 1 wg

View File

@@ -0,0 +1,35 @@
# TODO
# 1. Ask for listen port
# 2. Ask for name of eth interface
apt-get update
apt-get upgrade -y
apt-get install -y raspberrypi-kernel-headers
apt install -y wireguard qrencode iptables
cat > /etc/sysctl.conf <<EOF
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
reboot
cd /etc/wireguard
umask 077
export PRIVKEY=$(wg genkey)
echo $PRIVKEY | tee privatekey | wg pubkey | tee publickey
echo $PRIVKEY | tee --append /etc/wireguard/wg0.conf
cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = 10.10.0.1/24
Address = fd86:ea04:1111::1/64
SaveConfig = true
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
PrivateKey = $PRIVKEY
EOF
sysctl -p
wg-quick up wg0
wg

View File

@@ -0,0 +1,28 @@
- name: Create Backup Service
hosts: all
vars_files:
- secrets/vars.yaml
tasks:
- name: Install the latest version of Wireguard Tools
ansible.builtin.dnf:
name: wireguard-tools
state: latest
- name: Create wg0.conf
template:
dest: /etc/wireguard/wg0.conf
src: wg0.conf.j2
owner: root
group: root
mode: '0600'
- name: enable and persist ip forwarding
sysctl:
name: net.ipv4.ip_forward
value: "1"
state: present
sysctl_set: yes
reload: yes
- name: start wireguard and enable on boot
systemd:
name: wg-quick@wg0
enabled: yes
state: started

View File

@@ -0,0 +1,47 @@
# TODO
# 1. Read server pubkey from file
wg
echo -n 'Client Name: '
read name
echo -n 'Last digit of client IP \(10.10.0.?\): '
read ip
echo -n 'Server PubKey: '
read server_pubkey
mkdir $name
cd $name
export PRIVKEY=$(wg genkey)
echo $PRIVKEY | tee $name"_privkey"
export PUBKEY=$(echo $PRIVKEY | wg pubkey)
echo $PUBKEY | tee $name"_pubkey"
cat > $name".conf" <<EOF
[Interface]
PrivateKey = $PRIVKEY
Address = 10.10.0.$ip/32, fd86:ea04:1111::$ip/128
DNS = 10.10.0.1
[Peer]
PublicKey = $server_pubkey
Endpoint = wireguard.reeseapps.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
EOF
cat >> /etc/wireguard/wg0.conf <<EOF
# $name
[Peer]
PublicKey = $PUBKEY
AllowedIPs = 10.10.0.$ip/32
EOF
wg set wg0 peer $PUBKEY allowed-ips 10.10.0.$ip/32
qrencode -t ansiutf8 < $name".conf"
cd ..
chmod -R 600 $name
wg

1
active/systemd_wireguard/qr.sh Executable file
View File

@@ -0,0 +1 @@
qrencode -t ansiutf8

View File

@@ -0,0 +1,5 @@
# {{ ansible_managed }}
[Interface]
Address = 10.0.1.1/24
ListenPort = 51820
PrivateKey = {{ server_privkey }}

View File

@@ -0,0 +1,39 @@
# Wireguard
## Install
```bash
ansible-playbook \
-i ansible/inventory.yaml \
-l wireguard \
active/systemd_wireguard/install_backup.yaml \
-e "@active/systemd_wireguard/secrets/vars.yaml"
```
## Add a client
```bash
export WG_IP_SUFFIX=$(cat IP && echo $(($(cat IP) + 1)) > IP)
export PRIVKEY=$(wg genkey)
export PUBKEY=$(echo $PRIVKEY | wg pubkey)
export SERVER_PUBKEY=$(cat publickey)
cat <<EOF > id_$WG_IP_SUFFIX
[Interface]
PrivateKey = $PRIVKEY
Address = 10.10.0.$WG_IP_SUFFIX/32
DNS = 10.10.0.1
[Peer]
PublicKey = $SERVER_PUBKEY
Endpoint = pihole.reeserelease.com:51820
AllowedIPs = 10.10.0.1/32
EOF
cat id_$WG_IP_SUFFIX | qrencode -t ansiutf8
echo "Added ID $WG_IP_SUFFIX"
echo "Press enter to continue"
read
wg set wg0 peer $PUBKEY allowed-ips 10.10.0.$WG_IP_SUFFIX/32
wg-quick down wg0 && wg-quick up wg0
```

View File

@@ -259,7 +259,7 @@ vim /etc/hosts
`192.168.122.195 freeipa.reese.reeselink.com`
# This should populate /etc/krb5.conf and /etc/sssd/sssd.conf
realm join freeipa.reese.reeselink.com -v
realm join -U someuser freeipa.reese.reeselink.com -v
# AD should be configured to create the user's home dir, but to be safe
export freeipa_user=ducoterra

411
templates/os/foobar.md Normal file
View File

@@ -0,0 +1,411 @@
# Foobar
These docs frequently reference an "operator" and a "client". The operator is
your laptop, computer, pipeline, or any device will be connecting to, or
configuring, the OS during/after install. The client is the device you're
installing the OS onto.
- [Foobar](#foobar)
- [Installation](#installation)
- [Network](#network)
- [Firewalld Configuration](#firewalld-configuration)
- [Setup SSH](#setup-ssh)
- [Fail2Ban](#fail2ban)
- [Set eui64 on network interface](#set-eui64-on-network-interface)
- [Set up Network Bridge](#set-up-network-bridge)
- [Storage](#storage)
- [BTRFS Parent Volumes](#btrfs-parent-volumes)
- [BTRFS Snapshots](#btrfs-snapshots)
- [BTRFS Maintenance](#btrfs-maintenance)
- [TPM2 Luks Decryption](#tpm2-luks-decryption)
- [Users](#users)
- [Change your password](#change-your-password)
- [Updates](#updates)
- [Automatic Updates](#automatic-updates)
- [Monitoring](#monitoring)
- [Disk Usage](#disk-usage)
- [Disk Wear](#disk-wear)
- [Backups](#backups)
- [Downgrading Kernel](#downgrading-kernel)
- [Apps](#apps)
- [Package Manager](#package-manager)
- [Install and Enable Cockpit](#install-and-enable-cockpit)
- [Install and Enable Virtualization](#install-and-enable-virtualization)
- [Install and Enable Containers](#install-and-enable-containers)
- [Troubleshooting](#troubleshooting)
- [Disable Swap](#disable-swap)
- [Disable Selinux](#disable-selinux)
## Installation
1. Configure network first
1. Set a hostname
2. Disable ipv6 privacy extensions
2. Software Selection
1. Headless Management
3. User Creation
1. Set a simple password, we'll change it later
4. Disk partitioning
1. Select manual (blivet) partitioning
2. Create a 1GB EFI system partition and mount it at `/boot/efi`
3. Create a 1GB ext4 partition and mount it at `/boot`
4. Create a btrfs volume with the remaining data and name it something unqiue, do not mount it
5. Create a btrfs subvolume called "root" and mount it at `/`
6. Create any other btrfs subvolumes you might need
5. Take note of the ipv4 and ipv6 address. Update any DNS records at this time.
6. Install and reboot
## Network
### Firewalld Configuration
Set the default firewalld zone to `public`
```bash
# Note, you probably don't have to do this. Check Cockpit Network -> Firewall
# firewall-cmd --set-default-zone=public
```
Firewalld will be on and blocking by default. You can check the zone and allowed ports with:
```bash
firewall-cmd --zone=public --list-ports
firewall-cmd --zone=public --list-services
```
Allow Cockpit with
```bash
firewall-cmd --permanent --zone=public --add-port=9090/tcp
firewall-cmd --reload
```
### Setup SSH
See [README](/README.md#ssh-key-generation)
### Fail2Ban
On the server:
```bash
# Run tmux session
tmux
dnf install -y fail2ban
# Setup initial rules
cat <<EOF > /etc/fail2ban/jail.local
# Jail configuration additions for local installation
# Adjust the default configuration's default values
[DEFAULT]
# Optional enter an trusted IP never to ban
# ignoreip = 2600:1700:1e6c:a81f::0/64
bantime = 6600
backend = auto
# The main configuration file defines all services but
# deactivates them by default. We have to activate those neeeded
[sshd]
enabled = true
EOF
systemctl enable fail2ban --now
# OPTIONAL: follow logs
tail -f /var/log/fail2ban.log
```
Checking, banning, unbanning
```bash
# See banned clients
fail2ban-client banned
# See jails (sshd should be one of them)
fail2ban-client status
# Unban a client from the sshd jail
fail2ban-client set sshd unbanip <IP address>
```
### Set eui64 on network interface
Ensures consistent mac-based IPv6 address.
```bash
nmcli connection modify Wired\ connection\ 1 ipv6.addr-gen-mode eui64
```
### Set up Network Bridge
Networking -> Add bridge -> add network interface and save
```bash
nmcli connection modify bridge0 ipv6.addr-gen-mode eui64
```
## Storage
### BTRFS Parent Volumes
In `/etc/fstab`, add the parent volumes for your disks mounted with subvolid=5 at `/btrfs` so you can see
all subvolumes.
```conf
UUID=64beedac-c0c9-48bf-a3ae-7707df6ebc97 /btrfs/3dserver-root btrfs subvolid=5,compress=zstd:1,x-systemd.device-timeout=0 0 0
UUID=3c76b83f-7547-4c18-b08f-9e7902022b8d /btrfs/3dserver-data btrfs subvolid=5,compress=zstd:1,x-systemd.device-timeout=0 0 0
```
```bash
systemctl daemon-reload
mount -a --mkdir
```
### BTRFS Snapshots
<https://en.opensuse.org/openSUSE:Snapper_Tutorial>
<http://snapper.io/manpages/snapper-configs.html>
We'll be using snapper, a tool for automating and controlling snapshot behavior.
```bash
dnf install snapper dnf-plugin-snapper
# Allow selinux management
semanage permissive -a snapperd_t
# Note, if you mess something up you can run snapper -c root delete-config to delete
# System configs are stored in /etc/sysconfig/snapper as well as /etc/snapper
snapper -c root create-config /
snapper -c data create-config /path/to/other/data
# Enable automatic snapshots
systemctl enable --now snapper-timeline.timer
# Enable automatic cleanup
systemctl enable --now snapper-cleanup.timer
# Enable snapshots on boot
systemctl enable --now snapper-boot.timer
# List snapshots
snapper -c root list
# Create snapshot manually
snapper -c root create --description "test snapshot"
# Delete first snapshot
snapper -c root delete 1
```
Note - you probably don't want to keep yearly snapshots.
Edit `/etc/snapper/configs/root` and change `TIMELINE_LIMIT_YEARLY=` to `0`.
### BTRFS Maintenance
```bash
# Start a scrub in the foreground (-B) at /
btrfs scrub start -B /
```
### TPM2 Luks Decryption
Mostly taken from here:
<https://gist.github.com/jdoss/777e8b52c8d88eb87467935769c98a95>
PCR reference for `--tpm2-pcrs` args
```text
0: System firmware executable
2: Kernel
4: Bootloader
7: Secure boot state
8: Cmdline
9: Initrd
```
Note, if your threat vector is people trying to get data off your old disks after throwing them
away, you can set `--tpm2-pcrs=""`. Someone could gain access to your encrypted partition if they
can access your machine physically by manipulating the boot parameters but you're guaranteed to
unlock despite updates and upgrades.
Basic commands:
```bash
# Run tmux session
tmux
# Show tpm2 devices
systemd-cryptenroll --tpm2-device=list
# Show crypto luks block devices
blkid -t TYPE=crypto_LUKS
# Enroll the tpm2 device with systemd-cryptenroll
systemd-cryptenroll /dev/nvme0n1p3 --tpm2-device=auto --tpm2-pcrs=""
####################
##### OPTIONAL #####
####################
# If you have lots of devices to decrypt (like a btrfs raid array), use these commands.
# Get all crypto luks partitions
blkid | grep crypto_LUKS
# List them all space-separated and drop the '/dev'
LUKS_DEVS="nvme0n1p4 nvme1n1p1 nvme2n1p1 nvme3n1p1 nvme5n1p1 nvme4n1p1 nvme6n1p1"
# Check that your list is good
for dev in $LUKS_DEVS; do echo will enroll /dev/$dev; done
# Enroll
for dev in $LUKS_DEVS; do \
echo "Enrolling /dev/$dev"; \
systemd-cryptenroll /dev/$dev --tpm2-device=auto --tpm2-pcrs=""; \
done
########################
##### END OPTIONAL #####
########################
# Append to command line args
echo "add_dracutmodules+=\" tpm2-tss \"" | tee /etc/dracut.conf.d/tpm2.conf
dracut -f
```
Finally, `vim /etc/default/grub` and add `rd.luks.options=tpm2-device=auto` to GRUB_CMDLINE_LINUX
```bash
# Update Grub
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot
# Cross your fingers that you don't have to go type in the password manually.
# Yes, 60 full seconds is too long. Go type your password in.
```
If you need to reenroll for some reason:
```bash
# Reenroll
systemd-cryptenroll /dev/nvme0n1p3 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=""
```
## Users
### Change your password
In Cockpit navigate to Accounts -> user -> Set password
## Updates
### Automatic Updates
In Cockpit navigate to software updates -> automatic updates -> install -> security updates only
## Monitoring
In Cockpit: Overview -> View metrics and history -> Install PCP Support -> Metrics settings -> Turn on Collect Metrics
### Disk Usage
TODO
### Disk Wear
TODO
## Backups
See [borg.md](/active/systemd_borg/borg.md)
### Downgrading Kernel
```bash
dnf install koji
# Note: format is kernel-version.fedora-version
cd $(mktemp -d) && koji download-build --arch=x86_64 --arch=noarch kernel-6.11.3-300.fc41 && dnf install ./*
reboot
```
## Apps
### Package Manager
Configure dnf to use the fastest mirror:
```bash
echo 'fastestmirror=1' >> /etc/dnf/dnf.conf
dnf clean all
dnf update --refresh -y
# libdnf5 is required for ansible to work
dnf install -y glances tmux vim python3-libdnf5
```
### Install and Enable Cockpit
<https://cockpit-project.org/running>
```bash
dnf install cockpit
systemctl enable --now cockpit.socket
firewall-cmd --add-service=cockpit
firewall-cmd --add-service=cockpit --permanent
```
## Install and Enable Virtualization
Don't forget to add a btrfs subvolume for `/var/lib/libvirt`
```bash
# Since we already created our /btrfs mountpoint, this volume will show up automatically
# at /btrfs/libvirt
btrfs sub create /btrfs/libvirt
```
Now create an fstab entry that mounts the volume at /var/lib/libvirt
```bash
UUID=... /var/lib/libvirt btrfs subvol=libvirt,compress=zstd:1,x-systemd.device-timeout=0 0 0
```
Mount the libvirt volume:
```bash
systemctl daemon-reload
mount -a --mkdir
# Check that the mount was successful. This will print something if our mount worked.
mount | grep -i /var/lib/libvirt
```
Create a snapshot schedule for libvirt.
```bash
snapper -c libvirt create-config /var/lib/libvirt
# Don't forget to edit "YEARLY" at /etc/snapper/configs/libvirt
```
Install and enable the virtualization service.
```bash
dnf group install --with-optional virtualization
systemctl enable --now libvirtd
```
Install the cockpit machines application.
## Install and Enable Containers
## Troubleshooting
### Disable Swap
```bash
swapoff -a
zramctl --reset /dev/zram0
dnf -y remove zram-generator-defaults
```
### Disable Selinux
By default selinux will be enforcing. You can set it to permissive with
```bash
setenforce 0
```
And then make it permanent by editing `/etc/selinux/config` and inserting `SELINUX=permissive`.

View File

@@ -0,0 +1,3 @@
# Compose
Put your compose.yaml here.

View File

@@ -0,0 +1,12 @@
services:
foobar:
container_name: foobar
restart: always
image: localhost/foobar:latest
ports:
- "8080:8080"
volumes:
- /home/foobar/data:/var/app/data
security_opt:
- label=disable
userns_mode: keep-id

131
templates/podman/foobar.md Normal file
View File

@@ -0,0 +1,131 @@
# Podman foobar
- [Podman foobar](#podman-foobar)
- [Setup foobar Project](#setup-foobar-project)
- [Install foobar](#install-foobar)
- [Create the foobar user](#create-the-foobar-user)
- [Write the foobar compose spec](#write-the-foobar-compose-spec)
- [Convert foobar compose spec to quadlets](#convert-foobar-compose-spec-to-quadlets)
- [Expose foobar](#expose-foobar)
- [firewalld](#firewalld)
- [Backup foobar](#backup-foobar)
- [Upgrade foobar](#upgrade-foobar)
- [Upgrade Quadlets](#upgrade-quadlets)
- [Notes](#notes)
- [SELinux](#selinux)
## Setup foobar Project
1. Copy and rename this folder to active/podman_foobar
2. Find and replace foobar with the name of the service.
3. Create the rootless user to run the podman containers
4. Write the compose.yaml spec for your service
5. Convert the compose.yaml spec to a quadlet
6. Install the quadlet on the podman server
7. Expose the quadlet service
8. Install a backup service and timer
## Install foobar
### Create the foobar user
```bash
useradd foobar
su - foobar
ssh-keygen
exit
cp ~/.ssh/authorized_keys /home/foobar/.ssh/authorized_keys
chown foobar:foobar /home/foobar/.ssh/authorized_keys
loginctl enable-linger $(id -u foobar)
```
SSH into the server as foobar
```bash
systemctl --user enable podman-restart
systemctl --user enable --now podman.socket
mkdir -p ~/.config/containers/systemd
```
### Write the foobar compose spec
Edit the compose.yaml at active/foobar/compose/compose.yaml
### Convert foobar compose spec to quadlets
On your local machine:
```bash
# Generate the systemd service
podman run \
--security-opt label=disable \
--rm \
-v $(pwd)/active/foobar/:/compose \
-v $(pwd)/active/foobar/quadlets:/quadlets \
quay.io/k9withabone/podlet \
-f /quadlets \
-i \
--overwrite \
compose /compose/compose.yaml
# Copy the files to the server
scp -r active/foobar/quadlets/. foobar:~/.config/containers/systemd/
```
```bash
ssh foobar systemctl --user daemon-reload
ssh foobar systemctl --user restart foobar
# Enables auto-update service which will pull new container images automatically every day
ssh foobar systemctl --user enable --now podman-auto-update.timer
```
### Expose foobar
1. If you need a domain, follow the [DDNS instructions](/active/podman_ddns/ddns.md#install-a-new-ddns-service)
2. For a web service, follow the [Caddy instructions](/active/podman_caddy/caddy.md#adding-a-new-caddy-record)
3. Finally, follow your OS's guide for opening ports via its firewall service.
#### firewalld
```bash
# command to get current active zone and default zone
firewall-cmd --get-active-zones
firewall-cmd --get-default-zone
# command to open 443 on tcp
firewall-cmd --permanent --zone=<zone> --add-port=443/tcp
# command to open 80 and 443 on tcp and udp
firewall-cmd --permanent --zone=<zone> --add-port={80,443}/{tcp,udp}
# command to list available services and then open http and https
firewall-cmd --get-services
firewall-cmd --permanent --zone=<zone> --add-service={http,https}
```
## Backup foobar
Follow the [Borg Backup instructions](/active/systemd_borg/borg.md#set-up-a-client-for-backup)
## Upgrade foobar
### Upgrade Quadlets
Upgrades should be a repeat of [writing the compose spec](#convert-compose-to-quadlet) and [installing the quadlets](#convert-compose-to-quadlet)
```bash
scp -r quadlets/. foobar:~/.config/containers/systemd/
ssh foobar systemctl --user daemon-reload
ssh foobar systemctl --user restart foobar
```
## Notes
### SELinux
<https://blog.christophersmart.com/2021/01/31/podman-volumes-and-selinux/>
:z allows a container to share a mounted volume with all other containers.
:Z allows a container to reserve a mounted volume and prevents any other container from accessing.

View File

@@ -0,0 +1,3 @@
# Quadlets
Put your quadlets here.

View File

@@ -0,0 +1,49 @@
# foobar
- [foobar](#foobar)
- [Setup foobar Project](#setup-foobar-project)
- [Service Variables](#service-variables)
- [Install foobar](#install-foobar)
- [Upgrade foobar](#upgrade-foobar)
- [Backup foobar](#backup-foobar)
- [Restore foobar](#restore-foobar)
- [Uninstall foobar](#uninstall-foobar)
## Setup foobar Project
1. Copy and rename this folder to active/systemd_foobar
2. Find and replace foobar with the name of the service
3. Write the foobar.service spec
4. (OPTIONAL) Write the foobar.timer spec
5. (OPTIONAL) Write the foobar.sh.j2 template
6. Write the install_foobar.yaml ansible template
7. Install the service via ansible
8. Expose the service
9. Install a backup service and timer
## Service Variables
1. For most vars,populate `vars.yaml`
2. For secret vars, create a new folder called `secrets/` and put a `vars.yaml` there.
## Install foobar
```bash
# Run the playbook
ansible-playbook \
-i ansible/inventory.yaml \
-l podman \
active/systemd_foobar/install_foobar.yaml \
-e "@active/systemd_foobar/vars.yaml" \
-e "@active/systemd_foobar/secrets/vars.yaml"
```
## Upgrade foobar
## Backup foobar
Follow the [Borg Backup instructions](/active/systemd_borg/borg.md#set-up-a-client-for-backup)
## Restore foobar
## Uninstall foobar

View File

@@ -0,0 +1,12 @@
[Unit]
Description=Runs foobar
After=network.target
Wants=network-online.target
[Service]
Restart=no
Type=oneshot
ExecStart=/usr/local/script/foobar.sh
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,3 @@
#!/bin/sh
echo "hello foobar!"

View File

@@ -0,0 +1,11 @@
[Unit]
Description=Run Foobar every day
[Timer]
OnCalendar=*-*-* 2:00:00
AccuracySec=10min
Persistent=true
Unit=foobar.service
[Install]
WantedBy=timers.target

View File

@@ -0,0 +1,39 @@
- name: Create Backup Service
hosts: all
vars_files:
- secrets/vars.yaml
tasks:
- name: Create /usr/local/script dir
ansible.builtin.file:
path: /usr/local/script
state: directory
mode: '0755'
- name: Copy foobar.service
template:
src: backup.service
dest: /etc/systemd/system/foobar.service
owner: root
group: root
mode: '0644'
- name: Copy foobar.timer
template:
src: backup.timer
dest: /etc/systemd/system/foobar.timer
owner: root
group: root
mode: '0644'
- name: Template foobar.sh
template:
src: backup.sh.j2
dest: /usr/local/script/foobar.sh
owner: root
group: root
mode: '0744'
- name: Something foobar related that might fail
script: echo 'hello foobar!'
ignore_errors: yes
- name: Reload foobar.timer
ansible.builtin.systemd_service:
name: foobar.timer
enabled: true
daemon_reload: true

View File

@@ -0,0 +1 @@
name: foobar