Compare commits

...

5 Commits

  1. 63
      Makefile.common
  2. 13
      base/Makefile
  3. 1
      base/config/examples/fastfetch.env
  4. 110
      base/config/fastfetch.jsonc
  5. 12
      base/config/install-fastfetch.sh
  6. 14
      base/install-fastfetch.service
  7. 16
      base/overlay.bu
  8. 9
      base/profile.d/fastfetch.sh
  9. 1
      butane.blocklist
  10. 13
      lego/Makefile
  11. 3
      lego/config/examples/config.env
  12. 3
      lego/config/hooks/flag-as-renewed.sh
  13. 52
      lego/lego-renew.container
  14. 12
      lego/lego-renew.timer
  15. 52
      lego/lego-run.container
  16. 12
      lego/lego.target
  17. 9
      lego/overlay.bu
  18. 10
      nextcloud/Makefile
  19. 4
      nextcloud/config/examples/collabora.env
  20. 7
      nextcloud/config/examples/config.env
  21. 19
      nextcloud/config/nginx.conf
  22. 4
      nextcloud/nextcloud-app.container
  23. 4
      nextcloud/nextcloud-collabora.container
  24. 4
      nextcloud/nextcloud-cron.container
  25. 2
      nextcloud/nextcloud-cron.timer
  26. 13
      nextcloud/other/traefik-collabora.yaml
  27. 13
      nextcloud/other/traefik-nextcloud.yaml
  28. 9
      nextcloud/overlay.bu
  29. 1
      nginx/nginx-server.container
  30. 9
      postgresql/overlay.bu
  31. 1
      postgresql/postgresql-server.container
  32. 6
      qemu-user-static/Makefile
  33. 0
      qemu-user-static/config/container/Containerfile
  34. 0
      qemu-user-static/config/container/container-entrypoint
  35. 4
      qemu-user-static/qemu-user-static.build
  36. 22
      restic-server/Makefile
  37. 23
      restic-server/other/traefik/restic.yaml
  38. 9
      restic-server/overlay.bu
  39. 31
      restic-server/restic-server.container
  40. 2
      restic-server/tmpfiles.d/restic-server.conf
  41. 5
      samba/Makefile
  42. 15
      samba/config/container/Containerfile
  43. 10
      samba/config/container/container-entrypoint
  44. 19
      samba/config/examples/smb.conf.d/10-shares.conf
  45. 8
      samba/config/smb.conf.d/00-global.conf
  46. 10
      samba/samba-build.timer
  47. 9
      samba/samba.build
  48. 39
      samba/samba.container
  49. 14
      samba/samba.target
  50. 8
      samba/tmpfiles.d/samba.conf
  51. 24
      seedbox/Makefile
  52. 27
      seedbox/flaresolverr.container
  53. 34
      seedbox/jellyfin.container
  54. 35
      seedbox/lidarr.container
  55. 28
      seedbox/other/samba/10-shares.conf
  56. 16
      seedbox/other/traefik/jellyfin.yaml
  57. 16
      seedbox/other/traefik/lidarr.yaml
  58. 16
      seedbox/other/traefik/prowlarr.yaml
  59. 16
      seedbox/other/traefik/qbittorrent.yaml
  60. 16
      seedbox/other/traefik/radarr.yaml
  61. 16
      seedbox/other/traefik/sonarr.yaml
  62. 9
      seedbox/overlay.bu
  63. 35
      seedbox/prowlarr.container
  64. 36
      seedbox/qbittorrent.container
  65. 35
      seedbox/radarr.container
  66. 11
      seedbox/seedbox.target
  67. 36
      seedbox/sonarr.container
  68. 1
      seedbox/sysctl.d/seedbox.conf
  69. 22
      seedbox/tmpfiles.d/seedbox.conf
  70. 11
      traefik/Makefile
  71. 16
      traefik/config/examples/conf.d/itix-middlewares.yaml
  72. 15
      traefik/config/examples/conf.d/ping.yaml
  73. 0
      traefik/config/examples/itix-admins.txt
  74. 0
      traefik/config/examples/itix-users.txt
  75. 34
      traefik/config/traefik.yaml
  76. 9
      traefik/overlay.bu
  77. 43
      traefik/traefik.container
  78. 11
      traefik/traefik.target
  79. 16
      vmagent/Makefile
  80. 1
      vmagent/config/examples/conf.d/remotewrite.token
  81. 3
      vmagent/config/examples/vmagent.local.env
  82. 2
      vmagent/config/vmagent.global.env
  83. 9
      vmagent/overlay.bu
  84. 33
      vmagent/vmagent.container
  85. 15
      vsftpd/Makefile
  86. 20
      vsftpd/config/container/Containerfile
  87. 25
      vsftpd/config/container/container-entrypoint
  88. 27
      vsftpd/config/container/vsftpd-virtual
  89. 24
      vsftpd/config/examples/vsftpd.conf.d/local-users.conf
  90. 5
      vsftpd/config/examples/vsftpd.conf.d/tls.conf
  91. 18
      vsftpd/config/examples/vsftpd.conf.d/virtual-users.conf
  92. 21
      vsftpd/config/vsftpd.conf.d/global.conf
  93. 9
      vsftpd/overlay.bu
  94. 6
      vsftpd/tmpfiles.d/vsftpd.conf
  95. 10
      vsftpd/vsftpd-build.timer
  96. 17
      vsftpd/vsftpd-load-renewed-certificate.service
  97. 9
      vsftpd/vsftpd.build
  98. 52
      vsftpd/vsftpd.container
  99. 11
      vsftpd/vsftpd.target

63
Makefile.common

