From 19fe50ec5526c4216a633e925146750695843068 Mon Sep 17 00:00:00 2001 From: William Marshall <62070150+marshallwp@users.noreply.github.com> Date: Wed, 28 Jan 2026 14:12:27 -0600 Subject: [PATCH 1/7] feat(quadlets): add quadlet deployment option --- quadlets/README.md | 49 ++++++++++++++++++++++++ quadlets/postgres.container | 24 ++++++++++++ quadlets/redis.container | 18 +++++++++ quadlets/setup-quadlets.sh | 72 ++++++++++++++++++++++++++++++++++++ quadlets/sourcebot.container | 28 ++++++++++++++ quadlets/sourcebot.pod | 3 ++ 6 files changed, 194 insertions(+) create mode 100644 quadlets/README.md create mode 100644 quadlets/postgres.container create mode 100644 quadlets/redis.container create mode 100644 quadlets/setup-quadlets.sh create mode 100644 quadlets/sourcebot.container create mode 100644 quadlets/sourcebot.pod diff --git a/quadlets/README.md b/quadlets/README.md new file mode 100644 index 00000000..2b955a4d --- /dev/null +++ b/quadlets/README.md @@ -0,0 +1,49 @@ +# Usage +1. Copy the contents of this directory to a [valid quadlet directory](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#synopsis) on the destination machine. At the time of this writing that can be: + +> Podman rootful unit search path +> +> Quadlet files for the root user can be placed in the following directories ordered in precedence. Meaning duplicate named quadlets found under /run take precedence over ones in /etc, as well as those in /usr: +> +> Temporary quadlets, usually used for testing: +> +> /run/containers/systemd/ +> +> System administrator’s defined quadlets: +> +> /etc/containers/systemd/ +> +> Distribution defined quadlets: +> +> /usr/share/containers/systemd/ +> +> Podman rootless unit search path +> +> Quadlet files for non-root users can be placed in the following directories: +> +> $XDG_RUNTIME_DIR/containers/systemd/ +> +> $XDG_CONFIG_HOME/containers/systemd/ or ~/.config/containers/systemd/ +> +> /etc/containers/systemd/users/$(UID) +> +> /etc/containers/systemd/users/ +> +> Using symbolic links +> +> Quadlet supports using symbolic links for the base of the search paths and inside them. +> +> *Source: https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#synopsis* + +Note that as systemd services can specify the user they run as, rootful quadlets do not necessarily run as the root user. This is demonstrated in [sourcebot.container](sourcebot.container), where user `sourcebot` is specified. + +2. Create podman secrets for sensitive settings. As an example, see `setup-quadlets.sh`, which generates basic required secrets. You'll need to add others like API Keys yourself. + +> [!important] +> `podman secret create` does not trim newlines from input. If you do not account for this then secrets can 'mysteriously' not work. +> +> Workarounds: +> 1. Use `printf` instead of `echo` to pipe values to `podman secret create` without appending a newline character. +> 2. Pipe values to `tr -d '\n'` prior to piping to `podman secret create` to remove newline characters. + +1. Optionally delete the `secrets` subdirectory. This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS` set to 'N'. That is used to drop and recreate the secrets without changing them. diff --git a/quadlets/postgres.container b/quadlets/postgres.container new file mode 100644 index 00000000..5d636676 --- /dev/null +++ b/quadlets/postgres.container @@ -0,0 +1,24 @@ +# sourcebot-postgres.container +[Unit] +Description=PostgreSQL Instance for Sourcebot + +[Container] +Image=docker.io/library/postgres:17 +Pull=always +Pod=sourcebot.pod +AutoUpdate=registry +HealthCmd=pg_isready -U postgres +HealthInterval=3s +HealthRetries=10 +HealthTimeout=3s +Volume=sourcebot_postgres_data:/var/lib/postgresql/data +Environment=POSTGRES_USER=postgres +Environment=POSTGRES_PASSWORD_FILE=/run/secrets/postgres_admin_password +Environment=POSTGRES_DB=postgres +Secret=postgres_admin_password + +[Service] +Restart=always + +[Install] +WantedBy=default.target diff --git a/quadlets/redis.container b/quadlets/redis.container new file mode 100644 index 00000000..2bbddc43 --- /dev/null +++ b/quadlets/redis.container @@ -0,0 +1,18 @@ +# sourcebot-redis.container +[Unit] +Description=Redis Instance for Sourcebot + +[Container] +Image=docker.io/library/redis:8 +HealthCmd=["redis-cli","ping"] +HealthInterval=3s +HealthRetries=10 +HealthTimeout=10s +Pod=sourcebot.pod +Volume=sourcebot_redis_data:/data + +[Service] +Restart=always + +[Install] +WantedBy=default.target diff --git a/quadlets/setup-quadlets.sh b/quadlets/setup-quadlets.sh new file mode 100644 index 00000000..a16701c4 --- /dev/null +++ b/quadlets/setup-quadlets.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env sh + +# Generate Random Passwords, ignoring any existing secrets. +GENERATE_NEW_SECRETS='Y' + +# Verify Variables. +if [ $GENERATE_NEW_SECRETS != 'Y' -a $GENERATE_NEW_SECRETS != 'y' -a $GENERATE_NEW_SECRETS != 'N' -a $GENERATE_NEW_SECRETS != 'n' ]; then + echo "Environment variable GENERATE_NEW_SECRETS must be either Y or N."; exit 1; +fi + +echo "(Re)creating Podman Secret Cache" +if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then + if [ ! -d './secrets' ]; then + mkdir --mode='u=rw,g=,o=' './secrets' + else + chmod -R 'u=rw,g=,o=' './secrets' + fi + + # Use gpg dry-run to generate random passwords without worrying about profile polution. + # Additionally, it does not add linebreaks to long random strings like openssl does. + gpg --dry-run --gen-random --armor 1 64 > ./secrets/postgres_admin_password 2> /dev/null + gpg --dry-run --gen-random --armor 1 33 > ./secrets/sourcebot_auth_secret 2> /dev/null + gpg --dry-run --gen-random --armor 1 24 > ./secrets/sourcebot_encryption_key 2> /dev/null +fi + +# Removing old versions of these secrets +podman secret ls -f name="(postgres_admin_password|sourcebot_auth_secret|sourcebot_encryption_key|sourcebot_database_url)" --format "{{.ID}}" | sudo xargs --no-run-if-empty podman secret rm +# If you want to create secrets inline: printf 'Hello World!' | podman secret create hello_world - +podman secret create postgres_admin_password "./secrets/postgres_admin_password" +podman secret create sourcebot_auth_secret "./secrets/sourcebot_auth_secret" +podman secret create sourcebot_encryption_key "./secrets/sourcebot_encryption_key" + +# URL encodes everything following the function name using just native sh and printf. +# Invoke via: +# url_encode test me out +# url_encode 'test me out' +# url_encode $(cat /run/secrets/password) +# echo 'test me out' | xargs -I {} sh -c 'url_encode "$@"' _ {} +url_encode () { + string=$* + while [ -n "$string" ]; do + tail=${string#?} + head=${string%$tail} + case $head in + [-._~0-9A-Za-z]) printf %c "$head";; + *) printf %%%02x "'$head" + esac + string=$tail + done + echo +} + +# * Generate URL-encoded DATABASE_URL based on secrets. Allows use of special characters in passwords. +# When running on podman 5+, all containers run in the same pod, so the correct address for postgres is 'localhost'. +printf 'postgresql://postgres:%s@localhost/postgres' "$(url_encode $(cat ./secrets/postgres_admin_password))" | podman secret create sourcebot_database_url - + + +# * Alter Passwords of PostgreSQL users +# Ensures that passwords are changed when secrets change. +if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then + # Wait up to 90 seconds for the instance to be ready. + timeout 90s bash -c "until podman exec \"systemd-postgres\" pg_isready -U postgres ; do sleep 3 ; done" + # Wait another 1 second to ensure it's actually up. + sleep 1 + + echo "Updating superuser Password" + awk -v usr=postgres -v usrpwd="$(cat ./secrets/postgres_admin_password)" \ + 'BEGIN { print "ALTER USER "usr" WITH PASSWORD ""'\''"usrpwd"'\'';" }' \ + | podman exec systemd-postgres psql -U postgres +fi + +echo "Setup complete!" diff --git a/quadlets/sourcebot.container b/quadlets/sourcebot.container new file mode 100644 index 00000000..7777cc1b --- /dev/null +++ b/quadlets/sourcebot.container @@ -0,0 +1,28 @@ +# sourcebot-sourcebot.container +[Unit] +Description=Sourcebot Instance +Requires=postgres.service redis.service +After=postgres.service redis.service + +[Container] +ContainerName=sourcebot +Image=ghcr.io/sourcebot-dev/sourcebot:latest +Pull=always +AutoUpdate=registry +Pod=sourcebot.pod +User=sourcebot +Volume=./config.json:/data/config.json:ro,z +Volume=sourcebot_data:/data +Environment=CONFIG_PATH=/data/config.json +Environment=AUTH_URL=${AUTH_URL:-http://localhost:3000} +Environment=REDIS_URL=redis://localhost:6379 +Secret=SOURCEBOT_AUTH_SECRET,type=env,target=AUTH_SECRET +Secret=SOURCEBOT_ENCRYPTION_KEY,type=env +Secret=SOURCEBOT_DATABASE_URL,type=env,target=DATABASE_URL +Secret=SOURCEBOT_EE_LICENSE_KEY,type=env + +[Service] +Restart=always + +[Install] +WantedBy=default.target diff --git a/quadlets/sourcebot.pod b/quadlets/sourcebot.pod new file mode 100644 index 00000000..2b2d52ea --- /dev/null +++ b/quadlets/sourcebot.pod @@ -0,0 +1,3 @@ +# sourcebot.pod +[Pod] +PublishPort=3000:3000 From 906e746618b3c1add552fd86fe871fd066681eed Mon Sep 17 00:00:00 2001 From: William Marshall <62070150+marshallwp@users.noreply.github.com> Date: Wed, 28 Jan 2026 14:20:19 -0600 Subject: [PATCH 2/7] fix(quadlets): ensure casing of podman secrets is consistent. --- quadlets/postgres.container | 4 ++-- quadlets/setup-quadlets.sh | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/quadlets/postgres.container b/quadlets/postgres.container index 5d636676..b2e81011 100644 --- a/quadlets/postgres.container +++ b/quadlets/postgres.container @@ -13,9 +13,9 @@ HealthRetries=10 HealthTimeout=3s Volume=sourcebot_postgres_data:/var/lib/postgresql/data Environment=POSTGRES_USER=postgres -Environment=POSTGRES_PASSWORD_FILE=/run/secrets/postgres_admin_password +Environment=POSTGRES_PASSWORD_FILE=/run/secrets/POSTGRES_ADMIN_PASSWORD Environment=POSTGRES_DB=postgres -Secret=postgres_admin_password +Secret=POSTGRES_ADMIN_PASSWORD [Service] Restart=always diff --git a/quadlets/setup-quadlets.sh b/quadlets/setup-quadlets.sh index a16701c4..4c18a035 100644 --- a/quadlets/setup-quadlets.sh +++ b/quadlets/setup-quadlets.sh @@ -24,11 +24,11 @@ if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then fi # Removing old versions of these secrets -podman secret ls -f name="(postgres_admin_password|sourcebot_auth_secret|sourcebot_encryption_key|sourcebot_database_url)" --format "{{.ID}}" | sudo xargs --no-run-if-empty podman secret rm +podman secret ls -f name="(POSTGRES_ADMIN_PASSWORD|SOURCEBOT_AUTH_SECRET|SOURCEBOT_ENCRYPTION_KEY|SOURCEBOT_DATABASE_URL)" --format "{{.ID}}" | sudo xargs --no-run-if-empty podman secret rm # If you want to create secrets inline: printf 'Hello World!' | podman secret create hello_world - -podman secret create postgres_admin_password "./secrets/postgres_admin_password" -podman secret create sourcebot_auth_secret "./secrets/sourcebot_auth_secret" -podman secret create sourcebot_encryption_key "./secrets/sourcebot_encryption_key" +podman secret create POSTGRES_ADMIN_PASSWORD "./secrets/postgres_admin_password" +podman secret create SOURCEBOT_AUTH_SECRET "./secrets/sourcebot_auth_secret" +podman secret create SOURCEBOT_ENCRYPTION_KEY "./secrets/sourcebot_encryption_key" # URL encodes everything following the function name using just native sh and printf. # Invoke via: @@ -52,7 +52,7 @@ url_encode () { # * Generate URL-encoded DATABASE_URL based on secrets. Allows use of special characters in passwords. # When running on podman 5+, all containers run in the same pod, so the correct address for postgres is 'localhost'. -printf 'postgresql://postgres:%s@localhost/postgres' "$(url_encode $(cat ./secrets/postgres_admin_password))" | podman secret create sourcebot_database_url - +printf 'postgresql://postgres:%s@localhost/postgres' "$(url_encode $(cat ./secrets/postgres_admin_password))" | podman secret create SOURCEBOT_DATABASE_URL - # * Alter Passwords of PostgreSQL users From c900cffd5337e68d7f5d1228786560cd2cae1e82 Mon Sep 17 00:00:00 2001 From: William Marshall <62070150+marshallwp@users.noreply.github.com> Date: Wed, 28 Jan 2026 14:33:55 -0600 Subject: [PATCH 3/7] docs(quadlets): added pramble to README. This should make it clearer to users what this directory contains and whether it is something of interest to them. --- quadlets/README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/quadlets/README.md b/quadlets/README.md index 2b955a4d..0c65abf8 100644 --- a/quadlets/README.md +++ b/quadlets/README.md @@ -1,3 +1,12 @@ +This directory contains the files needed to deploy Sourcebot via Podman Quadlets. This is an alternative to Docker Compose that has a number of notable differences: + +- Containers are managed as systemd services, including logging as such. +- Online Auto-Update of container images with automatic rollback on update failure. NOTE: This is not scheduled by default, but you can manually run it via `podman auto-update`. +- Supports injecting podman secrets as environmental values (not just as files like docker does). This is very useful for keeping things like SOURCEBOT_AUTH_SECRET, SOURCEBOT_ENCRYPTION_KEY, DATABASE_URL, and various other sensitive environmental variables secret. +- Supports podman pods (podman 5+ only), which make it easy to isolate inter-container networking. + +This particular deployment assumes you are running podman 5+ as it uses Quadlets to define a Pod. + # Usage 1. Copy the contents of this directory to a [valid quadlet directory](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#synopsis) on the destination machine. At the time of this writing that can be: @@ -37,7 +46,7 @@ Note that as systemd services can specify the user they run as, rootful quadlets do not necessarily run as the root user. This is demonstrated in [sourcebot.container](sourcebot.container), where user `sourcebot` is specified. -2. Create podman secrets for sensitive settings. As an example, see `setup-quadlets.sh`, which generates basic required secrets. You'll need to add others like API Keys yourself. +2. Create podman secrets for sensitive settings. As an example, see [setup-quadlets.sh](setup-quadlets.sh), which generates basic required secrets. You'll need to add others like API Keys yourself. > [!important] > `podman secret create` does not trim newlines from input. If you do not account for this then secrets can 'mysteriously' not work. @@ -46,4 +55,4 @@ Note that as systemd services can specify the user they run as, rootful quadlets > 1. Use `printf` instead of `echo` to pipe values to `podman secret create` without appending a newline character. > 2. Pipe values to `tr -d '\n'` prior to piping to `podman secret create` to remove newline characters. -1. Optionally delete the `secrets` subdirectory. This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS` set to 'N'. That is used to drop and recreate the secrets without changing them. +3. Optionally delete the `secrets` subdirectory. This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS` set to 'N'. That is used to drop and recreate the secrets without changing them. Useful if you suspect you've succumbed to the important issue noted above. From c37a32c928818e22ac17fa07adb74bceb47825ec Mon Sep 17 00:00:00 2001 From: William Marshall <62070150+marshallwp@users.noreply.github.com> Date: Wed, 28 Jan 2026 14:39:11 -0600 Subject: [PATCH 4/7] fix(quadlets): removed alter postgres password code. It was from a more advanced script that also managed instantiation of quadlets. --- quadlets/setup-quadlets.sh | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/quadlets/setup-quadlets.sh b/quadlets/setup-quadlets.sh index 4c18a035..86f80116 100644 --- a/quadlets/setup-quadlets.sh +++ b/quadlets/setup-quadlets.sh @@ -54,19 +54,4 @@ url_encode () { # When running on podman 5+, all containers run in the same pod, so the correct address for postgres is 'localhost'. printf 'postgresql://postgres:%s@localhost/postgres' "$(url_encode $(cat ./secrets/postgres_admin_password))" | podman secret create SOURCEBOT_DATABASE_URL - - -# * Alter Passwords of PostgreSQL users -# Ensures that passwords are changed when secrets change. -if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then - # Wait up to 90 seconds for the instance to be ready. - timeout 90s bash -c "until podman exec \"systemd-postgres\" pg_isready -U postgres ; do sleep 3 ; done" - # Wait another 1 second to ensure it's actually up. - sleep 1 - - echo "Updating superuser Password" - awk -v usr=postgres -v usrpwd="$(cat ./secrets/postgres_admin_password)" \ - 'BEGIN { print "ALTER USER "usr" WITH PASSWORD ""'\''"usrpwd"'\'';" }' \ - | podman exec systemd-postgres psql -U postgres -fi - echo "Setup complete!" From 3c5bdfebedeaa1db641a4e8f179d3c8c8637e81f Mon Sep 17 00:00:00 2001 From: William Marshall <62070150+marshallwp@users.noreply.github.com> Date: Wed, 28 Jan 2026 14:58:54 -0600 Subject: [PATCH 5/7] fix(quadlets): remove lingering sudo. Also add an example of how to start the pod. --- quadlets/README.md | 7 +++++++ quadlets/setup-quadlets.sh | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/quadlets/README.md b/quadlets/README.md index 0c65abf8..0c8d702c 100644 --- a/quadlets/README.md +++ b/quadlets/README.md @@ -56,3 +56,10 @@ Note that as systemd services can specify the user they run as, rootful quadlets > 2. Pipe values to `tr -d '\n'` prior to piping to `podman secret create` to remove newline characters. 3. Optionally delete the `secrets` subdirectory. This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS` set to 'N'. That is used to drop and recreate the secrets without changing them. Useful if you suspect you've succumbed to the important issue noted above. + +4. Once everything is in place, you can start the pod via: +```bash +systemctl daemon-reload +systemctl start sourcebot-pod +``` +This will start all services in the pod. diff --git a/quadlets/setup-quadlets.sh b/quadlets/setup-quadlets.sh index 86f80116..c7841403 100644 --- a/quadlets/setup-quadlets.sh +++ b/quadlets/setup-quadlets.sh @@ -24,7 +24,7 @@ if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then fi # Removing old versions of these secrets -podman secret ls -f name="(POSTGRES_ADMIN_PASSWORD|SOURCEBOT_AUTH_SECRET|SOURCEBOT_ENCRYPTION_KEY|SOURCEBOT_DATABASE_URL)" --format "{{.ID}}" | sudo xargs --no-run-if-empty podman secret rm +podman secret ls -f name="(POSTGRES_ADMIN_PASSWORD|SOURCEBOT_AUTH_SECRET|SOURCEBOT_ENCRYPTION_KEY|SOURCEBOT_DATABASE_URL)" --format "{{.ID}}" | xargs --no-run-if-empty podman secret rm # If you want to create secrets inline: printf 'Hello World!' | podman secret create hello_world - podman secret create POSTGRES_ADMIN_PASSWORD "./secrets/postgres_admin_password" podman secret create SOURCEBOT_AUTH_SECRET "./secrets/sourcebot_auth_secret" From 175933ac40b0be922aa9b988035801318d7deba3 Mon Sep 17 00:00:00 2001 From: William Marshall <62070150+marshallwp@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:14:03 -0600 Subject: [PATCH 6/7] fix(quadlets): address chmod issue flaged by coderabbitai. --- quadlets/setup-quadlets.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/quadlets/setup-quadlets.sh b/quadlets/setup-quadlets.sh index c7841403..e1f37330 100644 --- a/quadlets/setup-quadlets.sh +++ b/quadlets/setup-quadlets.sh @@ -11,10 +11,11 @@ fi echo "(Re)creating Podman Secret Cache" if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then if [ ! -d './secrets' ]; then - mkdir --mode='u=rw,g=,o=' './secrets' + mkdir --mode='u=rwx,g=,o=' './secrets' else - chmod -R 'u=rw,g=,o=' './secrets' + chmod 'u=rwx,g=,o=' './secrets' fi + find './secrets' -type f -exec chmod 'u=rw,g=,o=' {} + # Use gpg dry-run to generate random passwords without worrying about profile polution. # Additionally, it does not add linebreaks to long random strings like openssl does. From 799b098fcb7af7571e541d5e0a1939c47e6ad061 Mon Sep 17 00:00:00 2001 From: William Marshall <62070150+marshallwp@users.noreply.github.com> Date: Wed, 28 Jan 2026 16:03:30 -0600 Subject: [PATCH 7/7] docs(quadlets): Instruct non-EE users to remove SOURCEBOT_EE_LICENSE_KEY from their quadlets. --- quadlets/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/quadlets/README.md b/quadlets/README.md index 0c8d702c..fb217972 100644 --- a/quadlets/README.md +++ b/quadlets/README.md @@ -46,7 +46,9 @@ This particular deployment assumes you are running podman 5+ as it uses Quadlets Note that as systemd services can specify the user they run as, rootful quadlets do not necessarily run as the root user. This is demonstrated in [sourcebot.container](sourcebot.container), where user `sourcebot` is specified. -2. Create podman secrets for sensitive settings. As an example, see [setup-quadlets.sh](setup-quadlets.sh), which generates basic required secrets. You'll need to add others like API Keys yourself. +2. If you are *not* using Enterprise Edition, edit the [sourcebot.container](sourcebot.container) file and remove the `Secret=SOURCEBOT_EE_LICENSE_KEY,type=env` line. + +3. Create podman secrets for sensitive settings. As an example, see [setup-quadlets.sh](setup-quadlets.sh), which generates basic required secrets. You'll need to add others like API Keys yourself. > [!important] > `podman secret create` does not trim newlines from input. If you do not account for this then secrets can 'mysteriously' not work. @@ -55,9 +57,9 @@ Note that as systemd services can specify the user they run as, rootful quadlets > 1. Use `printf` instead of `echo` to pipe values to `podman secret create` without appending a newline character. > 2. Pipe values to `tr -d '\n'` prior to piping to `podman secret create` to remove newline characters. -3. Optionally delete the `secrets` subdirectory. This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS` set to 'N'. That is used to drop and recreate the secrets without changing them. Useful if you suspect you've succumbed to the important issue noted above. +4. Optionally delete the `secrets` subdirectory. This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS` set to 'N'. That is used to drop and recreate the secrets without changing them. Useful if you suspect you've succumbed to the important issue noted above. -4. Once everything is in place, you can start the pod via: +5. Once everything is in place, you can start the pod via: ```bash systemctl daemon-reload systemctl start sourcebot-pod