From ba3a7bc94421f93818f9196bd8a2c32eb7d9d940 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Wed, 3 Jun 2026 17:12:58 +0200 Subject: feat: better initialization script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename `tools/build` → `net_services` `net_services` can be run from anywhere (previously it was not creating the fs archives in the right place). It also creates the directories specified in `.env`, generate a self-signed certificate if no certificate is available, initialize the first Radicale user if missing, and copy example configuration files if missing for cgit. `generate_self_signed_cert` has been removed (its code is in `net_services`) --- services/cgit/examples/about.md | 3 + services/cgit/examples/cgitrc | 47 +++++++++++++ services/cgit/examples/commit-filter.sh | 11 ++++ .../etc/nginx/templates/default.conf.template | 46 ------------- .../nginx/templates/services/cgit.conf.template | 17 ----- .../templates/services/radicale.conf.template | 19 ------ .../templates/services/syncthing.conf.template | 20 ------ .../fs/etc/nginx/templates/default.conf.template | 46 +++++++++++++ .../nginx/templates/services/cgit.conf.template | 17 +++++ .../templates/services/radicale.conf.template | 19 ++++++ .../templates/services/syncthing.conf.template | 20 ++++++ services/nginx/fs/sbin/cmd.bash | 11 ++++ services/nginx/sbin/cmd.bash | 11 ---- services/radicale/etc/radicale/conf.ini | 14 ---- services/radicale/fs/etc/radicale/conf.ini | 14 ++++ services/radicale/fs/sbin/cmd.sh | 33 ++++++++++ services/radicale/sbin/cmd.sh | 33 ---------- tools/build | 5 -- tools/generate_self_signed_cert | 12 ---- tools/net_services | 76 ++++++++++++++++++++++ 20 files changed, 297 insertions(+), 177 deletions(-) create mode 100644 services/cgit/examples/about.md create mode 100644 services/cgit/examples/cgitrc create mode 100755 services/cgit/examples/commit-filter.sh delete mode 100644 services/nginx/etc/nginx/templates/default.conf.template delete mode 100644 services/nginx/etc/nginx/templates/services/cgit.conf.template delete mode 100644 services/nginx/etc/nginx/templates/services/radicale.conf.template delete mode 100644 services/nginx/etc/nginx/templates/services/syncthing.conf.template create mode 100644 services/nginx/fs/etc/nginx/templates/default.conf.template create mode 100644 services/nginx/fs/etc/nginx/templates/services/cgit.conf.template create mode 100644 services/nginx/fs/etc/nginx/templates/services/radicale.conf.template create mode 100644 services/nginx/fs/etc/nginx/templates/services/syncthing.conf.template create mode 100755 services/nginx/fs/sbin/cmd.bash delete mode 100755 services/nginx/sbin/cmd.bash delete mode 100644 services/radicale/etc/radicale/conf.ini create mode 100644 services/radicale/fs/etc/radicale/conf.ini create mode 100755 services/radicale/fs/sbin/cmd.sh delete mode 100755 services/radicale/sbin/cmd.sh delete mode 100755 tools/build delete mode 100755 tools/generate_self_signed_cert create mode 100755 tools/net_services diff --git a/services/cgit/examples/about.md b/services/cgit/examples/about.md new file mode 100644 index 0000000..9aa4532 --- /dev/null +++ b/services/cgit/examples/about.md @@ -0,0 +1,3 @@ +# cgit + +Edit this in `about.md`. diff --git a/services/cgit/examples/cgitrc b/services/cgit/examples/cgitrc new file mode 100644 index 0000000..631feaa --- /dev/null +++ b/services/cgit/examples/cgitrc @@ -0,0 +1,47 @@ +# +# Global +# +css=/cgit.css +logo=/cgit.png +# Formatters +source-filter=/usr/local/lib/cgit/filters/syntax-highlighting.py +about-filter=/usr/local/lib/cgit/filters/about-formatting.sh +commit-filter=/usr/local/lib/cgit/filters/commit/commit-filter.sh +# Mimetypes (for plain blobs) +mimetype.gif=image/gif +mimetype.html=text/html +mimetype.jpg=image/jpeg +mimetype.jpeg=image/jpeg +mimetype.pdf=application/pdf +mimetype.png=image/png +mimetype.svg=image/svg+xml + +# +# Cache +# +cache-size=1000 + +# +# Index +# +root-title=Edit this in cgitrc +root-desc=Edit this in cgitrc +root-readme=/srv/cgit/about.md +favicon=/favicon.ico + +# +# Repositories +# +enable-index-owner=1 +enable-index-links=1 +enable-commit-graph=1 +enable-log-filecount=1 +enable-log-linecount=1 +repository-sort=age +remove-suffix=1 +max-stats=year +snapshots=tar.gz zip +clone-url=http://localhost:8080/$CGIT_REPO_URL +readme=:readme.md +# This setting must be set last because settings set after repos are scanned are not applied +scan-path=/srv/git diff --git a/services/cgit/examples/commit-filter.sh b/services/cgit/examples/commit-filter.sh new file mode 100755 index 0000000..3b6dbd2 --- /dev/null +++ b/services/cgit/examples/commit-filter.sh @@ -0,0 +1,11 @@ +regex='' + +# This expression generates links to commits referenced by their SHA1. +regex=$regex' +s|\b([0-9a-fA-F]{7,64})\b|\1|g' + +# This expression generates links to a fictional bugtracker. +regex=$regex' +s|#([0-9]+)\b|#\1|g' + +sed -re "$regex" diff --git a/services/nginx/etc/nginx/templates/default.conf.template b/services/nginx/etc/nginx/templates/default.conf.template deleted file mode 100644 index f90b61a..0000000 --- a/services/nginx/etc/nginx/templates/default.conf.template +++ /dev/null @@ -1,46 +0,0 @@ -server { - listen 80; - listen [::]:80; - - server_name ${NGINX__HOST} - www.${NGINX__HOST} - dav.${NGINX__HOST} - git.${NGINX__HOST} - sync.${NGINX__HOST}; - - # Prevent nginx HTTP Server Detection - server_tokens off; - - return 301 https://$host$request_uri; -} - -server { - listen 443 ssl; - listen [::]:443 ssl; - - server_name ${NGINX__HOST} www.${NGINX__HOST}; - - ssl_certificate /run/secrets/server.crt; - ssl_certificate_key /run/secrets/server.key; - - location / { - root /srv; - } -} - -server { - listen 443 ssl default_server; - listen [::]:443 ssl default_server; - - server_name _; - - ssl_certificate /run/secrets/server.crt; - ssl_certificate_key /run/secrets/server.key; - - return 444; -} - -# Docker embedded DNS server -resolver 127.0.0.11 valid=2s; - -include /etc/nginx/conf.d/services/*.conf; diff --git a/services/nginx/etc/nginx/templates/services/cgit.conf.template b/services/nginx/etc/nginx/templates/services/cgit.conf.template deleted file mode 100644 index c0fa070..0000000 --- a/services/nginx/etc/nginx/templates/services/cgit.conf.template +++ /dev/null @@ -1,17 +0,0 @@ -server { - listen 443 ssl; - listen [::]:443 ssl; - - server_name git.${NGINX__HOST}; - - ssl_certificate /run/secrets/server.crt; - ssl_certificate_key /run/secrets/server.key; - - location / { - proxy_pass http://cgit:80; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -} diff --git a/services/nginx/etc/nginx/templates/services/radicale.conf.template b/services/nginx/etc/nginx/templates/services/radicale.conf.template deleted file mode 100644 index d6e4617..0000000 --- a/services/nginx/etc/nginx/templates/services/radicale.conf.template +++ /dev/null @@ -1,19 +0,0 @@ -server { - listen 443 ssl; - listen [::]:443 ssl; - - server_name dav.${NGINX__HOST}; - - ssl_certificate /run/secrets/server.crt; - ssl_certificate_key /run/secrets/server.key; - - location / { - proxy_pass http://radicale:5232; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Port $server_port; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $http_host; - proxy_pass_header Authorization; - } -} diff --git a/services/nginx/etc/nginx/templates/services/syncthing.conf.template b/services/nginx/etc/nginx/templates/services/syncthing.conf.template deleted file mode 100644 index 31c90bb..0000000 --- a/services/nginx/etc/nginx/templates/services/syncthing.conf.template +++ /dev/null @@ -1,20 +0,0 @@ -server { - listen 443 ssl; - listen [::]:443 ssl; - - server_name sync.${NGINX__HOST}; - - ssl_certificate /run/secrets/server.crt; - ssl_certificate_key /run/secrets/server.key; - - location / { - proxy_pass http://syncthing:8384; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - proxy_read_timeout 600s; - proxy_send_timeout 600s; - } -} diff --git a/services/nginx/fs/etc/nginx/templates/default.conf.template b/services/nginx/fs/etc/nginx/templates/default.conf.template new file mode 100644 index 0000000..f90b61a --- /dev/null +++ b/services/nginx/fs/etc/nginx/templates/default.conf.template @@ -0,0 +1,46 @@ +server { + listen 80; + listen [::]:80; + + server_name ${NGINX__HOST} + www.${NGINX__HOST} + dav.${NGINX__HOST} + git.${NGINX__HOST} + sync.${NGINX__HOST}; + + # Prevent nginx HTTP Server Detection + server_tokens off; + + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name ${NGINX__HOST} www.${NGINX__HOST}; + + ssl_certificate /run/secrets/server.crt; + ssl_certificate_key /run/secrets/server.key; + + location / { + root /srv; + } +} + +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + + server_name _; + + ssl_certificate /run/secrets/server.crt; + ssl_certificate_key /run/secrets/server.key; + + return 444; +} + +# Docker embedded DNS server +resolver 127.0.0.11 valid=2s; + +include /etc/nginx/conf.d/services/*.conf; diff --git a/services/nginx/fs/etc/nginx/templates/services/cgit.conf.template b/services/nginx/fs/etc/nginx/templates/services/cgit.conf.template new file mode 100644 index 0000000..c0fa070 --- /dev/null +++ b/services/nginx/fs/etc/nginx/templates/services/cgit.conf.template @@ -0,0 +1,17 @@ +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name git.${NGINX__HOST}; + + ssl_certificate /run/secrets/server.crt; + ssl_certificate_key /run/secrets/server.key; + + location / { + proxy_pass http://cgit:80; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/services/nginx/fs/etc/nginx/templates/services/radicale.conf.template b/services/nginx/fs/etc/nginx/templates/services/radicale.conf.template new file mode 100644 index 0000000..d6e4617 --- /dev/null +++ b/services/nginx/fs/etc/nginx/templates/services/radicale.conf.template @@ -0,0 +1,19 @@ +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name dav.${NGINX__HOST}; + + ssl_certificate /run/secrets/server.crt; + ssl_certificate_key /run/secrets/server.key; + + location / { + proxy_pass http://radicale:5232; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $http_host; + proxy_pass_header Authorization; + } +} diff --git a/services/nginx/fs/etc/nginx/templates/services/syncthing.conf.template b/services/nginx/fs/etc/nginx/templates/services/syncthing.conf.template new file mode 100644 index 0000000..31c90bb --- /dev/null +++ b/services/nginx/fs/etc/nginx/templates/services/syncthing.conf.template @@ -0,0 +1,20 @@ +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name sync.${NGINX__HOST}; + + ssl_certificate /run/secrets/server.crt; + ssl_certificate_key /run/secrets/server.key; + + location / { + proxy_pass http://syncthing:8384; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_read_timeout 600s; + proxy_send_timeout 600s; + } +} diff --git a/services/nginx/fs/sbin/cmd.bash b/services/nginx/fs/sbin/cmd.bash new file mode 100755 index 0000000..e024b4f --- /dev/null +++ b/services/nginx/fs/sbin/cmd.bash @@ -0,0 +1,11 @@ +#!/usr/bin/bash +set -eu + +# Install sensitive data in tmpfs +install --mode 400 /run/host_secrets/server.crt /run/secrets/server.crt +install --mode 400 /run/host_secrets/server.key /run/secrets/server.key + +# We have to run the entrypoint again +# Because if the first positional parameter is not "nginx" or "nginx-debug" the scripts in /docker-entrypoint.d are not ran. +# https://github.com/nginx/docker-nginx/blob/master/stable/debian/docker-entrypoint.sh +exec /docker-entrypoint.sh nginx -g "daemon off;" diff --git a/services/nginx/sbin/cmd.bash b/services/nginx/sbin/cmd.bash deleted file mode 100755 index e024b4f..0000000 --- a/services/nginx/sbin/cmd.bash +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/bash -set -eu - -# Install sensitive data in tmpfs -install --mode 400 /run/host_secrets/server.crt /run/secrets/server.crt -install --mode 400 /run/host_secrets/server.key /run/secrets/server.key - -# We have to run the entrypoint again -# Because if the first positional parameter is not "nginx" or "nginx-debug" the scripts in /docker-entrypoint.d are not ran. -# https://github.com/nginx/docker-nginx/blob/master/stable/debian/docker-entrypoint.sh -exec /docker-entrypoint.sh nginx -g "daemon off;" diff --git a/services/radicale/etc/radicale/conf.ini b/services/radicale/etc/radicale/conf.ini deleted file mode 100644 index 2af4af9..0000000 --- a/services/radicale/etc/radicale/conf.ini +++ /dev/null @@ -1,14 +0,0 @@ -[server] - -hosts = localhost:5232, radicale:5232 - -[auth] - -type = htpasswd -htpasswd_filename = /etc/radicale/users/.htpasswd -htpasswd_encryption = bcrypt - -[storage] - -filesystem_folder = /data/collections -hook = git add -A && (git diff --cached --quiet || git commit -m "Changes by \"%(user)s\"") diff --git a/services/radicale/fs/etc/radicale/conf.ini b/services/radicale/fs/etc/radicale/conf.ini new file mode 100644 index 0000000..2af4af9 --- /dev/null +++ b/services/radicale/fs/etc/radicale/conf.ini @@ -0,0 +1,14 @@ +[server] + +hosts = localhost:5232, radicale:5232 + +[auth] + +type = htpasswd +htpasswd_filename = /etc/radicale/users/.htpasswd +htpasswd_encryption = bcrypt + +[storage] + +filesystem_folder = /data/collections +hook = git add -A && (git diff --cached --quiet || git commit -m "Changes by \"%(user)s\"") diff --git a/services/radicale/fs/sbin/cmd.sh b/services/radicale/fs/sbin/cmd.sh new file mode 100755 index 0000000..4d09e75 --- /dev/null +++ b/services/radicale/fs/sbin/cmd.sh @@ -0,0 +1,33 @@ +#!/bin/sh +set -eu + +conf=/etc/radicale/conf.ini + +if [ ! -d /data/collections/.git ]; then + # Initialize git repository (for storage) + echo "Starting server..." + /venv/bin/radicale --config "$conf" --logging-level error & + radicale_pid=$! + echo "Waiting for server to start..." + until curl -sf http://127.0.0.1:5232; do sleep 1; done + echo "Server started" + + cd /data/collections + git init --initial-branch=radicale + git config user.name radicale + git config user.email radicale@domain.tld + cat <.gitignore +.Radicale.cache +.Radicale.lock +.Radicale.tmp-* +EOF + git add -A && (git diff --cached --quiet || git commit -m "Initialization commit") + + echo "Restarting server..." + kill "$radicale_pid" + wait "$radicale_pid" +else + echo "Initialization skipped" +fi + +exec /venv/bin/radicale --config "$conf" diff --git a/services/radicale/sbin/cmd.sh b/services/radicale/sbin/cmd.sh deleted file mode 100755 index 4d09e75..0000000 --- a/services/radicale/sbin/cmd.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -set -eu - -conf=/etc/radicale/conf.ini - -if [ ! -d /data/collections/.git ]; then - # Initialize git repository (for storage) - echo "Starting server..." - /venv/bin/radicale --config "$conf" --logging-level error & - radicale_pid=$! - echo "Waiting for server to start..." - until curl -sf http://127.0.0.1:5232; do sleep 1; done - echo "Server started" - - cd /data/collections - git init --initial-branch=radicale - git config user.name radicale - git config user.email radicale@domain.tld - cat <.gitignore -.Radicale.cache -.Radicale.lock -.Radicale.tmp-* -EOF - git add -A && (git diff --cached --quiet || git commit -m "Initialization commit") - - echo "Restarting server..." - kill "$radicale_pid" - wait "$radicale_pid" -else - echo "Initialization skipped" -fi - -exec /venv/bin/radicale --config "$conf" diff --git a/tools/build b/tools/build deleted file mode 100755 index 09d7734..0000000 --- a/tools/build +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/bash - -for srv in nginx radicale; do - tar -czf services/"$srv"/fs.tar.gz -C services/"$srv" . -done diff --git a/tools/generate_self_signed_cert b/tools/generate_self_signed_cert deleted file mode 100755 index b25cdb3..0000000 --- a/tools/generate_self_signed_cert +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/bash - -# Creates a self-signed key/certificate pair for a domain and subdomain(s) -# Usage: -# build [...] - -domain=${1:?missing domain argument} -shift -subdomains=("$@") - -mkcert -install -mkcert "${subdomains[@]/%/.$domain}" "$domain" diff --git a/tools/net_services b/tools/net_services new file mode 100755 index 0000000..64a4fb5 --- /dev/null +++ b/tools/net_services @@ -0,0 +1,76 @@ +#!/usr/bin/bash +set -euo pipefail + +script_dir="$(dirname "$(realpath "$0")")" +root_dir="$(realpath "$script_dir/..")" + +env_file="$script_dir/../.env" +if ! [[ -r "$env_file" ]]; then + echo "$env_file is missing" >&2 + exit 1 +fi +# shellcheck disable=1090 +source "$env_file" + +init() { + for service in nginx radicale; do + tar -czf "$root_dir/services/$service/fs.tar.gz" -C "$root_dir/services/$service/fs" . + done + + local -a dirs=( + HOST__SECRET_DIR + HOST__GIT_REPO_DIR + HOST__CGITRC_DIR + HOST__CGIT_FILTER_DIR + HOST__CGIT_ABOUT_DIR + HOST__RADICALE_USERS_DIR + HOST__SYNC_DIR + ) + for envvar_name in "${dirs[@]}"; do + local -n dir="$envvar_name" + mkdir --parents "$dir" + done + + # generate_self_signed_cert [...] + generate_self_signed_cert() { + local crt_dst=${1:?missing crt_dst argument} + local key_dst=${2:?missing key_dst argument} + local domain=${3:?missing domain argument} + shift 3 + local -a subdomains=("$@") + mkcert -install + mkcert -cert-file "$crt_dst" -key-file "$key_dst" "${subdomains[@]/%/.$domain}" "$domain" + } + local crt_file="$HOST__SECRET_DIR/server.crt" + local key_file="$HOST__SECRET_DIR/server.key" + if ! [[ -e "$crt_file" && -e "$key_file" ]]; then + echo "$crt_file or $key_file missing" + read -rn 1 -p "Create? (y/n)" input + echo + if [[ $input == y ]]; then + generate_self_signed_cert "$crt_file" "$key_file" "$NGINX__HOST" www git sync dav + fi + fi + + if ! [[ -e "$HOST__RADICALE_USERS_DIR/.htpasswd" ]]; then + read -rp "Initial Radicale username: " username + htpasswd -c -B "$HOST__RADICALE_USERS_DIR/.htpasswd" "$username" + fi + + cp_if_absent() { + local src="${1:?missing src argument}" + local dst="${2:?missing dst argument}" + if ! [[ -e "$dst" ]]; then cp "$src" "$dst"; fi + } + cp_if_absent "$root_dir/services/cgit/examples/cgitrc" "$HOST__CGITRC_DIR/cgitrc" + cp_if_absent "$root_dir/services/cgit/examples/about.md" "$HOST__CGIT_ABOUT_DIR/about.md" + cp_if_absent "$root_dir/services/cgit/examples/commit-filter.sh" "$HOST__CGIT_FILTER_DIR/commit-filter.sh" +} + +case ${1:-} in +init) init ;; +*) + echo "usage: net_services init" + exit 1 + ;; +esac -- cgit v1.3.1