From e92a7e2e62d4d477150060365dbcfd591d66702b Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Sun, 17 Aug 2025 21:43:59 +0200 Subject: [PATCH] Some update --- .gitignore | 4 +- .vscode/settings.json | 76 ------------------- Containerfile | 9 +-- README.md | 28 ++++--- docker-compose.yml | 5 +- docker-entrypoint.d/1-check-environment.sh | 17 +++++ docker-entrypoint.d/10-generate-templates.sh | 14 ++++ .../10-initialize-certificates.sh | 29 ------- .../5-initialize-certificates.sh | 23 ++++++ docker-entrypoint.d/50-control-server.sh | 2 + nginx/nginx.conf | 6 +- nginx/templates/control.conf.template | 6 ++ ...t.conf.template => website.conf.btemplate} | 3 +- 13 files changed, 94 insertions(+), 128 deletions(-) delete mode 100644 .vscode/settings.json create mode 100644 docker-entrypoint.d/1-check-environment.sh create mode 100644 docker-entrypoint.d/10-generate-templates.sh delete mode 100755 docker-entrypoint.d/10-initialize-certificates.sh create mode 100755 docker-entrypoint.d/5-initialize-certificates.sh rename nginx/templates/{default.conf.template => website.conf.btemplate} (84%) diff --git a/.gitignore b/.gitignore index d22488c..ef49361 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -run/ -control-server/build/ \ No newline at end of file +/run/ +/control-server/build/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e1cc80d..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "files.associations": { - "ostream": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "cctype": "cpp", - "charconv": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "codecvt": "cpp", - "compare": "cpp", - "concepts": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "ratio": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "format": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "new": "cpp", - "numbers": "cpp", - "ranges": "cpp", - "span": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "typeinfo": "cpp", - "variant": "cpp", - "text_encoding": "cpp", - "queue": "cpp", - "filesystem": "cpp", - "any": "cpp", - "condition_variable": "cpp", - "coroutine": "cpp", - "source_location": "cpp", - "future": "cpp", - "mutex": "cpp", - "stop_token": "cpp", - "thread": "cpp", - "list": "cpp", - "semaphore": "cpp", - "stdfloat": "cpp", - "fstream": "cpp" - } -} \ No newline at end of file diff --git a/Containerfile b/Containerfile index a77fb5d..42399b8 100644 --- a/Containerfile +++ b/Containerfile @@ -24,12 +24,11 @@ RUN mkdir -p build \ FROM docker.io/nginx:${NGINX_TAG} -ENV DOMAIN="example.localhost" +#ENV DOMAIN="example.localhost" ENV SERVER_ID="server" -ENV RELOAD_FILE="/var/run/nginx-reload" -ENV ACME_CHALLENGE_URL="http://acme-challenge.${DOMAIN}/.well-known/acme-challenge/" -ENV CONTROL_DOMAIN="control.localhost" -ENV CONTROL_TOKEN="Tr0ub4dor&3" +ENV ACME_CHALLENGE_URL='http://acme-challenge.${DOMAIN}/.well-known/acme-challenge' +#ENV CONTROL_DOMAIN="control.localhost" +#ENV CONTROL_TOKEN="Tr0ub4dor&3" COPY nginx /etc/nginx/ COPY certificates /etc/ssl/ diff --git a/README.md b/README.md index 441d135..792a077 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,30 @@ -This is a container that helps host a static website. +This is a container that helps host a website. ## Configuration **Requires** the following mounts: -- `/etc/ssl/certs/$DOMAIN`: For certificates (`fullchain.pem` and `privkey.pem`) -- `/var/www/html/$DOMAIN`: Website files, `index.html` goes right here +- `/etc/ssl/certs/`: For certificates, `fullchain.pem` and `privkey.pem`. Also includes the control domain. Can be read-only if you don't use the built-in (control server) certificate management. +- `/var/www/html/`: Website files, `index.html` goes right here, mount this read-only **Requires** the following environment variables: -- `DOMAIN`: The domain -- `ACME_CHALLENGE_HOST`: The source of `.well-known/acme-challenge` +- `DOMAINS`: One or more domains to handle, separated with `,`s or spaces +- `ACME_CHALLENGE_HOST`: The source of `.well-known/acme-challenge`. Proxied, may be internal. Don't forget to add +- `CONTROL_DOMAIN`: Domain to access the control server - `CONTROL_TOKEN`: Token to access the control server You're also encouraged to provide your own: -- `/etc/ssl/dhparam.pem`, generated with: +- `/etc/ssl/dhparam.pem` (read-only), generated with: ```bash openssl dhparam -out dhparam.pem 4096 ``` -- `/etc/ssl/snakeoil.key` & `/etc/ssl/snakeoil.pem`, generated with: +- `/etc/ssl/snakeoil.key` (read-only) & `/etc/ssl/snakeoil.pem` (read-only), generated with: ```bash openssl req -new -x509 -days 398 -noenc -out snakeoil.pem -keyout snakeoil.key -subj "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd" ``` -- `SERVER_ID`: How to call this server (for info) -- **Mount** `/var/run/nginx-reload`: modify this file to reload nginx +- `SERVER_ID`: Label this server (informational, not used currently) ## Control server -Authorize as you normally would with a Bearer token. +Authorize as you normally do with a Bearer token. If you get an empty response, watch the status code! @@ -41,5 +41,13 @@ Endpoints: - `/reload`: Reloads nginx - `/certificate/`: Uploads a certificate (POST, upload like a form with field names `certificate` and `private_key`) +## Custom nginx configs +Put custom configuration templates in the `/templates/` directory + +Stock config files, mount (read-only) to replace: +- Control: `control.conf.template` ([default](nginx/templates/control.conf.template)) +- Website: `website.conf.btemplate` ([default](nginx/templates/website.conf.template)) (not used hence diff extension) +- Specific website: `website-$DOMAIN.conf.template` (generated) + ## TODO - support for multiple domains \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 893761d..4d0a35e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: context: . dockerfile: Containerfile environment: - DOMAIN: example.localhost + DOMAINS: example.localhost SERVER_ID: development ACME_CHALLENGE_URL: https://files.catbox.moe/xpfyfh CONTROL_DOMAIN: control.localhost @@ -16,4 +16,5 @@ services: volumes: - ./run/html:/var/www/html - ./run/certs:/etc/ssl/certs - - ./run/reload:/var/run/nginx-reload \ No newline at end of file + + \ No newline at end of file diff --git a/docker-entrypoint.d/1-check-environment.sh b/docker-entrypoint.d/1-check-environment.sh new file mode 100644 index 0000000..4365183 --- /dev/null +++ b/docker-entrypoint.d/1-check-environment.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -euo pipefail + +: "${DOMAINS?Error: DOMAINS environment variable is not set.}" +: "${CONTROL_DOMAIN?Error: CONTROL_DOMAIN environment variable is not set.}" +: "${CONTROL_TOKEN?Error: CONTROL_TOKEN environment variable is not set.}" + +for domain in ${DOMAINS//,/ }; do + echo "Detected domain: $domain" + + if [ "$domain" = "$CONTROL_DOMAIN" ]; then + echo "Domain must not equal control domain" + exit 1 + fi +done + diff --git a/docker-entrypoint.d/10-generate-templates.sh b/docker-entrypoint.d/10-generate-templates.sh new file mode 100644 index 0000000..5d5f492 --- /dev/null +++ b/docker-entrypoint.d/10-generate-templates.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -euo pipefail + +if [ -e "/templates" ]; then + cp -r templates/. /etc/nginx/templates/ +fi + +for domain in ${DOMAINS//,/ }; do + cp -n /etc/nginx/templates/website.conf.btemplate /etc/nginx/templates/website-$domain.conf.template + + sed -i "s/\$DOMAIN/$domain/g" /etc/nginx/templates/website-$domain.conf.template + sed -i "s/\${DOMAIN}/$domain/g" /etc/nginx/templates/website-$domain.conf.template +done \ No newline at end of file diff --git a/docker-entrypoint.d/10-initialize-certificates.sh b/docker-entrypoint.d/10-initialize-certificates.sh deleted file mode 100755 index e7a7908..0000000 --- a/docker-entrypoint.d/10-initialize-certificates.sh +++ /dev/null @@ -1,29 +0,0 @@ - -#!/bin/sh - -set -euo pipefail - -: "${DOMAIN?Error: DOMAIN environment variable is not set.}" -: "${CONTROL_DOMAIN?Error: CONTROL_DOMAIN environment variable is not set.}" - -CERTIFICATE_ROOT="/etc/ssl" - -setup_snakeoil_cert() { - local domain="$1" - local cert_dir="$CERTIFICATE_ROOT/certs/$domain" - - mkdir -p "$cert_dir" - - cp -n "$CERTIFICATE_ROOT/snakeoil.pem" "$cert_dir/fullchain.pem" - cp -n "$CERTIFICATE_ROOT/snakeoil.key" "$cert_dir/privkey.pem" - - chmod 644 "$cert_dir/fullchain.pem" - chmod 600 "$cert_dir/privkey.pem" -} - -for domain_to_setup in "$DOMAIN" "$CONTROL_DOMAIN"; do - echo "Ensuring certificate for domain: $domain_to_setup" - setup_snakeoil_cert "$domain_to_setup" -done - -echo "Placeholder certificate setup complete." \ No newline at end of file diff --git a/docker-entrypoint.d/5-initialize-certificates.sh b/docker-entrypoint.d/5-initialize-certificates.sh new file mode 100755 index 0000000..36b78ea --- /dev/null +++ b/docker-entrypoint.d/5-initialize-certificates.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -euo pipefail + +CERTIFICATE_ROOT="/etc/ssl" + +setup_snakeoil_cert() { + local domain="$1" + local cert_dir="$CERTIFICATE_ROOT/certs/$domain" + + mkdir -p "$cert_dir" + + cp -n "$CERTIFICATE_ROOT/snakeoil.key" "$cert_dir/privkey.pem" + cp -n "$CERTIFICATE_ROOT/snakeoil.pem" "$cert_dir/fullchain.pem" + + chmod 600 "$cert_dir/privkey.pem" || true + chmod 600 "$cert_dir/fullchain.pem" || true +} + +for domain in ${DOMAINS//,/ } $CONTROL_DOMAIN; do + echo "Ensuring certificate for domain: $domain" + setup_snakeoil_cert "$domain" +done \ No newline at end of file diff --git a/docker-entrypoint.d/50-control-server.sh b/docker-entrypoint.d/50-control-server.sh index bf15e48..692cbe6 100644 --- a/docker-entrypoint.d/50-control-server.sh +++ b/docker-entrypoint.d/50-control-server.sh @@ -6,4 +6,6 @@ CONTROL_SERVER_SOCKET="/var/run/control-server.sock" NGINX_PID_FILE="/var/run/nginx.pid" CERTIFICATE_PATH="/etc/ssl/certs" +# TODO run this as user + control_server $CONTROL_SERVER_SOCKET $NGINX_PID_FILE $CERTIFICATE_PATH & \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 70c6601..c436a8f 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -13,9 +13,9 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; + # looking for $remote_addr and $http_user_agent? log_format main '$remote_user [$time_local] "$request" ' - '$status $body_bytes_sent bytes "$http_referer" ' - '"$http_x_forwarded_for"'; + '$status $body_bytes_sent bytes "$http_referer" '; access_log /var/log/nginx/access.log main; # /dev/null to disable @@ -57,7 +57,7 @@ http { ssl_stapling_verify on; # async 'resolver' is important for proper operation of OCSP stapling - resolver [2001:4860:4860::8888] 8.8.8.8; + # resolver [2001:4860:4860::8888] 8.8.8.8; # If certificates are marked OCSP Must-Staple, consider managing the # OCSP stapling cache with an external script, e.g. certbot-ocsp-fetcher diff --git a/nginx/templates/control.conf.template b/nginx/templates/control.conf.template index c2414ab..05dfdc8 100644 --- a/nginx/templates/control.conf.template +++ b/nginx/templates/control.conf.template @@ -18,4 +18,10 @@ server { proxy_pass http://unix:/var/run/control-server.sock; } + + location /.well-known/acme-challenge { + set $target ${ACME_CHALLENGE_URL}; + proxy_buffering off; + proxy_pass $target; + } } \ No newline at end of file diff --git a/nginx/templates/default.conf.template b/nginx/templates/website.conf.btemplate similarity index 84% rename from nginx/templates/default.conf.template rename to nginx/templates/website.conf.btemplate index 5ac7e32..c0f452c 100644 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/website.conf.btemplate @@ -13,7 +13,8 @@ server { index index.html; location /.well-known/acme-challenge { + set $target ${ACME_CHALLENGE_URL}; proxy_buffering off; - proxy_pass ${ACME_CHALLENGE_URL}; + proxy_pass $target; } } \ No newline at end of file