From 353e050a39708f9307dd3b9dd9105c0d7a8e8d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Borov=C4=8Danin?= Date: Wed, 20 May 2026 19:23:19 +0200 Subject: [PATCH] NOISSUE - Add a fast Certbot startup (#3517) Signed-off-by: dusan --- Makefile | 13 +- docker/.env | 9 + docker/README.md | 69 ++++++- docker/docker-compose.yaml | 59 ++++++ docker/nginx/nginx-key.conf | 9 + docker/nginx/nginx-x509.conf | 9 + docker/nginx/snippets/proxy-headers.conf | 2 + docker/nginx/snippets/ui-proxy.conf | 5 + docker/setup-tls.sh | 242 +++++++++++++++++++++++ docker/ssl/.gitignore | 2 + 10 files changed, 411 insertions(+), 8 deletions(-) create mode 100644 docker/nginx/snippets/ui-proxy.conf create mode 100755 docker/setup-tls.sh diff --git a/Makefile b/Makefile index 92f625d67..04e827f4a 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,7 @@ FILTERED_SERVICES = $(filter-out $(RUN_ADDON_ARGS), $(SERVICES)) all: $(SERVICES) -.PHONY: all $(SERVICES) dockers dockers_dev latest release run_latest run_stable run_addons grpc_mtls_certs check_mtls check_certs test_api mocks +.PHONY: all $(SERVICES) dockers dockers_dev latest release run_latest run_tls run_stable run_addons grpc_mtls_certs check_mtls check_certs test_api mocks clean: rm -rf ${BUILD_DIR} @@ -293,6 +293,17 @@ run_latest: check_certs $(SED_INPLACE) 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=latest/' docker/.env $(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args) +run_tls: + @test -n "$(host)" || (echo "Usage: make run_tls host=example.com [email=admin@example.com] [letsencrypt=false] [staging=false] [force=true]" && exit 2) + @if [ "$(or $(letsencrypt),true)" != "false" ] && [ -z "$(email)" ]; then echo "Usage: make run_tls host=example.com email=admin@example.com [letsencrypt=false] [staging=false] [force=true]"; exit 2; fi + MG_PUBLIC_HOST="$(host)" \ + MG_LETSENCRYPT_ENABLED="$(or $(letsencrypt),true)" \ + MG_LETSENCRYPT_EMAIL="$(email)" \ + MG_LETSENCRYPT_STAGING="$(or $(staging),true)" \ + MG_LETSENCRYPT_FORCE_RENEWAL="$(or $(force),false)" \ + DOCKER_PROJECT="$(DOCKER_PROJECT)" \ + ./docker/setup-tls.sh + run_stable: check_certs $(eval version = $(shell git describe --abbrev=0 --tags)) git checkout $(version) diff --git a/docker/.env b/docker/.env index bb23adb48..8c1a94ce9 100644 --- a/docker/.env +++ b/docker/.env @@ -7,12 +7,21 @@ GRPC_MTLS= ## NginX +MG_PUBLIC_HOST=localhost +MG_UI_HOST=ui +MG_LETSENCRYPT_ENABLED=false +MG_LETSENCRYPT_EMAIL= +MG_LETSENCRYPT_STAGING=true +MG_LETSENCRYPT_FORCE_RENEWAL=false MG_NGINX_HTTP_PORT=80 MG_NGINX_SSL_PORT=443 MG_NGINX_MQTT_PORT=1883 MG_NGINX_MQTTS_PORT=8883 MG_NGINX_AMQP_PORT=5682 MG_NGINX_SERVER_NAME= +# After issuing a Let's Encrypt certificate, uncomment these paths and restart nginx. +# MG_NGINX_SERVER_CERT=./ssl/letsencrypt/live/${MG_PUBLIC_HOST}/fullchain.pem +# MG_NGINX_SERVER_KEY=./ssl/letsencrypt/live/${MG_PUBLIC_HOST}/privkey.pem ## FluxMQ Cluster MG_FLUXMQ_IMAGE_TAG=latest diff --git a/docker/README.md b/docker/README.md index 937e5af63..45ba2aef6 100644 --- a/docker/README.md +++ b/docker/README.md @@ -129,16 +129,71 @@ services: Nginx is the entry point for all traffic to Magistrala. By using environment variables file at `docker/.env` you can modify the below given Nginx directive. -| Environment Variable | Description | -|----------------------|-------------| -| `MG_NGINX_SERVER_NAME` | `MG_NGINX_SERVER_NAME` environmental variable is used to configure nginx directive `server_name`. If environmental variable `MG_NGINX_SERVER_NAME` is empty then default value `localhost` will set to `server_name`. | -| `MG_NGINX_SERVER_CERT` | `MG_NGINX_SERVER_CERT` environmental variable is used to configure nginx directive `ssl_certificate`. If environmental variable `MG_NGINX_SERVER_CERT` is empty then by default server certificate in the path `docker/ssl/certs/magistrala-server.crt` will be assigned. | -| `MG_NGINX_SERVER_KEY` | `MG_NGINX_SERVER_KEY` environmental variable is used to configure nginx directive `ssl_certificate_key`. If environmental variable `MG_NGINX_SERVER_KEY` is empty then by default server certificate key in the path `docker/ssl/certs/magistrala-server.key` will be assigned. | -| `MG_NGINX_SERVER_CLIENT_CA` | `MG_NGINX_SERVER_CLIENT_CA` environmental variable is used to configure nginx directive `ssl_client_certificate`. If environmental variable `MG_NGINX_SERVER_CLIENT_CA` is empty then by default certificate in the path `docker/ssl/certs/ca.crt` will be assigned. | -| `MG_NGINX_SERVER_DHPARAM` | `MG_NGINX_SERVER_DHPARAM` environmental variable is used to configure nginx directive `ssl_dhparam`. If environmental variable `MG_NGINX_SERVER_DHPARAM` is empty then by default file in the path `docker/ssl/dhparam.pem` will be assigned. | +| Environment Variable | Description | +| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `MG_PUBLIC_HOST` | Public DNS name for the Docker host. This value is used by UI URLs and Let's Encrypt certificate requests. | +| `MG_UI_HOST` | Internal Compose hostname for the UI service. Defaults to `ui`. | +| `MG_LETSENCRYPT_ENABLED` | Set to `true` to request and use a Let's Encrypt certificate. Set to `false` to comment out the Let's Encrypt cert/key paths and use the fallback Nginx certificate. | +| `MG_LETSENCRYPT_EMAIL` | Email address used by Let's Encrypt for expiry and account notifications. Required when running the `letsencrypt` profile. | +| `MG_LETSENCRYPT_STAGING` | Set to `true` to request staging certificates while testing. Set to `false` for trusted production certificates. | +| `MG_LETSENCRYPT_FORCE_RENEWAL` | Set to `true` for one certbot run when replacing a staging certificate with a production certificate. Set it back to `false` after the production certificate is issued. | +| `MG_NGINX_SERVER_NAME` | `MG_NGINX_SERVER_NAME` environmental variable is used to configure nginx directive `server_name`. If environmental variable `MG_NGINX_SERVER_NAME` is empty then default value `localhost` will set to `server_name`. | +| `MG_NGINX_SERVER_CERT` | `MG_NGINX_SERVER_CERT` environmental variable is used to configure nginx directive `ssl_certificate`. If environmental variable `MG_NGINX_SERVER_CERT` is empty then by default server certificate in the path `docker/ssl/certs/magistrala-server.crt` will be assigned. | +| `MG_NGINX_SERVER_KEY` | `MG_NGINX_SERVER_KEY` environmental variable is used to configure nginx directive `ssl_certificate_key`. If environmental variable `MG_NGINX_SERVER_KEY` is empty then by default server certificate key in the path `docker/ssl/certs/magistrala-server.key` will be assigned. | +| `MG_NGINX_SERVER_CLIENT_CA` | `MG_NGINX_SERVER_CLIENT_CA` environmental variable is used to configure nginx directive `ssl_client_certificate`. If environmental variable `MG_NGINX_SERVER_CLIENT_CA` is empty then by default certificate in the path `docker/ssl/certs/ca.crt` will be assigned. | +| `MG_NGINX_SERVER_DHPARAM` | `MG_NGINX_SERVER_DHPARAM` environmental variable is used to configure nginx directive `ssl_dhparam`. If environmental variable `MG_NGINX_SERVER_DHPARAM` is empty then by default file in the path `docker/ssl/dhparam.pem` will be assigned. | Adjust these values in `.env` to configure TLS / SSL behavior for your deployment. +### HTTPS UI with Let's Encrypt + +The Compose stack can request and renew a Let's Encrypt certificate with the optional `letsencrypt` profile. This secures the public Nginx entrypoint and serves the UI through `https://${MG_PUBLIC_HOST}/`. Plain UI requests to `/` are redirected to HTTPS, while API and messaging routes keep their existing protocol behavior. Certbot stores challenge files and issued certificates under ignored local paths in `docker/ssl/`. + +Prerequisites: + +- `MG_PUBLIC_HOST` must resolve to the Docker host. +- Ports `80` and `443` must be reachable from the public internet. +- Set `MG_LETSENCRYPT_EMAIL` before requesting a certificate. + +For a staging certificate, run one command from the project root: + +```bash +make run_tls host=example.com email=admin@example.com +``` + +For a trusted production certificate, set `staging=false`: + +```bash +make run_tls host=example.com email=admin@example.com staging=false +``` + +The target updates `docker/.env`, starts the Compose stack with the fallback certificate, runs certbot, switches Nginx to the issued certificate, and recreates Nginx. It also sets `MG_UI_DOCKER_ACCEPT_EULA=yes` for the UI container and configures public UI URLs to `https://${MG_PUBLIC_HOST}`. + +To configure the same instance without Let's Encrypt, use: + +```bash +make run_tls host=example.com letsencrypt=false +``` + +That command updates `docker/.env`, comments out `MG_NGINX_SERVER_CERT` and `MG_NGINX_SERVER_KEY`, stops certbot if it exists, and runs the stack with the fallback Nginx certificate. + +If you are replacing an existing valid certificate and want certbot to request a new one immediately, pass `force=true`: + +```bash +make run_tls host=example.com email=admin@example.com staging=false force=true +``` + +The generated certificate paths in `docker/.env` are: + +```env +MG_NGINX_SERVER_CERT=./ssl/letsencrypt/live//fullchain.pem +MG_NGINX_SERVER_KEY=./ssl/letsencrypt/live//privkey.pem +``` + +The setup script comments or uncomments those values automatically. Operators should not need to edit them by hand. + +The certbot service keeps running and checks renewal twice a day. When a certificate is renewed, it sends a `HUP` signal to the Nginx process so new TLS handshakes use the renewed certificate. + ## Makefile Integration The included `Makefile` defines build and Docker‑build targets for all Magistrala services. Key points: diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index dcfa1143a..ffc422d3d 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -525,6 +525,8 @@ services: - type: bind source: ${MG_NGINX_SERVER_DHPARAM:-./ssl/dhparam.pem} target: /etc/ssl/certs/dhparam.pem + - ./ssl/letsencrypt:/etc/letsencrypt:ro + - ./ssl/certbot-www:/var/www/certbot:ro ports: - ${MG_NGINX_HTTP_PORT}:${MG_NGINX_HTTP_PORT} - ${MG_NGINX_SSL_PORT}:${MG_NGINX_SSL_PORT} @@ -544,6 +546,63 @@ services: soft: 65536 hard: 65536 + certbot: + image: docker.io/certbot/certbot:v2.11.0 + container_name: magistrala-certbot + profiles: + - letsencrypt + depends_on: + - nginx + pid: "service:nginx" + restart: unless-stopped + env_file: + - .env + volumes: + - ./ssl/letsencrypt:/etc/letsencrypt + - ./ssl/certbot-www:/var/www/certbot + entrypoint: /bin/sh + command: + - -c + - | + if [ -z "$${MG_PUBLIC_HOST}" ] || [ "$${MG_PUBLIC_HOST}" = "localhost" ]; then + echo "Set MG_PUBLIC_HOST to a public DNS name before requesting a Let's Encrypt certificate." >&2 + exit 1 + fi + if [ -z "$${MG_LETSENCRYPT_EMAIL}" ]; then + echo "Set MG_LETSENCRYPT_EMAIL before requesting a Let's Encrypt certificate." >&2 + exit 1 + fi + + staging_arg="" + if [ "$${MG_LETSENCRYPT_STAGING}" = "true" ]; then + staging_arg="--staging" + fi + renewal_arg="--keep-until-expiring" + if [ "$${MG_LETSENCRYPT_FORCE_RENEWAL}" = "true" ]; then + renewal_arg="--force-renewal" + fi + + certbot certonly \ + --webroot \ + --webroot-path /var/www/certbot \ + --domain "$${MG_PUBLIC_HOST}" \ + --email "$${MG_LETSENCRYPT_EMAIL}" \ + --agree-tos \ + --no-eff-email \ + --non-interactive \ + $${renewal_arg} \ + $${staging_arg} + + while :; do + certbot renew \ + --webroot \ + --webroot-path /var/www/certbot \ + --quiet \ + --deploy-hook "kill -HUP 1" \ + $${staging_arg} + sleep 12h & wait $$! + done + clients-db: image: docker.io/postgres:18.0-alpine3.22 container_name: magistrala-clients-db diff --git a/docker/nginx/nginx-key.conf b/docker/nginx/nginx-key.conf index 6a28cb232..4747d9358 100644 --- a/docker/nginx/nginx-key.conf +++ b/docker/nginx/nginx-key.conf @@ -71,6 +71,12 @@ http { add_header Access-Control-Allow-Methods '*'; add_header Access-Control-Allow-Headers '*'; + location ^~ /.well-known/acme-challenge/ { + root /var/www/certbot; + default_type text/plain; + try_files $uri =404; + } + # Proxy pass to auth service location ~ ^/(pats) { include snippets/proxy-headers.conf; @@ -156,6 +162,9 @@ http { include snippets/ws-upgrade.conf; proxy_pass http://mqtt_ws_cluster; } + + # UI proxy – populated by docker/setup-tls.sh; empty = no catch-all (local dev) + include snippets/ui-proxy.conf; } } diff --git a/docker/nginx/nginx-x509.conf b/docker/nginx/nginx-x509.conf index 58521cfe0..8e4f0aafd 100644 --- a/docker/nginx/nginx-x509.conf +++ b/docker/nginx/nginx-x509.conf @@ -80,6 +80,12 @@ http { add_header Access-Control-Allow-Methods '*'; add_header Access-Control-Allow-Headers '*'; + location ^~ /.well-known/acme-challenge/ { + root /var/www/certbot; + default_type text/plain; + try_files $uri =404; + } + # Proxy pass to auth service location ~ ^/(pats) { include snippets/proxy-headers.conf; @@ -168,6 +174,9 @@ http { include snippets/ws-upgrade.conf; proxy_pass http://mqtt_ws_cluster; } + + # UI proxy – populated by docker/setup-tls.sh; empty = no catch-all (local dev) + include snippets/ui-proxy.conf; } } diff --git a/docker/nginx/snippets/proxy-headers.conf b/docker/nginx/snippets/proxy-headers.conf index 4183c4750..4b11cc591 100644 --- a/docker/nginx/snippets/proxy-headers.conf +++ b/docker/nginx/snippets/proxy-headers.conf @@ -3,6 +3,8 @@ proxy_redirect off; proxy_set_header Host $host; +proxy_set_header X-Forwarded-Host $host; +proxy_set_header X-Forwarded-Port $server_port; 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/docker/nginx/snippets/ui-proxy.conf b/docker/nginx/snippets/ui-proxy.conf new file mode 100644 index 000000000..05d822da1 --- /dev/null +++ b/docker/nginx/snippets/ui-proxy.conf @@ -0,0 +1,5 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 +# +# This file is written by docker/setup-tls.sh for TLS deployments. +# It is intentionally empty for local development (make run_latest). diff --git a/docker/setup-tls.sh b/docker/setup-tls.sh new file mode 100755 index 000000000..71a807e58 --- /dev/null +++ b/docker/setup-tls.sh @@ -0,0 +1,242 @@ +#!/usr/bin/env sh +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -eu + +ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +ENV_FILE="$ROOT_DIR/docker/.env" +COMPOSE_FILE="$ROOT_DIR/docker/docker-compose.yaml" + +HOST=${MG_PUBLIC_HOST:-} +EMAIL=${MG_LETSENCRYPT_EMAIL:-} +LETSENCRYPT_ENABLED=${MG_LETSENCRYPT_ENABLED:-true} +STAGING=${MG_LETSENCRYPT_STAGING:-true} +FORCE_RENEWAL=${MG_LETSENCRYPT_FORCE_RENEWAL:-false} +PROJECT=${DOCKER_PROJECT:-magistrala} +TIMEOUT_SECONDS=${MG_LETSENCRYPT_TIMEOUT_SECONDS:-180} + +usage() { + cat <&2 + exit 2 +fi + +case "$LETSENCRYPT_ENABLED" in + true|false) + ;; + *) + echo "MG_LETSENCRYPT_ENABLED must be true or false." >&2 + exit 2 + ;; +esac + +if [ "$LETSENCRYPT_ENABLED" = "true" ] && [ -z "$EMAIL" ]; then + usage >&2 + exit 2 +fi + +if [ "$LETSENCRYPT_ENABLED" = "true" ] && [ "$HOST" = "localhost" ]; then + echo "MG_PUBLIC_HOST must be a public DNS name, not localhost." >&2 + exit 2 +fi + +if [ ! -f "$ENV_FILE" ]; then + echo "Missing $ENV_FILE" >&2 + exit 1 +fi + +set_env() { + key=$1 + value=$2 + tmp=$(mktemp) + awk -v key="$key" -v value="$value" ' + BEGIN { done = 0 } + !done && (index($0, key "=") == 1 || index($0, "#" key "=") == 1) { + print key "=" value + done = 1 + next + } + { print } + END { + if (!done) { + print key "=" value + } + } + ' "$ENV_FILE" > "$tmp" + mv "$tmp" "$ENV_FILE" +} + +comment_env() { + key=$1 + value=$2 + tmp=$(mktemp) + awk -v key="$key" -v value="$value" ' + BEGIN { done = 0 } + !done && (index($0, key "=") == 1 || index($0, "# " key "=") == 1 || index($0, "#" key "=") == 1) { + print "# " key "=" value + done = 1 + next + } + { print } + END { + if (!done) { + print "# " key "=" value + } + } + ' "$ENV_FILE" > "$tmp" + mv "$tmp" "$ENV_FILE" +} + +compose() { + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT" "$@" +} + +write_ui_proxy() { + ui_host=${MG_UI_HOST:-ui} + cat > "$ROOT_DIR/docker/nginx/snippets/ui-proxy.conf" </dev/null 2>&1; then + return 0 + fi + + elapsed=0 + while [ "$elapsed" -lt "$TIMEOUT_SECONDS" ]; do + status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 \ + http://127.0.0.1/.well-known/acme-challenge/magistrala-tls-probe 2>/dev/null || true) + case "$status" in + 200|301|302|307|308|404) + return 0 + ;; + esac + sleep 2 + elapsed=$((elapsed + 2)) + done + + echo "Timed out waiting for Nginx to accept HTTP traffic." >&2 + docker logs --tail 80 magistrala-nginx >&2 || true + exit 1 +} + +cert_path="./ssl/letsencrypt/live/$HOST/fullchain.pem" +key_path="./ssl/letsencrypt/live/$HOST/privkey.pem" +cert_file="$ROOT_DIR/docker/ssl/letsencrypt/live/$HOST/fullchain.pem" +key_file="$ROOT_DIR/docker/ssl/letsencrypt/live/$HOST/privkey.pem" + +if [ "$LETSENCRYPT_ENABLED" = "false" ]; then + FORCE_RENEWAL=false +fi + +if [ "$LETSENCRYPT_ENABLED" = "true" ] && [ "$STAGING" = "false" ] && [ -f "$cert_file" ]; then + if openssl x509 -in "$cert_file" -noout -issuer 2>/dev/null | grep -q "STAGING"; then + FORCE_RENEWAL=true + fi +fi + +echo "Configuring docker/.env for $HOST" +set_env MG_RELEASE_TAG latest +set_env MG_PUBLIC_HOST "$HOST" +set_env MG_UI_HOST "${MG_UI_HOST:-ui}" +set_env MG_LETSENCRYPT_ENABLED "$LETSENCRYPT_ENABLED" +set_env MG_LETSENCRYPT_EMAIL "$EMAIL" +set_env MG_LETSENCRYPT_STAGING "$STAGING" +set_env MG_LETSENCRYPT_FORCE_RENEWAL "$FORCE_RENEWAL" +set_env MG_NGINX_SERVER_NAME "$HOST" +comment_env MG_NGINX_SERVER_CERT "$cert_path" +comment_env MG_NGINX_SERVER_KEY "$key_path" +set_env MG_UI_DOCKER_ACCEPT_EULA yes + +set_env MG_OAUTH_UI_REDIRECT_URL "https://$HOST/api/auth/token" +set_env MG_OAUTH_UI_ERROR_URL "https://$HOST/login" +set_env MG_PASSWORD_RESET_URL_PREFIX "https://$HOST/password-reset" +set_env MG_VERIFICATION_URL_PREFIX "https://$HOST/verify-email" +set_env MG_GOOGLE_REDIRECT_URL "https://$HOST/oauth/callback/google" +set_env NEXTAUTH_URL "https://$HOST" +set_env MG_HOST_URL "https://$HOST" +set_env MG_UI_BASEURL "https://$HOST" +set_env MG_UI_CLI_MQTT_HOST "$HOST" +set_env MG_UI_CLI_WS_URL "wss://$HOST/mqtt" +set_env MG_UI_CLI_COAP_HOST "$HOST" +set_env MG_UI_CLI_HTTP_URL "https://$HOST/http" + +mkdir -p "$ROOT_DIR/docker/ssl/letsencrypt" "$ROOT_DIR/docker/ssl/certbot-www" + +write_ui_proxy + +if [ "$LETSENCRYPT_ENABLED" = "false" ]; then + echo "Starting Magistrala with the fallback Nginx certificate" + MG_UI_DOCKER_ACCEPT_EULA=yes compose up -d + MG_UI_DOCKER_ACCEPT_EULA=yes COMPOSE_PROFILES=letsencrypt compose stop certbot >/dev/null 2>&1 || true + echo "Let's Encrypt disabled. Nginx cert/key paths are commented in docker/.env." + echo "Fallback TLS setup complete: https://$HOST/" + exit 0 +fi + +echo "Starting Magistrala with the fallback Nginx certificate" +MG_UI_DOCKER_ACCEPT_EULA=yes compose up -d +wait_for_nginx_http + +echo "Requesting Let's Encrypt certificate for $HOST" +MG_UI_DOCKER_ACCEPT_EULA=yes COMPOSE_PROFILES=letsencrypt compose up -d --force-recreate certbot + +elapsed=0 +while [ "$elapsed" -lt "$TIMEOUT_SECONDS" ]; do + if [ -s "$cert_file" ] && [ -s "$key_file" ]; then + break + fi + sleep 2 + elapsed=$((elapsed + 2)) +done + +if [ ! -s "$cert_file" ] || [ ! -s "$key_file" ]; then + echo "Timed out waiting for Let's Encrypt certificate files." >&2 + docker logs --tail 80 magistrala-certbot >&2 || true + exit 1 +fi + +echo "Switching Nginx to the issued certificate" +set_env MG_NGINX_SERVER_CERT "$cert_path" +set_env MG_NGINX_SERVER_KEY "$key_path" +set_env MG_LETSENCRYPT_FORCE_RENEWAL false + +MG_UI_DOCKER_ACCEPT_EULA=yes compose up -d --force-recreate nginx + +echo "TLS setup complete: https://$HOST/" diff --git a/docker/ssl/.gitignore b/docker/ssl/.gitignore index 28e5ba20a..d6931c5d9 100644 --- a/docker/ssl/.gitignore +++ b/docker/ssl/.gitignore @@ -7,3 +7,5 @@ *conf client.crt client.key +certbot-www/ +letsencrypt/