@ -73,28 +73,32 @@ SYSTEMD_TIMER_NAMES := $(wildcard *.timer)
SYSTEMD_MAIN_UNIT_NAMES := $(wildcard *.target) SYSTEMD_MAIN_UNIT_NAMES := $(wildcard *.target)
# Configuration files # Configuration files
CONFIG_FILES = $(filter-out %/examples, $(wildcard config/*)) CONFIG_FILES := $(shell find config/ -mindepth 1 \! -path "config/examples/*" \! -path "config/examples" 2>/dev/null)
TMPFILESD_FILES = $(filter-out %/examples, $(wildcard tmpfiles.d/*)) TMPFILESD_FILES = $(filter-out %/examples, $(wildcard tmpfiles.d/*))
SYSCTLD_FILES = $(filter-out %/examples, $(wildcard sysctl.d/*)) SYSCTLD_FILES = $(filter-out %/examples, $(wildcard sysctl.d/*))
PROFILED_FILES = $(filter-out %/examples, $(wildcard profile.d/*))
TARGET_CONFIG_FILES = $(patsubst config/%, $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%, $(CONFIG_FILES)) TARGET_CONFIG_FILES = $(patsubst config/%, $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%, $(CONFIG_FILES))
TARGET_TMPFILESD_FILES = $(patsubst tmpfiles.d/%, $(TARGET_CHROOT)/etc/tmpfiles.d/%, $(TMPFILESD_FILES)) TARGET_TMPFILESD_FILES = $(patsubst tmpfiles.d/%, $(TARGET_CHROOT)/etc/tmpfiles.d/%, $(TMPFILESD_FILES))
TARGET_SYSCTLD_FILES = $(patsubst sysctl.d/%, $(TARGET_CHROOT)/etc/sysctl.d/%, $(SYSCTLD_FILES)) TARGET_SYSCTLD_FILES = $(patsubst sysctl.d/%, $(TARGET_CHROOT)/etc/sysctl.d/%, $(SYSCTLD_FILES))
TARGET_PROFILED_FILES = $(patsubst profile.d/%, $(TARGET_CHROOT)/etc/profile.d/%, $(PROFILED_FILES))
# Example configuration files # Example configuration files
EXAMPLES_CONFIG_FILES = $(wildcard config/examples/*) EXAMPLES_CONFIG_FILES := $(shell find config/examples -mindepth 1 2>/dev/null)
EXAMPLES_TMPFILESD_FILES = $(wildcard tmpfiles.d/examples/*) EXAMPLES_TMPFILESD_FILES = $(wildcard tmpfiles.d/examples/*)
EXAMPLES_SYSCTLD_FILES = $(wildcard sysctl.d/examples/*) EXAMPLES_SYSCTLD_FILES = $(wildcard sysctl.d/examples/*)
EXAMPLES_PROFILED_FILES = $(wildcard profile.d/examples/*)
TARGET_EXAMPLES_CONFIG_FILES = $(patsubst config/examples/%, $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%, $(EXAMPLES_CONFIG_FILES)) TARGET_EXAMPLES_CONFIG_FILES = $(patsubst config/examples/%, $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%, $(EXAMPLES_CONFIG_FILES))
TARGET_EXAMPLES_TMPFILESD_FILES = $(patsubst tmpfiles.d/examples/%, $(TARGET_CHROOT)/etc/tmpfiles.d/%, $(EXAMPLES_TMPFILESD_FILES)) TARGET_EXAMPLES_TMPFILESD_FILES = $(patsubst tmpfiles.d/examples/%, $(TARGET_CHROOT)/etc/tmpfiles.d/%, $(EXAMPLES_TMPFILESD_FILES))
TARGET_EXAMPLES_SYSCTLD_FILES = $(patsubst sysctl.d/examples/%, $(TARGET_CHROOT)/etc/sysctl.d/%, $(EXAMPLES_SYSCTLD_FILES)) TARGET_EXAMPLES_SYSCTLD_FILES = $(patsubst sysctl.d/examples/%, $(TARGET_CHROOT)/etc/sysctl.d/%, $(EXAMPLES_SYSCTLD_FILES))
TARGET_EXAMPLES_PROFILED_FILES = $(patsubst profile.d/examples/%, $(TARGET_CHROOT)/etc/profile.d/%, $(EXAMPLES_PROFILED_FILES))
# All configuration files to be installed # All configuration files to be installed
TARGET_FILES = $(addprefix $(TARGET_CHROOT)/etc/containers/systemd/, $(QUADLETS_FILES)) \ TARGET_FILES = $(addprefix $(TARGET_CHROOT)/etc/containers/systemd/, $(QUADLETS_FILES)) \
$(addprefix $(TARGET_CHROOT)/etc/systemd/system/, $(SYSTEMD_FILES)) \ $(addprefix $(TARGET_CHROOT)/etc/systemd/system/, $(SYSTEMD_FILES)) \
$(TARGET_CONFIG_FILES) $(TARGET_TMPFILESD_FILES) $(TARGET_SYSCTLD_FILES) $(TARGET_CONFIG_FILES) $(TARGET_TMPFILESD_FILES) $(TARGET_SYSCTLD_FILES) $(TARGET_PROFILED_FILES)
# All example configuration files to be installed # All example configuration files to be installed
TARGET_EXAMPLE_FILES = $(TARGET_EXAMPLES_CONFIG_FILES) $(TARGET_EXAMPLES_TMPFILESD_FILES) $(TARGET_EXAMPLES_SYSCTLD_FILES) TARGET_EXAMPLE_FILES = $(TARGET_EXAMPLES_CONFIG_FILES) $(TARGET_EXAMPLES_TMPFILESD_FILES) $(TARGET_EXAMPLES_SYSCTLD_FILES) $(TARGET_EXAMPLES_PROFILED_FILES)
# Dependencies on other projects # Dependencies on other projects
# List here the names of other projects (directories at the top-level) that this project depends on. # List here the names of other projects (directories at the top-level) that this project depends on.
@ -111,8 +115,12 @@ DEPENDENCIES_IGNITION_FILES := $(shell for dep in base $(DEPENDENCIES); do echo
PROJECT_UID ?= 0 PROJECT_UID ?= 0
PROJECT_GID ?= 0 PROJECT_GID ?= 0
# Function to reverse a list of words
# Usage: $(call reverse,word1 word2 word3)
reverse = $(let first rest,$1,$(if $(rest),$(call reverse,$(rest)) )$(first))
# Ensure that the Makefile is not run from the top-level directory and that it is run as root. # Ensure that the Makefile is not run from the top-level directory and that it is run as root.
pre-requisites: pre-requisites::
@if [ -z "$(TOP_LEVEL_DIR)" ]; then \ @if [ -z "$(TOP_LEVEL_DIR)" ]; then \
echo "Do not run this Makefile from the top-level directory!" >&2; \ echo "Do not run this Makefile from the top-level directory!" >&2; \
exit 1; \ exit 1; \
@ -155,11 +163,15 @@ $(TARGET_EXAMPLES_CONFIG_FILES): $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%
$(filter-out %.env, $(TARGET_CONFIG_FILES) $(TARGET_EXAMPLES_CONFIG_FILES)): $(filter-out %.env, $(TARGET_CONFIG_FILES) $(TARGET_EXAMPLES_CONFIG_FILES)):
@run() { echo $$*; "$$@"; }; \ @run() { echo $$*; "$$@"; }; \
set -Eeuo pipefail; \ set -Eeuo pipefail; \
if [ -x $< ]; then \ if [ -d $< ]; then \
run install -D -m 0755 -o $(PROJECT_UID) -g $(PROJECT_GID) $< $@; \ run install -d -m 0755 -o $(PROJECT_UID) -g $(PROJECT_GID) $@; \
else \ else \
run install -D -m 0644 -o $(PROJECT_UID) -g $(PROJECT_GID) $< $@; \ if [ -x $< ]; then \
fi run install -m 0755 -o $(PROJECT_UID) -g $(PROJECT_GID) $< $@; \
else \
run install -m 0644 -o $(PROJECT_UID) -g $(PROJECT_GID) $< $@; \
fi ; \
fi; \
# Handle .env files separately to set more restrictive permissions # Handle .env files separately to set more restrictive permissions
$(filter %.env, $(TARGET_CONFIG_FILES) $(TARGET_EXAMPLES_CONFIG_FILES)): $(filter %.env, $(TARGET_CONFIG_FILES) $(TARGET_EXAMPLES_CONFIG_FILES)):
@ -177,6 +189,12 @@ $(TARGET_EXAMPLES_SYSCTLD_FILES): $(TARGET_CHROOT)/etc/sysctl.d/%: sysctl.d/exam
$(TARGET_SYSCTLD_FILES) $(TARGET_EXAMPLES_SYSCTLD_FILES): $(TARGET_SYSCTLD_FILES) $(TARGET_EXAMPLES_SYSCTLD_FILES):
install -D -m 0644 -o root -g root $< $@ install -D -m 0644 -o root -g root $< $@
# Copy profile.d files
$(TARGET_PROFILED_FILES): $(TARGET_CHROOT)/etc/profile.d/%: profile.d/% $(TARGET_CHROOT)/etc/profile.d
$(TARGET_EXAMPLES_PROFILED_FILES): $(TARGET_CHROOT)/etc/profile.d/%: profile.d/examples/% $(TARGET_CHROOT)/etc/profile.d
$(TARGET_PROFILED_FILES) $(TARGET_EXAMPLES_PROFILED_FILES):
install -D -m 0644 -o root -g root $< $@
# Create the directory to store quadlet state and data. # Create the directory to store quadlet state and data.
$(TARGET_CHROOT)/var/lib/quadlets/$(PROJECT_NAME): $(TARGET_CHROOT)/var/lib/quadlets/$(PROJECT_NAME):
install -d -m 0755 -o $(PROJECT_UID) -g $(PROJECT_GID) $@ install -d -m 0755 -o $(PROJECT_UID) -g $(PROJECT_GID) $@
@ -204,6 +222,11 @@ install-files-pre::
# This target can be extended by Makefiles sourcing this one. # This target can be extended by Makefiles sourcing this one.
install-files-post:: install-files-post::
# Generated systemd units (quadlets) cannot be enabled.
# That's why we filter them out from the list of units to be enabled.
install-actions uninstall: ENABLE_UNITS = $(filter-out $(QUADLET_UNIT_NAMES),$(SYSTEMD_MAIN_UNIT_NAMES) $(SYSTEMD_TIMER_NAMES))
install-actions uninstall: START_UNITS = $(SYSTEMD_MAIN_UNIT_NAMES)
# Perform post-installation actions such as enabling and starting units. # Perform post-installation actions such as enabling and starting units.
install-actions: install-actions-pre install-actions: install-actions-pre
systemctl daemon-reload systemctl daemon-reload
@ -215,9 +238,13 @@ install-actions: install-actions-pre
fi; \ fi; \
if [ -f /etc/sysctl.d/$(PROJECT_NAME).conf ]; then \ if [ -f /etc/sysctl.d/$(PROJECT_NAME).conf ]; then \
run sysctl -q -p /etc/sysctl.d/$(PROJECT_NAME).conf; \ run sysctl -q -p /etc/sysctl.d/$(PROJECT_NAME).conf; \
fi ; \
if [ -n "$(ENABLE_UNITS)" ]; then \
run systemctl enable $(ENABLE_UNITS); \
fi ; \
if [ -n "$(START_UNITS)" ]; then \
run systemctl start $(START_UNITS); \
fi fi
systemctl enable $(SYSTEMD_MAIN_UNIT_NAMES) $(SYSTEMD_TIMER_NAMES)
systemctl start $(SYSTEMD_MAIN_UNIT_NAMES)
$(MAKE) install-actions-post $(MAKE) install-actions-post
# Custom commands to be run before performing post-installation actions. # Custom commands to be run before performing post-installation actions.
@ -248,15 +275,23 @@ install-pre::
install-post:: install-post::
# Uninstall all quadlets and systemd units installed by this project. # Uninstall all quadlets and systemd units installed by this project.
uninstall: FILES_TO_REMOVE := $(call reverse,$(TARGET_EXAMPLE_FILES) $(TARGET_FILES))
uninstall: pre-requisites uninstall-pre uninstall: pre-requisites uninstall-pre
systemctl disable $(SYSTEMD_MAIN_UNIT_NAMES) $(SYSTEMD_TIMER_NAMES) || true @run() { echo $$*; "$$@"; }; \
systemctl stop $(SYSTEMD_UNIT_NAMES) $(QUADLET_UNIT_NAMES) || true set -Eeuo pipefail; \
if [ -n "$(ENABLE_UNITS)" ]; then \
run systemctl disable $(ENABLE_UNITS) || true; \
fi ; \
if [ -n "$(START_UNITS)" ]; then \
run systemctl stop $(START_UNITS) || true; \
fi
@run() { echo $$*; "$$@"; }; \ @run() { echo $$*; "$$@"; }; \
set -Eeuo pipefail; \ set -Eeuo pipefail; \
if [ -f /etc/tmpfiles.d/$(PROJECT_NAME).conf ]; then \ if [ -f /etc/tmpfiles.d/$(PROJECT_NAME).conf ]; then \
run systemd-tmpfiles --purge /etc/tmpfiles.d/$(PROJECT_NAME).conf; \ run systemd-tmpfiles --purge /etc/tmpfiles.d/$(PROJECT_NAME).conf; \
fi fi
rm -f $(TARGET_FILES) $(TARGET_EXAMPLE_FILES) rm -df $(FILES_TO_REMOVE)
systemctl daemon-reload systemctl daemon-reload
$(MAKE) uninstall-post $(MAKE) uninstall-post

13
base/Makefile

@ -1,3 +1,14 @@
TOP_LEVEL_DIR := .. TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common include $(TOP_LEVEL_DIR)/Makefile.common
SYSTEMD_MAIN_UNIT_NAMES := var-lib-virtiofs-data.mount rpm-ostree-install-qemu-guest-agent.service SYSTEMD_MAIN_UNIT_NAMES += var-lib-virtiofs-data.mount
SYSTEMD_MAIN_UNIT_NAMES += rpm-ostree-install-qemu-guest-agent.service
SYSTEMD_MAIN_UNIT_NAMES += install-fastfetch.service
pre-requisites::
@set -Eeuo pipefail; \
for tool in rpm-ostree; do \
if ! which $$tool &>/dev/null ; then \
echo "$$tool is not installed. Please install it first." >&2; \
exit 1; \
fi ; \
done

1
base/config/examples/fastfetch.env

@ -0,0 +1 @@
FASTFETCH_VERSION="2.45.0"

110
base/config/fastfetch.jsonc

@ -0,0 +1,110 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"padding": {
"top": 2
}
},
"display": {
"showErrors": false,
"size": {
"ndigits": 0,
"maxPrefix": "GB"
},
"separator": "",
"color": {
"keys": "blue",
"title": "blue"
},
"key": {
"width": 36,
"type": "string"
},
"bar": {
"width": 16,
"charElapsed": "■",
"charTotal": "-"
},
"percent": {
"type": 3,
"color": {
"green": "green",
"yellow": "light_yellow",
"red": "light_red"
}
}
},
"modules": [
{
"type": "custom",
"key": " ------- Software ------- ",
"format": " "
},
"os",
"kernel",
"break",
{
"type": "custom",
"key": " ------- Hardware ------- ",
"format": " "
},
"host",
"cpu",
{
"type": "physicaldisk",
"key": "Disk {dev-path}",
"format": "{size>10} {serial}"
},
"break",
{
"type": "custom",
"key": " ---- Resource Usage ---- ",
"format": " "
},
{
"type": "memory",
"key": "Memory",
"format": "{percentage-bar} {percentage>4}"
},
{
"type": "disk",
"format": "{size-percentage-bar} {size-percentage>4}",
"key": "Vol. /",
"folders": "/sysroot",
"percent": {
"green": 75,
"yellow": 90
}
},
{
"type": "disk",
"format": "{size-percentage-bar} {size-percentage>4}",
"key": "Vol. {mountpoint}",
"folders": "/var:/var/lib/virtiofs/data",
"percent": {
"green": 75,
"yellow": 90
}
},
"break",
{
"type": "custom",
"key": " ------ Environment ------ ",
"format": " "
},
{
"type": "title",
"key": "User",
"format": "{user-name-colored}"
},
"uptime",
{
"type": "title",
"key": "Hostname",
"format": "{host-name}",
"fqdn": true
},
"localip",
"publicip"
]
}

12
base/config/install-fastfetch.sh

@ -0,0 +1,12 @@
#!/bin/bash
set -Eeuo pipefail
FASTFETCH_LATEST_VERSION="$(curl -sSfL https://api.github.com/repos/fastfetch-cli/fastfetch/releases | jq -r '.[] | select(.prerelease == false and .draft == false) | .tag_name' | sort -V | tail -1)"
FASTFETCH_VERSION="${FASTFETCH_VERSION:-$FASTFETCH_LATEST_VERSION}"
FASTFETCH_BIN="/usr/local/bin/fastfetch"
declare -A ARCH_MAP=( ["aarch64"]="aarch64" ["x86_64"]="amd64" )
if [ ! -f "$FASTFETCH_BIN" ]; then
arch="$(arch)"
arch=${ARCH_MAP[$arch]}
echo "Installing fastfetch $FASTFETCH_VERSION for $arch..."
curl -sSfL https://github.com/fastfetch-cli/fastfetch/releases/download/$FASTFETCH_VERSION/fastfetch-linux-$arch.tar.gz | tar -zx --strip-components=2 -C /usr/local --no-same-owner
fi

14
base/install-fastfetch.service

@ -0,0 +1,14 @@
[Unit]
Description=Install fastfetch
Wants=network-online.target
After=network-online.target
ConditionPathExists=!/usr/local/bin/fastfetch
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/quadlets/base/install-fastfetch.sh
EnvironmentFile=-/etc/quadlets/base/fastfetch.env
[Install]
WantedBy=multi-user.target

16
base/overlay.bu

@ -41,3 +41,19 @@ systemd:
contents: | contents: |
[Service] [Service]
ExecStartPost=/bin/bash -c 'if [ -f /var/lib/private/sshd/ssh_host_%i_key ]; then cp -Z /var/lib/private/sshd/ssh_host_%i_key{,.pub} /etc/ssh/; elif [ -f /etc/ssh/ssh_host_%i_key ]; then cp -a /etc/ssh/ssh_host_%i_key{,.pub} /var/lib/private/sshd/; fi' ExecStartPost=/bin/bash -c 'if [ -f /var/lib/private/sshd/ssh_host_%i_key ]; then cp -Z /var/lib/private/sshd/ssh_host_%i_key{,.pub} /etc/ssh/; elif [ -f /etc/ssh/ssh_host_%i_key ]; then cp -a /etc/ssh/ssh_host_%i_key{,.pub} /var/lib/private/sshd/; fi'
passwd:
users:
- name: core
should_exist: false
- name: itix-svc
uid: 10000
gecos: ITIX Misc. Services
home_dir: /tmp
primary_group: itix-svc
groups:
- name: core
should_exist: false
- name: itix
gid: 1000
- name: itix-svc
gid: 10000

9
base/profile.d/fastfetch.sh

@ -0,0 +1,9 @@
#!/bin/sh
declare -a FASTFETCH_OPTIONS=( -c /etc/quadlets/base/fastfetch.jsonc )
if [ "$USER" == "root" ]; then
FASTFETCH_OPTIONS+=( --custom-key-color dim_red --color-keys red --title-color-user red )
else
FASTFETCH_OPTIONS+=( --custom-key-color dim_blue --color-keys blue --title-color-user green )
fi
fastfetch "${FASTFETCH_OPTIONS[@]}"
unset FASTFETCH_OPTIONS

1
butane.blocklist

@ -9,3 +9,4 @@
/etc/containers/systemd /etc/containers/systemd
/etc/tmpfiles.d /etc/tmpfiles.d
/etc/sysctl.d /etc/sysctl.d
/etc/profile.d

13
lego/Makefile

@ -0,0 +1,13 @@
##
## Makefile for Lego quadlet
##
# Lego quadlet is mapped to the 10023 user (lego) and 10000 group (itix-svc)
PROJECT_UID = 10023
PROJECT_GID = 10000
# Include common Makefile
TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common

3
lego/config/examples/config.env

@ -0,0 +1,3 @@
LEGO_GLOBAL_ARGS=-a -m nicolas.masse@itix.fr -d changeme.example.tld --http
LEGO_RUN_ARGS=
LEGO_RENEW_ARGS=--days 30 --renew-hook=/etc/lego/hooks/flag-as-renewed.sh

3
lego/config/hooks/flag-as-renewed.sh

@ -0,0 +1,3 @@
#!/bin/sh
set -Eeuo pipefail
touch ${LEGO_CERT_PATH%.*}.renewed

52
lego/lego-renew.container

@ -0,0 +1,52 @@
[Unit]
Description=Lego Let's Encrypt client - Renew a certificate
Documentation=https://go-acme.github.io/lego/
# Only start if there are certificates to renew
ConditionPathExistsGlob=/var/lib/quadlets/lego/certificates/*.crt
# and if Lego has been configured !
ConditionPathExists=/etc/quadlets/lego/config.env
[Container]
ContainerName=lego-renew
# No need for root privileges
User=10023
Group=10000
# Image
Image=docker.io/goacme/lego:latest
AutoUpdate=registry
# Network configuration
Network=host
# Environment variables from config
EnvironmentFile=/etc/quadlets/lego/config.env
# Volume mounts
Volume=/var/lib/quadlets/lego:/.lego:z
Volume=/etc/quadlets/lego/hooks:/etc/lego/hooks:ro
# Be safe, set the umask to 0077 so that private keys are not world-readable
PodmanArgs=--umask=0077
# Command to run
Exec=$LEGO_GLOBAL_ARGS renew $LEGO_RENEW_ARGS
[Service]
# If the command fails, don't try to restart it.
# Otherwise, we would hammer the Let's Encrypt servers and possibly get banned.
Restart=no
# Getting a certificate may take some time
TimeoutStartSec=600
# This container is a job - run once to completion
Type=oneshot
# These environment variables are sourced to be used by systemd in the Exec* commands
EnvironmentFile=/etc/quadlets/lego/config.env
[Install]
WantedBy=lego.target

12
lego/lego-renew.timer

@ -0,0 +1,12 @@
[Unit]
Description=Lego Let's Encrypt client - Renew a certificate
Documentation=https://go-acme.github.io/lego/
PartOf=lego.target
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=lego.target

52
lego/lego-run.container

@ -0,0 +1,52 @@
[Unit]
Description=Lego Let's Encrypt client - Fetch a certificate
Documentation=https://go-acme.github.io/lego/
PartOf=lego.target
# Only start if no certificates exist yet
ConditionPathExistsGlob=!/var/lib/quadlets/lego/certificates/*.crt
# and if Lego has been configured !
ConditionPathExists=/etc/quadlets/lego/config.env
[Container]
ContainerName=lego-run
# No need for root privileges
User=10023
Group=10000
# Image
Image=docker.io/goacme/lego:latest
AutoUpdate=registry
# Network configuration
Network=host
# Environment variables from config
EnvironmentFile=/etc/quadlets/lego/config.env
# Volume mounts
Volume=/var/lib/quadlets/lego:/.lego:z
# Be safe, set the umask to 0077 so that private keys are not world-readable
PodmanArgs=--umask=0077
# Command to run
Exec=$LEGO_GLOBAL_ARGS run $LEGO_RUN_ARGS
[Service]
# If the command fails, don't try to restart it.
# Otherwise, we would hammer the Let's Encrypt servers and possibly get banned.
Restart=no
# Getting a certificate may take some time
TimeoutStartSec=600
# This container is a job - run once to completion
Type=oneshot
# These environment variables are sourced to be used by systemd in the Exec* commands
EnvironmentFile=/etc/quadlets/lego/config.env
[Install]
WantedBy=lego.target

12
lego/lego.target

@ -0,0 +1,12 @@
[Unit]
Description=Lego Let's Encrypt client
Documentation=https://go-acme.github.io/lego/
Requires=lego-run.service lego-renew.timer
After=lego-run.service lego-renew.timer
# Allow isolation - can stop/start this target independently
AllowIsolate=yes
[Install]
# Start by default on boot
WantedBy=multi-user.target default.target

9
lego/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: lego
uid: 10023
gecos: Lego Let's Encrypt client
home_dir: /var/lib/quadlets/lego
primary_group: itix-svc

10
nextcloud/Makefile

@ -2,7 +2,7 @@
## Makefile for PostgreSQL quadlet ## Makefile for PostgreSQL quadlet
## ##
DEPENDENCIES = postgresql DEPENDENCIES = postgresql traefik
# Nextcloud quadlet is mapped to the 10008 user (nextcloud) and 10000 group (itix-svc) # Nextcloud quadlet is mapped to the 10008 user (nextcloud) and 10000 group (itix-svc)
PROJECT_UID = 10008 PROJECT_UID = 10008
@ -32,9 +32,13 @@ $(TARGET_CHROOT)/etc/quadlets/nextcloud/collabora-seccomp-profile.json:
install-config: $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/redis $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/data $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/config $(TARGET_CHROOT)/etc/quadlets/nextcloud/collabora-seccomp-profile.json install-config: $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/redis $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/data $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/config $(TARGET_CHROOT)/etc/quadlets/nextcloud/collabora-seccomp-profile.json
install-examples: $(TARGET_CHROOT)/etc/quadlets/postgresql/init.d/nextcloud.sql install-examples: $(TARGET_CHROOT)/etc/quadlets/postgresql/init.d/nextcloud.sql $(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/nextcloud.yaml $(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/collabora.yaml
$(TARGET_CHROOT)/etc/quadlets/postgresql/init.d/nextcloud.sql: other/nextcloud.sql $(TARGET_CHROOT)/etc/quadlets/postgresql/init.d/nextcloud.sql: other/nextcloud.sql
install -m 0644 -o 10004 -g 10000 $< $@ install -m 0600 -o 10004 -g 10000 $< $@
$(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/nextcloud.yaml $(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/collabora.yaml: $(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/%.yaml: other/traefik-%.yaml
install -m 0644 -o 10001 -g 10000 $< $@
test: test:
@run() { echo $$*; "$$@"; }; \ @run() { echo $$*; "$$@"; }; \

4
nextcloud/config/examples/collabora.env

@ -16,7 +16,7 @@ dictionaries=fr_FR en_US en_GB
# When this environment variable is set (is not “”), then its value will be used # When this environment variable is set (is not “”), then its value will be used
# as server name in /etc/coolwsd/coolwsd.xml. Without this, CODE is not delivering # as server name in /etc/coolwsd/coolwsd.xml. Without this, CODE is not delivering
# a correct host for the websocket connection in case of a proxy in front of it. # a correct host for the websocket connection in case of a proxy in front of it.
server_name=localhost server_name=collabora
# You can pass extra command line parameters to coolwsd via this environment # You can pass extra command line parameters to coolwsd via this environment
# variable. For example, if you want to start coolwsd without SSL, when you # variable. For example, if you want to start coolwsd without SSL, when you
@ -27,7 +27,7 @@ extra_params=--o:ssl.enable=false --o:ssl.termination=false
# By default Collabora Online enables the first WOPI host that tries to connect. # By default Collabora Online enables the first WOPI host that tries to connect.
# You can define the allowed WOPI hosts by passing environment variables. # You can define the allowed WOPI hosts by passing environment variables.
aliasgroup1=http://localhost:9980 aliasgroup1=http://collabora
# When this environment variable is set (is not “”), then startup script will # When this environment variable is set (is not “”), then startup script will
# not generate a new SSL certificate signed by a dummy CA. It is useful, if # not generate a new SSL certificate signed by a dummy CA. It is useful, if

7
nextcloud/config/examples/config.env

@ -8,10 +8,11 @@ REDIS_MAJOR=8
NGINX_MAJOR=1.20 NGINX_MAJOR=1.20
# Nextcloud domain configuration # Nextcloud domain configuration
NEXTCLOUD_TRUSTED_DOMAINS=localhost NEXTCLOUD_TRUSTED_DOMAINS=nextcloud localhost
OVERWRITEHOST=localhost OVERWRITEHOST=nextcloud
OVERWRITEPROTOCOL=http OVERWRITEPROTOCOL=http
OVERWRITECLIURL=http://localhost OVERWRITECLIURL=http://localhost:8080
TRUSTED_PROXIES=127.0.0.1
# Nextcloud admin credentials # Nextcloud admin credentials
NEXTCLOUD_ADMIN_USER=admin NEXTCLOUD_ADMIN_USER=admin

19
nextcloud/config/nginx.conf

@ -19,6 +19,11 @@ http {
include /etc/nginx/mime.types; include /etc/nginx/mime.types;
default_type application/octet-stream; default_type application/octet-stream;
types {
# Add missing types for Nextcloud
application/javascript js mjs;
}
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" ' '$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; '"$http_user_agent" "$http_x_forwarded_for"';
@ -56,13 +61,13 @@ http {
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
# HTTP response headers borrowed from Nextcloud `.htaccess` # HTTP response headers borrowed from Nextcloud `.htaccess`
add_header Referrer-Policy "no-referrer" always; add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always; add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always; add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always; add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always; add_header X-Robots-Tag "noindex,nofollow" always;
add_header X-XSS-Protection "1; mode=block" always; add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak # Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By; fastcgi_hide_header X-Powered-By;

4
nextcloud/nextcloud-app.container

@ -30,6 +30,10 @@ GIDMap=+82:10000:1
Network=host Network=host
AddCapability=CAP_NET_BIND_SERVICE AddCapability=CAP_NET_BIND_SERVICE
# Allow Nextcloud to talk to itself through the same hostname as used by clients
AddHost=nextcloud:127.0.0.1
AddHost=collabora:127.0.0.1
# Environment variables from secrets and config # Environment variables from secrets and config
EnvironmentFile=/etc/quadlets/nextcloud/config.env EnvironmentFile=/etc/quadlets/nextcloud/config.env

4
nextcloud/nextcloud-collabora.container

@ -29,6 +29,10 @@ SeccompProfile=/etc/quadlets/nextcloud/collabora-seccomp-profile.json
# Network configuration # Network configuration
Network=host Network=host
# Collabora needs to connect to Nextcloud through the same hostname as used by clients
AddHost=nextcloud:127.0.0.1
AddHost=collabora:127.0.0.1
# Environment variables from secrets and config # Environment variables from secrets and config
EnvironmentFile=/etc/quadlets/nextcloud/collabora.env EnvironmentFile=/etc/quadlets/nextcloud/collabora.env

4
nextcloud/nextcloud-cron.container

@ -26,6 +26,10 @@ GIDMap=+82:10000:1
# Network configuration # Network configuration
Network=host Network=host
# Allow Nextcloud to talk to itself through the same hostname as used by clients
AddHost=nextcloud:127.0.0.1
AddHost=collabora:127.0.0.1
# Environment variables from config # Environment variables from config
EnvironmentFile=/etc/quadlets/nextcloud/config.env EnvironmentFile=/etc/quadlets/nextcloud/config.env

2
nextcloud/nextcloud-cron.timer

@ -4,7 +4,7 @@ Documentation=https://hub.docker.com/_/nextcloud/
PartOf=nextcloud.target PartOf=nextcloud.target
[Timer] [Timer]
OnActiveSec=15min OnActiveSec=5min
RandomizedDelaySec=15s RandomizedDelaySec=15s
DeferReactivation=true DeferReactivation=true

13
nextcloud/other/traefik-collabora.yaml

@ -0,0 +1,13 @@
http:
routers:
collabora:
rule: "Host(`collabora`)"
entryPoints:
- http
middlewares:
service: "collabora"
services:
collabora:
loadBalancer:
servers:
- url: "http://127.0.0.1:9980"

13
nextcloud/other/traefik-nextcloud.yaml

@ -0,0 +1,13 @@
http:
routers:
nextcloud:
rule: "Host(`nextcloud`)"
entryPoints:
- http
middlewares:
service: "nextcloud"
services:
nextcloud:
loadBalancer:
servers:
- url: "http://127.0.0.1:8080"

9
nextcloud/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: nextcloud
uid: 10008
gecos: Nextcloud
home_dir: /var/lib/quadlets/nextcloud
primary_group: itix-svc

1
nginx/nginx-server.container

@ -15,6 +15,7 @@ PartOf=nginx.target
[Container] [Container]
ContainerName=nginx-server ContainerName=nginx-server
Image=docker.io/library/nginx:mainline-alpine Image=docker.io/library/nginx:mainline-alpine
AutoUpdate=registry
# Network configuration # Network configuration
Network=host Network=host

9
postgresql/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: postgresql
uid: 10004
gecos: PostgreSQL
home_dir: /var/lib/quadlets/postgresql
primary_group: itix-svc

1
postgresql/postgresql-server.container

@ -18,6 +18,7 @@ PartOf=postgresql.target
[Container] [Container]
ContainerName=postgresql-server ContainerName=postgresql-server
Image=docker.io/library/postgres:${PG_MAJOR}-alpine Image=docker.io/library/postgres:${PG_MAJOR}-alpine
AutoUpdate=registry
# Network configuration # Network configuration
Network=host Network=host

6
qemu-user-static/Makefile

@ -1,8 +1,2 @@
TOP_LEVEL_DIR := .. TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common include $(TOP_LEVEL_DIR)/Makefile.common
.PHONY: test
test: uninstall clean install
@echo "Running $(PROJECT_NAME) tests..."
curl -sSfL -I http://localhost/

0
qemu-user-static/config/Containerfile → qemu-user-static/config/container/Containerfile

0
qemu-user-static/config/container-entrypoint → qemu-user-static/config/container/container-entrypoint

4
qemu-user-static/qemu-user-static.build

@ -5,6 +5,6 @@ Wants=network-online.target
After=network-online.target After=network-online.target
[Build] [Build]
File=/etc/quadlets/qemu-user-static/Containerfile File=/etc/quadlets/qemu-user-static/container/Containerfile
ImageTag=localhost/qemu-user-static:latest ImageTag=localhost/qemu-user-static:latest
SetWorkingDirectory=/etc/quadlets/qemu-user-static SetWorkingDirectory=/etc/quadlets/qemu-user-static/container

22
restic-server/Makefile

@ -0,0 +1,22 @@
##
## Makefile for Restic REST Server quadlet
##
DEPENDENCIES = traefik
# Restic REST Server quadlet is mapped to the 10022 user (restic) and 10000 group (itix-svc)
PROJECT_UID = 10022
PROJECT_GID = 10000
TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common
SYSTEMD_MAIN_UNIT_NAMES += restic-server.service
TARGET_TRAEFIK_FILES = $(patsubst other/traefik/%, $(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/%, $(wildcard other/traefik/*))
install-examples: $(TARGET_TRAEFIK_FILES)
$(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/%: other/traefik/%
install -m 0644 -o 10001 -g 10000 $< $@

23
restic-server/other/traefik/restic.yaml

@ -0,0 +1,23 @@
http:
middlewares:
ip_from_internal_network:
IPAllowList:
sourceRange:
- "127.0.0.1/32"
- "192.168.0.0/16"
routers:
restic:
rule: "Host(`restic`)"
entryPoints:
- http
#- https
middlewares:
- ip_from_internal_network
service: restic
#tls:
# certResolver: le
services:
restic:
loadBalancer:
servers:
- url: "http://localhost:8080"

9
restic-server/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: restic
uid: 10022
gecos: Restic
home_dir: /var/lib/quadlets/restic
primary_group: itix-svc

31
restic-server/restic-server.container

@ -0,0 +1,31 @@
[Unit]
Description=Restic REST Server
After=local-fs.target network-online.target
Wants=network-online.target
RequiresMountsFor=/var/lib/virtiofs/data /var
[Container]
ContainerName=restic
# Image
Image=docker.io/restic/rest-server:latest
AutoUpdate=registry
# Security
User=10022
Group=10000
# Storage
Volume=/var/lib/virtiofs/data/restic-server:/data:z
Volume=/var/lib/quadlets/restic-server/log:/var/log/restic:z
# Network
AddCapability=CAP_NET_BIND_SERVICE
Network=host
# Configuration
Environment=OPTIONS="--append-only --listen 127.0.0.1:8080 --log /var/log/restic/rest-server.log --private-repos --prometheus --prometheus-no-auth"
[Install]
# Start by default on boot
WantedBy=multi-user.target

2
restic-server/tmpfiles.d/restic-server.conf

@ -0,0 +1,2 @@
d$ /var/lib/virtiofs/data/restic-server 0700 10022 10000 -
d$ /var/lib/quadlets/restic-server/log 0755 10022 10000 -

5
samba/Makefile

@ -0,0 +1,5 @@
TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common
$(TARGET_CHROOT)/etc/quadlets/samba/smb.conf.d:
install -d -m 0700 -o $(PROJECT_UID) -g $(PROJECT_GID) -D $< $@

15
samba/config/container/Containerfile

@ -0,0 +1,15 @@
FROM quay.io/centos/centos:stream10
# Install Samba
RUN dnf install -y samba samba-client cifs-utils shadow-utils procps-ng \
&& dnf clean all
# /data holds the samba shares, /run/samba is for temporary files (non-persistent)
VOLUME /data /run
# We only run smb (no nmb)
EXPOSE 445
ADD container-entrypoint /
ENTRYPOINT [ "/container-entrypoint" ]
CMD [ ]

10
samba/config/container/container-entrypoint

@ -0,0 +1,10 @@
#!/bin/bash
set -Eeuo pipefail
echo -n > /etc/samba/smb.conf
for file in /etc/samba/smb.conf.d/*.conf; do
echo "Using config file from $file..."
cat $file >> /etc/samba/smb.conf
echo >> /etc/samba/smb.conf
done
mkdir -p /var/lib/samba/lock /var/lib/samba/private /run/samba
exec /usr/sbin/smbd --foreground --no-process-group --debug-stdout "$@"

19
samba/config/examples/smb.conf.d/10-shares.conf

@ -0,0 +1,19 @@
server string = Storage
[foo]
path = /data/foo
comment = Foo
valid users = @itix
write list = @itix
group = itix
directory mask = 0770
create mask = 0660
[bar]
path = /data/bar
comment = Bar
valid users = @itix
write list = @itix
group = itix
directory mask = 0775
create mask = 0664

8
samba/config/smb.conf.d/00-global.conf

@ -0,0 +1,8 @@
[global]
workgroup = ITIX
passdb backend = tdbsam:/var/lib/samba/private/sam.tdb
map to guest = Bad User
load printers = no
private dir = /var/lib/samba/private
disable netbios = yes
debug syslog format = always

10
samba/samba-build.timer

@ -0,0 +1,10 @@
[Unit]
Description=Rebuild the samba container image
PartOf=samba.target
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=samba.target

9
samba/samba.build

@ -0,0 +1,9 @@
[Unit]
Description=Build of the Samba daemon
Wants=network-online.target
After=network-online.target
[Build]
File=/etc/quadlets/samba/container/Containerfile
ImageTag=localhost/samba:latest
SetWorkingDirectory=/etc/quadlets/samba/container

39
samba/samba.container

@ -0,0 +1,39 @@
[Unit]
Description=Samba
After=samba-build.service
Wants=samba-build.service
Requires=var-lib-virtiofs-data.mount
# Start/stop this unit when the target is started/stopped
PartOf=samba.target
# Start Samba only if at least one share configuration file exists
ConditionPathExistsGlob=/etc/quadlets/samba/smb.conf.d/*shares.conf
[Container]
ContainerName=samba
# Image
Image=localhost/samba:latest
AutoUpdate=local
# Security
User=0
# Storage
Volume=/var/lib/quadlets/samba/data:/var/lib/samba:Z
Volume=/var/lib/quadlets/samba/log:/var/log/samba:Z
Volume=/var/lib/virtiofs/data/storage:/data
Volume=/etc/quadlets/samba/smb.conf.d:/etc/samba/smb.conf.d:Z
Volume=/run/quadlets/samba/passwd:/etc/passwd:Z
Volume=/run/quadlets/samba/group:/etc/group:Z
Volume=/run/quadlets/samba/shadow:/etc/shadow:Z
# Network
Network=host
# Samba debug level
Exec=--debuglevel=1
[Install]
WantedBy=samba.target

14
samba/samba.target

@ -0,0 +1,14 @@
[Unit]
Description=Samba Service Target
Documentation=man:systemd.target(5)
Requires=samba.service
After=samba.service
# Allow isolation - can stop/start this target independently
AllowIsolate=yes
# Start Samba only if at least one share configuration file exists
ConditionPathExistsGlob=/etc/quadlets/samba/smb.conf.d/*shares.conf
[Install]
WantedBy=multi-user.target

8
samba/tmpfiles.d/samba.conf

@ -0,0 +1,8 @@
d$ /var/lib/quadlets/samba/data 0755 0 0 -
d$ /var/lib/quadlets/samba/log 0755 0 0 -
d$ /var/lib/quadlets/samba/cache 0755 0 0 -
d$ /var/lib/virtiofs/data/storage 0755 0 0 -
d$ /run/quadlets/samba 0700 0 0 -
C$ /run/quadlets/samba/passwd - - - - /etc/passwd
C$ /run/quadlets/samba/group - - - - /etc/group
C$ /run/quadlets/samba/shadow - - - - /etc/shadow

24
seedbox/Makefile

@ -0,0 +1,24 @@
##
## Makefile for Seedbox quadlet
##
DEPENDENCIES = traefik
# Seedbox quadlet is mapped to the 10017 user (seedbox) and 10000 group (itix-svc)
PROJECT_UID = 10017
PROJECT_GID = 10000
TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common
TARGET_TRAEFIK_FILES = $(patsubst other/traefik/%, $(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/%, $(wildcard other/traefik/*))
TARGET_SAMBA_FILES = $(patsubst other/samba/%, $(TARGET_CHROOT)/etc/quadlets/samba/smb.conf.d/%, $(wildcard other/samba/*))
install-examples: $(TARGET_TRAEFIK_FILES) $(TARGET_SAMBA_FILES)
$(TARGET_CHROOT)/etc/quadlets/samba/smb.conf.d/%: other/samba/%
install -m 0644 -o root -g root $< $@
$(TARGET_CHROOT)/etc/quadlets/traefik/conf.d/%: other/traefik/%
install -m 0644 -o 10001 -g 10000 $< $@

27
seedbox/flaresolverr.container

@ -0,0 +1,27 @@
[Unit]
Description=Proxy server to bypass Cloudflare protection
Documentation=https://github.com/FlareSolverr/FlareSolverr/
Wants=network-online.target
After=network-online.target
[Container]
ContainerName=flaresolverr
# Image
Image=ghcr.io/flaresolverr/flaresolverr:latest
AutoUpdate=registry
# Security
# <by default it runs as "flaresolverr">
# Storage
# <no storage>
# Network
Network=host
# Configuration
Environment=LOG_LEVEL=debug TZ=Europe/Paris HOST=127.0.0.1 PROMETHEUS_ENABLED=true PROMETHEUS_PORT=8192 LANG=fr_FR
[Install]
WantedBy=seedbox.target

34
seedbox/jellyfin.container

@ -0,0 +1,34 @@
[Unit]
Description= The Free Software Media System
Documentation=https://docs.linuxserver.io/images/docker-jellyfin/
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/lib/virtiofs/data
ConditionPathIsMountPoint=/var/lib/virtiofs/data
[Container]
ContainerName=jellyfin
# Image
Image=lscr.io/linuxserver/jellyfin:latest
AutoUpdate=registry
# Security
User=10017
Group=10000
# Storage
Volume=/var/lib/virtiofs/data/jellyfin/config:/config:z
Volume=/var/lib/virtiofs/data/storage/media:/data:z
# Network
AddCapability=CAP_NET_BIND_SERVICE
Network=host
# Configuration
Environment=PUID=10017 PGID=10000 JELLYFIN_DATA_DIR=/config/data JELLYFIN_CONFIG_DIR=/config JELLYFIN_LOG_DIR=/config/log JELLYFIN_CACHE_DIR=/config/cache JELLYFIN_WEB_DIR=/usr/share/jellyfin/web TZ=Etc/UTC
Entrypoint=/usr/bin/jellyfin
Exec=--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg
[Install]
WantedBy=seedbox.target

35
seedbox/lidarr.container

@ -0,0 +1,35 @@
[Unit]
Description=Smart PVR for newsgroup and bittorrent users.
Documentation=https://docs.linuxserver.io/images/docker-lidarr/
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/lib/virtiofs/data
ConditionPathIsMountPoint=/var/lib/virtiofs/data
[Container]
ContainerName=lidarr
# Image
Image=lscr.io/linuxserver/lidarr:latest
AutoUpdate=registry
# Security
User=10017
Group=10000
# Storage
Volume=/var/lib/virtiofs/data/lidarr/config:/config:z
Volume=/var/lib/virtiofs/data/storage:/data:z
# Network
AddCapability=CAP_NET_BIND_SERVICE
Network=host
# Configuration
Environment=PUID=10017 PGID=10000 TZ=Etc/UTC HOME=/config TMPDIR=/config/tmp
Entrypoint=/app/lidarr/bin/Lidarr
Exec=-nobrowser -data=/config
WorkingDir=/app/lidarr/bin
[Install]
WantedBy=seedbox.target

28
seedbox/other/samba/10-shares.conf

@ -0,0 +1,28 @@
server string = Seedbox
[media]
path = /data/storage/media
comment = Media
valid users = @itix
write list = @itix
group = itix
directory mask = 0775
create mask = 0664
[downloads]
path = /data/storage/downloads
comment = Downloads
valid users = @itix
write list = @itix
group = itix
directory mask = 0775
create mask = 0664
[import]
path = /data/storage/import
comment = Imports
valid users = @itix
write list = @itix
group = itix
directory mask = 0775
create mask = 0664

16
seedbox/other/traefik/jellyfin.yaml

@ -0,0 +1,16 @@
http:
routers:
jellyfin:
rule: "Host(`jellyfin`)"
entryPoints:
#- https
- http
middlewares:
service: "jellyfin"
#tls:
# certResolver: le
services:
jellyfin:
loadBalancer:
servers:
- url: "http://127.0.0.1:8096"

16
seedbox/other/traefik/lidarr.yaml

@ -0,0 +1,16 @@
http:
routers:
lidarr:
rule: "Host(`lidarr`)"
entryPoints:
#- https
- http
middlewares:
service: "lidarr"
#tls:
# certResolver: le
services:
lidarr:
loadBalancer:
servers:
- url: "http://127.0.0.1:8686"

16
seedbox/other/traefik/prowlarr.yaml

@ -0,0 +1,16 @@
http:
routers:
prowlarr:
rule: "Host(`prowlarr`)"
entryPoints:
#- https
- http
middlewares:
service: "prowlarr"
#tls:
# certResolver: le
services:
prowlarr:
loadBalancer:
servers:
- url: "http://127.0.0.1:9696"

16
seedbox/other/traefik/qbittorrent.yaml

@ -0,0 +1,16 @@
http:
routers:
qbittorrent-webui:
rule: "Host(`qbittorrent`)"
entryPoints:
#- https
- http
middlewares:
service: "qbittorrent-webui"
#tls:
# certResolver: le
services:
qbittorrent-webui:
loadBalancer:
servers:
- url: "http://127.0.0.1:8080"

16
seedbox/other/traefik/radarr.yaml

@ -0,0 +1,16 @@
http:
routers:
radarr:
rule: "Host(`radarr`)"
entryPoints:
#- https
- http
middlewares:
service: "radarr"
#tls:
# certResolver: le
services:
radarr:
loadBalancer:
servers:
- url: "http://127.0.0.1:7878"

16
seedbox/other/traefik/sonarr.yaml

@ -0,0 +1,16 @@
http:
routers:
sonarr:
rule: "Host(`sonarr`)"
entryPoints:
#- https
- http
middlewares:
service: "sonarr"
#tls:
# certResolver: le
services:
sonarr:
loadBalancer:
servers:
- url: "http://127.0.0.1:8989"

9
seedbox/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: seedbox
uid: 10017
gecos: seedbox
home_dir: /var/lib/quadlets/seedbox
primary_group: itix-svc

35
seedbox/prowlarr.container

@ -0,0 +1,35 @@
[Unit]
Description=Prowlarr is an indexer manager/proxy built on the popular *arr .net/reactjs base stack to integrate with your various PVR apps.
Documentation=https://docs.linuxserver.io/images/docker-prowlarr/
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/lib/virtiofs/data
ConditionPathIsMountPoint=/var/lib/virtiofs/data
[Container]
ContainerName=prowlarr
# Image
Image=lscr.io/linuxserver/prowlarr:latest
AutoUpdate=registry
# Security
User=10017
Group=10000
# Storage
Volume=/var/lib/virtiofs/data/prowlarr/config:/config:z
Volume=/var/lib/virtiofs/data/storage:/data:z
# Network
AddCapability=CAP_NET_BIND_SERVICE
Network=host
# Configuration
Environment=PUID=10017 PGID=10000 TZ=Etc/UTC HOME=/config TMPDIR=/config/tmp
Entrypoint=/app/prowlarr/bin/Prowlarr
Exec=-nobrowser -data=/config
WorkingDir=/app/prowlarr/bin
[Install]
WantedBy=seedbox.target

36
seedbox/qbittorrent.container

@ -0,0 +1,36 @@
[Unit]
Description=qBittorrent client
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/lib/virtiofs/data
ConditionPathIsMountPoint=/var/lib/virtiofs/data
[Container]
ContainerName=qbittorrent
# Image
Image=lscr.io/linuxserver/qbittorrent:latest
AutoUpdate=registry
# Security
User=10017
Group=10000
# Storage
Volume=/var/lib/virtiofs/data/qbittorrent/config:/config:z
Volume=/var/lib/virtiofs/data/storage:/data:z
# This volume is required for torrents migrated from the old seedbox
Volume=/var/lib/virtiofs/data/storage/downloads:/downloads:z
# Network
AddCapability=CAP_NET_BIND_SERVICE
Network=host
# Configuration
Environment=PUID=10017 PGID=10000 TZ=Etc/UTC WEBUI_PORT=8080
Entrypoint=/usr/bin/qbittorrent-nox
Exec=--webui-port=8080
[Install]
WantedBy=seedbox.target

35
seedbox/radarr.container

@ -0,0 +1,35 @@
[Unit]
Description=Radarr is a movie collection manager for Usenet and BitTorrent users.
Documentation=https://docs.linuxserver.io/images/docker-radarr/
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/lib/virtiofs/data
ConditionPathIsMountPoint=/var/lib/virtiofs/data
[Container]
ContainerName=radarr
# Image
Image=lscr.io/linuxserver/radarr:latest
AutoUpdate=registry
# Security
User=10017
Group=10000
# Storage
Volume=/var/lib/virtiofs/data/radarr/config:/config:z
Volume=/var/lib/virtiofs/data/storage:/data:z
# Network
AddCapability=CAP_NET_BIND_SERVICE
Network=host
# Configuration
Environment=PUID=10017 PGID=10000 TZ=Etc/UTC HOME=/config TMPDIR=/config/tmp
Entrypoint=/app/radarr/bin/Radarr
Exec=-nobrowser -data=/config
WorkingDir=/app/radarr/bin
[Install]
WantedBy=seedbox.target

11
seedbox/seedbox.target

@ -0,0 +1,11 @@
[Unit]
Description=Seedbox Service Target
Documentation=man:systemd.target(5)
Requires=radarr.service sonarr.service lidarr.service prowlarr.service qbittorrent.service jellyfin.service flaresolverr.service
After=radarr.service sonarr.service lidarr.service prowlarr.service qbittorrent.service jellyfin.service flaresolverr.service
# Allow isolation - can stop/start this target independently
AllowIsolate=yes
[Install]
WantedBy=multi-user.target

36
seedbox/sonarr.container

@ -0,0 +1,36 @@
[Unit]
Description=Smart PVR for newsgroup and bittorrent users.
Documentation=https://docs.linuxserver.io/images/docker-sonarr/
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/lib/virtiofs/data
ConditionPathIsMountPoint=/var/lib/virtiofs/data
[Container]
ContainerName=sonarr
# Image
Image=lscr.io/linuxserver/sonarr:latest
AutoUpdate=registry
# Security
User=10017
Group=10000
# Storage
Volume=/var/lib/virtiofs/data/sonarr/config:/config:z
Volume=/var/lib/virtiofs/data/storage:/data:z
# Network
AddCapability=CAP_NET_BIND_SERVICE
Network=host
# Configuration
Environment=PUID=10017 PGID=10000 TZ=Etc/UTC HOME=/config TMPDIR=/config/tmp
Entrypoint=/app/sonarr/bin/Sonarr
Exec=-nobrowser -data=/config
WorkingDir=/app/sonarr/bin
[Install]
WantedBy=seedbox.target

1
seedbox/sysctl.d/seedbox.conf

@ -0,0 +1 @@
fs.inotify.max_user_instances=8192

22
seedbox/tmpfiles.d/seedbox.conf

@ -0,0 +1,22 @@
d$ /var/lib/virtiofs/data/storage 0755 0 0 -
d$ /var/lib/virtiofs/data/storage/media 0775 10017 10000 -
d$ /var/lib/virtiofs/data/storage/media/movies 0775 10017 10000 -
d$ /var/lib/virtiofs/data/storage/media/series 0775 10017 10000 -
d$ /var/lib/virtiofs/data/storage/media/music 0775 10017 10000 -
d$ /var/lib/virtiofs/data/storage/downloads 0775 10017 10000 -
d$ /var/lib/virtiofs/data/storage/torrents 0775 10017 10000 -
d$ /var/lib/virtiofs/data/storage/import 0775 10017 10000 -
d$ /var/lib/virtiofs/data/radarr 0700 10017 10000 -
d$ /var/lib/virtiofs/data/radarr/config 0700 10017 10000 -
d$ /var/lib/virtiofs/data/radarr/config/tmp 0700 10017 10000 -
d$ /var/lib/virtiofs/data/radarr/config/xdg 0700 10017 10000 -
d$ /var/lib/virtiofs/data/sonarr 0700 10017 10000 -
d$ /var/lib/virtiofs/data/sonarr/config 0700 10017 10000 -
d$ /var/lib/virtiofs/data/sonarr/config/tmp 0700 10017 10000 -
d$ /var/lib/virtiofs/data/sonarr/config/xdg 0700 10017 10000 -
d$ /var/lib/virtiofs/data/prowlarr 0700 10017 10000 -
d$ /var/lib/virtiofs/data/prowlarr/config 0700 10017 10000 -
d$ /var/lib/virtiofs/data/prowlarr/config/tmp 0700 10017 10000 -
d$ /var/lib/virtiofs/data/prowlarr/config/xdg 0700 10017 10000 -
d$ /var/lib/virtiofs/data/jellyfin 0700 10017 10000 -
d$ /var/lib/virtiofs/data/jellyfin/config 0700 10017 10000 -

11
traefik/Makefile

@ -0,0 +1,11 @@
##
## Makefile for Traefik quadlet
##
# Traefik quadlet is mapped to the 10001 user (traefik) and 10000 group (itix-svc)
PROJECT_UID = 10001
PROJECT_GID = 10000
TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common

16
traefik/config/examples/conf.d/itix-middlewares.yaml

@ -0,0 +1,16 @@
http:
middlewares:
## Password hashes can be generated with:
#
# htpasswd -n -B -C 10 <username>
#
itix-admins:
basicAuth:
realm: "ITIX"
headerField: "X-WebAuth-User"
usersFile: "/etc/traefik/itix-admins.txt"
itix-users:
basicAuth:
realm: "ITIX"
headerField: "X-WebAuth-User"
usersFile: "/etc/traefik/itix-users.txt"

15
traefik/config/examples/conf.d/ping.yaml

@ -0,0 +1,15 @@
http:
routers:
traefik-ping:
rule: Host(`ping`)
entryPoints:
- http
service: "ping@internal"
middlewares:
- localhost-only
services: {}
middlewares:
localhost-only:
ipAllowList:
sourceRange:
- "127.0.0.1/32"

0
traefik/config/examples/itix-admins.txt

0
traefik/config/examples/itix-users.txt

34
traefik/config/traefik.yaml

@ -0,0 +1,34 @@
api:
dashboard: true
debug: false
ping:
manualRouting: true
log:
level: "INFO"
accesslog: false
global:
sendanonymoususage: false
checknewversion: false
entryPoints:
http:
address: ":80"
https:
address: ":443"
certificatesResolvers:
le:
acme:
email: "nicolas.masse@itix.fr"
keyType: "EC384"
httpChallenge:
# used during the challenge
entryPoint: http
storage: "/var/lib/traefik/acme.json"
providers:
file:
directory: /etc/traefik/conf.d/
watch: true

9
traefik/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: traefik
uid: 10001
gecos: Traefik
home_dir: /var/lib/quadlets/traefik
primary_group: itix-svc

43
traefik/traefik.container

@ -0,0 +1,43 @@
[Unit]
Description=Traefik reverse proxy
Documentation=https://github.com/traefik/traefik-library-image
After=local-fs.target network.target
Before=traefik.target
# Start/stop this unit when the target is started/stopped
PartOf=traefik.target
[Container]
ContainerName=traefik
# Image
Image=docker.io/library/traefik:v3.4
AutoUpdate=registry
# No need for root privileges
User=10001
Group=10000
AddCapability=CAP_NET_BIND_SERVICE
# Storage
Volume=/var/lib/quadlets/traefik:/var/lib/traefik:z
Volume=/etc/quadlets/traefik:/etc/traefik:z
# Network
Network=host
# Health check
HealthCmd=wget -q -O /dev/null --header 'Host: ping' http://127.0.0.1/
HealthInterval=30s
HealthTimeout=10s
HealthStartPeriod=10s
HealthRetries=3
[Service]
Restart=always
RestartSec=10
TimeoutStartSec=120
TimeoutStopSec=30
[Install]
WantedBy=traefik.target

11
traefik/traefik.target

@ -0,0 +1,11 @@
[Unit]
Description=PostgreSQL Service Target
Documentation=man:systemd.target(5)
Requires=traefik.service
After=traefik.service
# Allow isolation - can stop/start this target independently
AllowIsolate=yes
[Install]
WantedBy=multi-user.target

16
vmagent/Makefile

@ -0,0 +1,16 @@
##
## Makefile for Victoria Metrics Agent quadlet
##
# Victoria Metrics Agent quadlet is mapped to the 10025 user (vmagent) and 10000 group (itix-svc)
PROJECT_UID = 10025
PROJECT_GID = 10000
# Include common Makefile
TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common
SYSTEMD_MAIN_UNIT_NAMES += vmagent.service
$(TARGET_CHROOT)/etc/quadlets/vmagent/conf.d:
install -d -m 0700 -o $(PROJECT_UID) -g $(PROJECT_GID) -D $< $@

1
vmagent/config/examples/conf.d/remotewrite.token

@ -0,0 +1 @@
REDACTED

3
vmagent/config/examples/vmagent.local.env

@ -0,0 +1,3 @@
remoteWrite_url=https://victoriametrics.example.tld/api/v1/write
remoteWrite_basicAuth_passwordFile=/etc/vmagent/remotewrite.token
remoteWrite_basicAuth_username=remotewrite

2
vmagent/config/vmagent.global.env

@ -0,0 +1,2 @@
httpListenAddr=127.0.0.1:8428
remoteWrite_tmpDataPath=/var/lib/vmagent/tmp

9
vmagent/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: vmagent
uid: 10025
gecos: Victoria Metrics Agent
home_dir: /var/lib/quadlets/vmagent
primary_group: itix-svc

33
vmagent/vmagent.container

@ -0,0 +1,33 @@
[Unit]
Description=Victoria Metrics agent
After=local-fs.target network.target
Wants=network.target
# Only start if the local configuration file exists
ConditionPathExists=/etc/quadlets/vmagent/vmagent.local.env
[Container]
ContainerName=vmagent
# Image
Image=quay.io/victoriametrics/vmagent:latest
AutoUpdate=registry
# Security
User=10025
Group=10000
# Storage
Volume=/var/lib/quadlets/vmagent:/var/lib/vmagent:Z
Volume=/etc/quadlets/vmagent/conf.d:/etc/vmagent:ro
# Network
Network=host
# Configuration
EnvironmentFile=/etc/quadlets/vmagent/vmagent.global.env
EnvironmentFile=/etc/quadlets/vmagent/vmagent.local.env
Exec=-envflag.enable
[Install]
WantedBy=multi-user.target

15
vsftpd/Makefile

@ -0,0 +1,15 @@
##
## Makefile for Vsftpd quadlet
##
DEPENDENCIES = lego
# Vsftpd quadlet is mapped to the 10015 user (vsftpd) and 10000 group (itix-svc)
PROJECT_UID = 10015
PROJECT_GID = 10000
# Include common Makefile
TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common

20
vsftpd/config/container/Containerfile

@ -0,0 +1,20 @@
FROM quay.io/centos/centos:stream10
# Install Vsftpd
RUN dnf config-manager --set-enabled crb \
&& dnf install -y epel-release \
&& dnf install -y vsftpd procps-ng shadow-utils authselect authselect-libs pam gdbm \
&& authselect select local --force \
&& dnf clean all
# /data holds the data to share through vsftpd
VOLUME /data
# Expose FTP port + ports for passive mode
EXPOSE 21 20000-20100
ADD container-entrypoint /
ADD vsftpd-virtual /etc/pam.d/vsftpd-virtual
ENTRYPOINT [ "/container-entrypoint" ]
CMD [ ]

25
vsftpd/config/container/container-entrypoint

@ -0,0 +1,25 @@
#!/bin/sh
set -Eeuo pipefail
# Handle the virtual user database when supplied
if [ -f /var/lib/vsftpd/users.txt ]; then
## Format of the "users.txt" file :
#
# nicolas:$y$....
# john:$y$....
#
# Empty lines and comments are allowed
#
## Hashes can be generated with :
#
# mkpasswd --method=yescrypt -s
#
umask 0077
touch /var/lib/vsftpd/users.txt
rm -f /var/lib/vsftpd/users.db
sed -r -e 's/^([^:]+):([^:]+)$/store "\1" "\2"/; t r; d; :r s/[\\]/\\\\$/g; s/[$]/\\$/g' < /var/lib/vsftpd/users.txt | gdbmtool --newdb /var/lib/vsftpd/users.db
umask 0022
fi
exec /usr/sbin/vsftpd -obackground=NO /etc/vsftpd/global.conf /etc/vsftpd/local.conf "$@"

27
vsftpd/config/container/vsftpd-virtual

@ -0,0 +1,27 @@
#%PAM-1.0
##
## Debug instructions
##
#
# - Add the "debug" option to pam_userdb.so
#
# [...] pam_userdb.so db=/var/lib/vsftpd/users crypt=crypt debug
#
# - Execute this command in the container:
#
# socat UNIX-LISTEN:/dev/log,fork STDOUT
#
##
## HEADS UP !!!
##
#
# pam_userdb.so is now linked to gdbm rather than berkeley db.
# so, you have to use gdbmtool to create the database, rather than db_load.
# Also, the path to the database has to include the final ".db".
#
auth required pam_userdb.so db=/var/lib/vsftpd/users.db crypt=crypt
account required pam_userdb.so db=/var/lib/vsftpd/users.db crypt=crypt
session required pam_loginuid.so

24
vsftpd/config/examples/vsftpd.conf.d/local-users.conf

@ -0,0 +1,24 @@
# Network parameters
pasv_address=storage.example.tld
pasv_addr_resolve=YES
# Authenticate local users
local_enable=YES
local_root=/data
chroot_local_user=YES
pam_service_name=vsftpd
# Enable write on the FTP server
write_enable=YES
# Since /var/lib/virtiofs/data (/data) is writable only by root we can allow this
allow_writeable_chroot=YES
# No anonymous access
anonymous_enable=NO
# Misc parameters
delete_failed_uploads=NO
ftpd_banner=Storage
file_open_mode=0660
ls_recurse_enable=YES

5
vsftpd/config/examples/vsftpd.conf.d/tls.conf

@ -0,0 +1,5 @@
ssl_enable=YES
ssl_request_cert=NO
ssl_tlsv1_2=NO
rsa_cert_file=/etc/vsftpd/tls/f.q.d.n.crt
rsa_private_key_file=/etc/vsftpd/tls/f.q.d.n.key

18
vsftpd/config/examples/vsftpd.conf.d/virtual-users.conf

@ -0,0 +1,18 @@
# Network parameters
pasv_address=storage.example.tld
pasv_addr_resolve=YES
# Authenticate virtual users
guest_enable=YES
guest_username=vsftpd
local_enable=YES
virtual_use_local_privs=YES
chroot_local_user=YES
pam_service_name=vsftpd-virtual
# Site specific config (example)
local_root=/data
# OR
#user_sub_token=$USER
#local_root=/data/$USER

21
vsftpd/config/vsftpd.conf.d/global.conf

@ -0,0 +1,21 @@
# Network parameters
listen=YES
listen_port=21
pasv_min_port=20000
pasv_max_port=20100
pasv_enable=YES
pasv_promiscuous=YES
# Be strict by default
anonymous_enable=NO
guest_enable=NO
local_enable=NO
# Log file
vsftpd_log_file=/var/log/vsftpd/vsftpd.log
xferlog_enable=YES
syslog_enable=NO
# Misc parameters
setproctitle_enable=YES
reverse_lookup_enable=NO

9
vsftpd/overlay.bu

@ -0,0 +1,9 @@
variant: fcos
version: 1.4.0
passwd:
users:
- name: vsftpd
uid: 10015
gecos: Vsftpd
home_dir: /var/lib/quadlets/vsftpd
primary_group: itix-svc

6
vsftpd/tmpfiles.d/vsftpd.conf

@ -0,0 +1,6 @@
d$ /run/quadlets/vsftpd 0700 0 0 -
d$ /run/quadlets/vsftpd/cache 0700 0 0 -
d$ /run/quadlets/vsftpd/tls 0700 0 0 -
d$ /var/lib/virtiofs/data/storage 0755 0 0 -
d$ /var/lib/quadlets/vsftpd/log 0755 0 0 -
d$ /var/lib/quadlets/vsftpd/data 0755 0 0 -

10
vsftpd/vsftpd-build.timer

@ -0,0 +1,10 @@
[Unit]
Description=Rebuild the vsftpd container image
PartOf=vsftpd.target
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=vsftpd.target

17
vsftpd/vsftpd-load-renewed-certificate.service

@ -0,0 +1,17 @@
[Unit]
Description=Restart Vsftpd if a new TLS certificate is available
# Lego touch .renewed files when renewed certificates are available
ConditionPathExistsGlob=/var/lib/quadlets/lego/certificates/*.renewed
After=lego-renew.service
[Service]
Type=oneshot
# Copy the renewed certificates to the vsftpd /run directory
ExecStartPre=/bin/sh -Eeuo pipefail -c 'install -o 10015 -g 10000 -m 0600 -t /run/quadlets/vsftpd/tls /var/lib/quadlets/lego/certificates/*.crt /var/lib/quadlets/lego/certificates/*.key'
# Restart vsftpd to load the new certificates
ExecStart=systemctl --no-block restart vsftpd.service
# Remove the flag files after restarting vsftpd
ExecStartPost=/bin/sh -Eeuo pipefail -c 'rm -f /var/lib/quadlets/lego/certificates/*.renewed'
[Install]
WantedBy=lego-renew.service

9
vsftpd/vsftpd.build

@ -0,0 +1,9 @@
[Unit]
Description=Build of the Vsftpd daemon
Wants=network-online.target
After=network-online.target
[Build]
File=/etc/quadlets/vsftpd/container/Containerfile
ImageTag=localhost/vsftpd:latest
SetWorkingDirectory=/etc/quadlets/vsftpd/container

52
vsftpd/vsftpd.container

@ -0,0 +1,52 @@
[Unit]
Description=Vsftpd
After=local-fs.target network.target vsftpd-build.service lego.target
Wants=vsftpd-build.service lego.target
# Only start if the local configuration file exists
ConditionPathExists=/etc/quadlets/vsftpd/vsftpd.conf.d/local.conf
# Stop when the target is stopped
PartOf=vsftpd.target
[Service]
# Copy a complete version of /etc/{passwd,group,shadow} in /run/quadlets/vsftpd so that SELinux
# does not prevent Vsftpd from reading those files.
#
# Oh, and by the way, mangle /etc/passwd so that local users' homes are located in /data.
# This is required by Vsftpd to let the users login.
ExecStartPre=/bin/sh -Eeuo pipefail -c '\
umask 0077 ; \
for file in passwd group shadow; do \
getent $file | (if [[ "$file" == "passwd" ]]; then \
sed -r "s|^([^:]+:[^:]*:[^:]+:1[0-9][0-9][0-9]:[^:]*:)[^:]*(:.*)$|\\1/data\\2|" ; \
else \
cat ; \
fi) > /run/quadlets/vsftpd/cache/$file ; \
done'
[Container]
ContainerName=vsftpd
# Image
Image=localhost/vsftpd:latest
AutoUpdate=local
# Security
User=0
# Storage
Volume=/var/lib/quadlets/vsftpd/log:/var/log/vsftpd:Z
Volume=/var/lib/quadlets/vsftpd/data:/var/lib/vsftpd:Z
Volume=/var/lib/virtiofs/data/storage:/data
Volume=/etc/quadlets/vsftpd/vsftpd.conf.d:/etc/vsftpd:ro
Volume=/run/quadlets/vsftpd/cache/passwd:/etc/passwd:Z
Volume=/run/quadlets/vsftpd/cache/group:/etc/group:Z
Volume=/run/quadlets/vsftpd/cache/shadow:/etc/shadow:Z
Volume=/run/quadlets/vsftpd/tls:/etc/vsftpd/tls:Z
# Network
Network=host
[Install]
WantedBy=vsftpd.target

11
vsftpd/vsftpd.target

@ -0,0 +1,11 @@
[Unit]
Description=Vsftpd Service Target
Documentation=man:systemd.target(5)
Requires=vsftpd.service vsftpd-build.timer
After=vsftpd.service vsftpd-build.timer
# Allow isolation - can stop/start this target independently
AllowIsolate=yes
[Install]
WantedBy=multi-user.target
Loading…
Cancel
Save