diff --git a/Dockerfile b/Dockerfile index 55e3511a87..ec74fbbeb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,13 +29,12 @@ ENV PATH /opt/appsmith/utils/node_modules/.bin:/opt/java/bin:/opt/node/bin:$PATH RUN cd ./utils && npm install --only=prod && npm install --only=prod -g . && cd - \ && chmod 0644 /etc/cron.d/* \ - && chmod +x *.sh templates/nginx-app.conf.sh /watchtower-hooks/*.sh \ + && chmod +x *.sh /watchtower-hooks/*.sh \ # Disable setuid/setgid bits for the files inside container. && find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true \ - && node prepare-image.mjs \ && mkdir -p /.mongodb/mongosh /appsmith-stacks \ && chmod ugo+w /etc /appsmith-stacks \ - && chmod -R ugo+w /var/lib/nginx /var/log/nginx /var/run /usr/sbin/cron /.mongodb /etc/ssl /usr/local/share + && chmod -R ugo+w /var/run /usr/sbin/cron /.mongodb /etc/ssl /usr/local/share LABEL com.centurylinklabs.watchtower.lifecycle.pre-check=/watchtower-hooks/pre-check.sh LABEL com.centurylinklabs.watchtower.lifecycle.pre-update=/watchtower-hooks/pre-update.sh diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/InstanceConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/InstanceConfig.java index 24c22e27ec..6995fd4b3a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/InstanceConfig.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/InstanceConfig.java @@ -31,7 +31,7 @@ public class InstanceConfig implements ApplicationListener "$TMP/nginx-app.conf" - server { - listen ${PORT:-80} default_server; - location / { - try_files \$uri \$uri/ /index.html =404; - } - } -EOF - # Start nginx page to display the Appsmith is Initializing page - nginx - # Update editor nginx page for starting page - cp "$starting_page" "$editor_load_page" + export XDG_DATA_HOME=/appsmith-stacks/data # so that caddy saves tls certs and other data under stacks/data/caddy + export XDG_CONFIG_HOME=/appsmith-stacks/configuration + mkdir -p "$XDG_DATA_HOME" "$XDG_CONFIG_HOME" + cp templates/loading.html "$WWW_PATH" + if [[ -z "${APPSMITH_ALLOWED_FRAME_ANCESTORS-}" ]]; then + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors + export APPSMITH_ALLOWED_FRAME_ANCESTORS="'self'" + else + # Remove any extra rules that may be present in the frame ancestors value. This is to prevent this env variable from + # being used to inject more rules to the CSP header. If needed, that should be supported/solved separately. + export APPSMITH_ALLOWED_FRAME_ANCESTORS="${APPSMITH_ALLOWED_FRAME_ANCESTORS%;*}" + fi + node caddy-reconfigure.mjs + /opt/caddy/caddy start --config "$TMP/Caddyfile" } # Main Section @@ -498,8 +490,5 @@ mkdir -p /appsmith-stacks/data/{backup,restore} # Create sub-directory to store services log in the container mounting folder mkdir -p /appsmith-stacks/logs/{supervisor,backend,cron,editor,rts,mongodb,redis,postgres,appsmithctl} -# Stop nginx gracefully -nginx -s quit - # Handle CMD command exec "$@" diff --git a/deploy/docker/fs/opt/appsmith/init_ssl_cert.sh b/deploy/docker/fs/opt/appsmith/init_ssl_cert.sh deleted file mode 100755 index 2a384a78b5..0000000000 --- a/deploy/docker/fs/opt/appsmith/init_ssl_cert.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -init_ssl_cert() { - APPSMITH_CUSTOM_DOMAIN="$1" - - local rsa_key_size=4096 - local data_path="/appsmith-stacks/data/certificate" - - mkdir -p "$data_path/www" - - echo "Re-generating nginx config template with domain" - /opt/appsmith/templates/nginx-app.conf.sh "0" "$APPSMITH_CUSTOM_DOMAIN" - - echo "Start Nginx to verify certificate" - nginx - - local live_path="/etc/letsencrypt/live/$APPSMITH_CUSTOM_DOMAIN" - local ssl_path="/appsmith-stacks/ssl" - if [[ -e "$ssl_path/fullchain.pem" ]] && [[ -e "$ssl_path/privkey.pem" ]]; then - echo "Existing custom certificate" - echo "Stop Nginx" - nginx -s stop - return - fi - - if [[ -e "$live_path" ]]; then - echo "Existing certificate for domain $APPSMITH_CUSTOM_DOMAIN" - echo "Stop Nginx" - nginx -s stop - return - fi - - echo "Creating certificate for '$APPSMITH_CUSTOM_DOMAIN'" - - echo "Requesting Let's Encrypt certificate for '$APPSMITH_CUSTOM_DOMAIN'..." - echo "Generating OpenSSL key for '$APPSMITH_CUSTOM_DOMAIN'..." - - mkdir -p "$live_path" && openssl req -x509 -nodes -newkey rsa:2048 -days 1 \ - -keyout "$live_path/privkey.pem" \ - -out "$live_path/fullchain.pem" \ - -subj "/CN=localhost" - - echo "Removing key now that validation is done for $APPSMITH_CUSTOM_DOMAIN..." - rm -Rfv /etc/letsencrypt/live/$APPSMITH_CUSTOM_DOMAIN /etc/letsencrypt/archive/$APPSMITH_CUSTOM_DOMAIN /etc/letsencrypt/renewal/$APPSMITH_CUSTOM_DOMAIN.conf - - echo "Generating certification for domain $APPSMITH_CUSTOM_DOMAIN" - mkdir -p "$data_path/certbot" - certbot certonly --webroot --webroot-path="$data_path/certbot" \ - --register-unsafely-without-email \ - --domains $APPSMITH_CUSTOM_DOMAIN \ - --rsa-key-size $rsa_key_size \ - --agree-tos \ - --force-renewal - - if (($? != 0)); then - echo "Stop Nginx due to provisioning fail" - nginx -s stop - return 1 - fi - - echo "Stop Nginx" - nginx -s stop -} diff --git a/deploy/docker/fs/opt/appsmith/prepare-image.mjs b/deploy/docker/fs/opt/appsmith/prepare-image.mjs deleted file mode 100644 index eeced714fe..0000000000 --- a/deploy/docker/fs/opt/appsmith/prepare-image.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import * as fs from "fs/promises"; - -const TMP = process.env.TMP; -const NGINX_WWW_PATH = process.env.NGINX_WWW_PATH; - -async function applyNginxChanges() { - const contents = await fs.readFile("/etc/nginx/nginx.conf", "utf8") - - const modContents = contents - .replace("pid /run/nginx.pid;", `pid ${TMP}/nginx.pid;`) - .replace("# server_tokens off;", "server_tokens off; more_set_headers 'Server: ';") - .replace("gzip on;", "gzip on; gzip_types *;") - .replace("include /etc/nginx/conf.d/*.conf;", [ - "include /etc/nginx/conf.d/*.conf;", - `include ${TMP}/nginx-app.conf;`, - `root ${NGINX_WWW_PATH};`, - ].join("\n")); - - await Promise.all([ - fs.writeFile("/etc/nginx/nginx.conf.original", contents), - fs.writeFile("/etc/nginx/nginx.conf", modContents), - fs.rm("/etc/nginx/sites-enabled", { recursive: true }), - fs.rm("/etc/nginx/conf.d", { recursive: true }), - ]) -} - -await applyNginxChanges(); diff --git a/deploy/docker/fs/opt/appsmith/renew-certificate.sh b/deploy/docker/fs/opt/appsmith/renew-certificate.sh deleted file mode 100644 index 3a4981accb..0000000000 --- a/deploy/docker/fs/opt/appsmith/renew-certificate.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -set -e - -ENV_PATH="/appsmith-stacks/configuration/docker.env" -PRE_DEFINED_ENV_PATH="$TMP/pre-define.env" -if [[ -f /appsmith-stacks/configuration/docker.env ]]; then - echo 'Load environment configuration' - set -o allexport - . "$ENV_PATH" - . "$PRE_DEFINED_ENV_PATH" - set +o allexport -fi - -if [[ -n $APPSMITH_CUSTOM_DOMAIN ]]; then - data_path="/appsmith-stacks/data/certificate" - domain="$APPSMITH_CUSTOM_DOMAIN" - rsa_key_size=4096 - - certbot certonly --webroot --webroot-path="$data_path/certbot" \ - --register-unsafely-without-email \ - --domains $domain \ - --rsa-key-size $rsa_key_size \ - --agree-tos \ - --force-renewal - supervisorctl restart editor -else - echo 'Custom domain not configured. Cannot enable SSL without a custom domain.' >&2 -fi diff --git a/deploy/docker/fs/opt/appsmith/run-caddy.sh b/deploy/docker/fs/opt/appsmith/run-caddy.sh new file mode 100755 index 0000000000..b00d18cb66 --- /dev/null +++ b/deploy/docker/fs/opt/appsmith/run-caddy.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +if [[ -z "${APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX-}" ]]; then + # For backwards compatibility, if this is not set to anything, we default to no sandbox for iframe widgets. + export APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX="true" +fi + +apply-env-vars() { + original="$1" + served="$2" + node -e ' + const fs = require("fs") + const content = fs.readFileSync("'"$original"'", "utf8").replace( + /\b__(APPSMITH_[A-Z0-9_]+)__\b/g, + (placeholder, name) => (process.env[name] || "") + ) + fs.writeFileSync("'"$served"'", content) + ' + pushd "$(dirname "$served")" + gzip --keep --force "$(basename "$served")" + popd +} + +apply-env-vars /opt/appsmith/editor/index.html "$WWW_PATH/index.html" + +node caddy-reconfigure.mjs + +# Caddy may already be running for the loading page. +/opt/caddy/caddy stop --config "$TMP/Caddyfile" || true + +exec /opt/caddy/caddy run --config "$TMP/Caddyfile" diff --git a/deploy/docker/fs/opt/appsmith/run-nginx.sh b/deploy/docker/fs/opt/appsmith/run-nginx.sh deleted file mode 100755 index e89933b8a4..0000000000 --- a/deploy/docker/fs/opt/appsmith/run-nginx.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail -set -o xtrace - -ssl_conf_path="/appsmith-stacks/data/certificate/conf" - -mkdir -pv "$ssl_conf_path" - -cat < "$ssl_conf_path/options-ssl-nginx.conf" -# This file contains important security parameters. If you modify this file -# manually, Certbot will be unable to automatically provide future security -# updates. Instead, Certbot will print and log an error message with a path to -# the up-to-date file that you will need to refer to when manually updating -# this file. - -ssl_session_cache shared:le_nginx_SSL:10m; -ssl_session_timeout 1440m; -ssl_session_tickets off; - -ssl_protocols TLSv1.2 TLSv1.3; -ssl_prefer_server_ciphers off; - -ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; -EOF - -cat < "$ssl_conf_path/ssl-dhparams.pem" ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz -+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a -87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 -YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi -7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD -ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== ------END DH PARAMETERS----- -EOF - -if [[ -z "${APPSMITH_ALLOWED_FRAME_ANCESTORS-}" ]]; then - # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors - export APPSMITH_ALLOWED_FRAME_ANCESTORS="'self'" -else - # Remove any extra rules that may be present in the frame ancestors value. This is to prevent this env variable from - # being used to inject more rules to the CSP header. If needed, that should be supported/solved separately. - export APPSMITH_ALLOWED_FRAME_ANCESTORS="${APPSMITH_ALLOWED_FRAME_ANCESTORS%;*}" -fi - -if [[ -z "${APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX-}" ]]; then - # For backwards compatibility, if this is not set to anything, we default to no sandbox for iframe widgets. - export APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX="true" -fi - -# Check exist certificate with given custom domain -# Heroku not support for custom domain, only generate HTTP config if deploying on Heroku -use_https=0 -if [[ -n ${APPSMITH_CUSTOM_DOMAIN-} ]] && [[ -z ${DYNO-} ]]; then - use_https=1 - if ! [[ -e "/etc/letsencrypt/live/$APPSMITH_CUSTOM_DOMAIN" ]]; then - source "/opt/appsmith/init_ssl_cert.sh" - if ! init_ssl_cert "$APPSMITH_CUSTOM_DOMAIN"; then - echo "Status code from init_ssl_cert is $?" - use_https=0 - fi - fi -fi - -/opt/appsmith/templates/nginx-app.conf.sh "$use_https" "${APPSMITH_CUSTOM_DOMAIN-}" - -cp -r /opt/appsmith/editor/* "$NGINX_WWW_PATH" - -apply-env-vars() { - original="$1" - served="$2" - node -e ' - const fs = require("fs") - const content = fs.readFileSync("'"$original"'", "utf8").replace( - /\b__(APPSMITH_[A-Z0-9_]+)__\b/g, - (placeholder, name) => (process.env[name] || "") - ) - fs.writeFileSync("'"$served"'", content) - ' - pushd "$(dirname "$served")" - gzip --keep --force "$(basename "$served")" - popd -} - -apply-env-vars /opt/appsmith/editor/index.html "$NGINX_WWW_PATH/index.html" - -exec nginx -g "daemon off;error_log stderr info;" diff --git a/deploy/docker/fs/opt/appsmith/run-starting-page-init.sh b/deploy/docker/fs/opt/appsmith/run-starting-page-init.sh index 310d67f18e..78c3c72e1e 100644 --- a/deploy/docker/fs/opt/appsmith/run-starting-page-init.sh +++ b/deploy/docker/fs/opt/appsmith/run-starting-page-init.sh @@ -1,4 +1,4 @@ #!/bin/bash python3 /opt/appsmith/starting-page-init.py -rm -f "$NGINX_WWW_PATH/loading.html" +rm -f "$WWW_PATH/loading.html" diff --git a/deploy/docker/fs/opt/appsmith/starting-page-init.py b/deploy/docker/fs/opt/appsmith/starting-page-init.py index 45fc9cb7ef..3e5c40c0b0 100644 --- a/deploy/docker/fs/opt/appsmith/starting-page-init.py +++ b/deploy/docker/fs/opt/appsmith/starting-page-init.py @@ -9,7 +9,7 @@ import urllib.request LOADING_TEMPLATE_PAGE = r'/opt/appsmith/templates/appsmith_starting.html' -LOADING_PAGE_EDITOR = os.getenv("NGINX_WWW_PATH") + '/loading.html' +LOADING_PAGE_EDITOR = os.getenv("WWW_PATH") + '/loading.html' BACKEND_HEALTH_ENDPOINT = "http://localhost:8080/api/v1/health" LOG_FILE = r'/appsmith-stacks/logs/backend/starting_page_init.log' LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' diff --git a/deploy/docker/fs/opt/appsmith/templates/appsmith_initializing.html b/deploy/docker/fs/opt/appsmith/templates/appsmith_initializing.html deleted file mode 100644 index fba1f0dab2..0000000000 --- a/deploy/docker/fs/opt/appsmith/templates/appsmith_initializing.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - Appsmith - - -
-

- Please wait -

-

Appsmith is initializing. This might take a few minutes.

-
-
- - - - diff --git a/deploy/docker/fs/opt/appsmith/templates/appsmith_starting.html b/deploy/docker/fs/opt/appsmith/templates/loading.html similarity index 92% rename from deploy/docker/fs/opt/appsmith/templates/appsmith_starting.html rename to deploy/docker/fs/opt/appsmith/templates/loading.html index 007a0dfce2..1bac4bb7f3 100644 --- a/deploy/docker/fs/opt/appsmith/templates/appsmith_starting.html +++ b/deploy/docker/fs/opt/appsmith/templates/loading.html @@ -14,10 +14,8 @@
-

- Appsmith is starting. -

-

Please wait until Appsmith is ready. This process usually takes a minute.

+

Appsmith is starting.

+

Please wait until Appsmith is ready. This may take a few minutes.

diff --git a/deploy/docker/fs/opt/appsmith/templates/nginx-app.conf.sh b/deploy/docker/fs/opt/appsmith/templates/nginx-app.conf.sh deleted file mode 100755 index d1644fec3c..0000000000 --- a/deploy/docker/fs/opt/appsmith/templates/nginx-app.conf.sh +++ /dev/null @@ -1,155 +0,0 @@ -#!/bin/bash - -set -o nounset - -use_https="$1" -custom_domain="${2:-_}" - -if [[ $use_https == 1 ]]; then - # By default, container will use the auto-generate certificate by Let's Encrypt - ssl_cert_path="/etc/letsencrypt/live/$custom_domain/fullchain.pem" - ssl_key_path="/etc/letsencrypt/live/$custom_domain/privkey.pem" - - # In case of existing custom certificate, container will use them to configure SSL - if [[ -e "/appsmith-stacks/ssl/fullchain.pem" ]] && [[ -e "/appsmith-stacks/ssl/privkey.pem" ]]; then - ssl_cert_path="/appsmith-stacks/ssl/fullchain.pem" - ssl_key_path="/appsmith-stacks/ssl/privkey.pem" - fi -fi - -additional_downstream_headers=' -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options -add_header X-Content-Type-Options "nosniff"; -' - -cat < "$TMP/nginx-app.conf" -map \$http_x_forwarded_proto \$origin_scheme { - default \$http_x_forwarded_proto; - '' \$scheme; -} - -map \$http_x_forwarded_host \$origin_host { - default \$http_x_forwarded_host; - '' \$host; -} - -map \$http_forwarded \$final_forwarded { - default '\$http_forwarded, host=\$host;proto=\$scheme'; - '' ''; -} - -# redirect log to stdout for supervisor to capture -access_log /dev/stdout; - -server { - -$( -if [[ $use_https == 1 ]]; then - echo " - listen 80; - server_name $custom_domain; - - location /.well-known/acme-challenge/ { - root /appsmith-stacks/data/certificate/certbot; - } - - location / { - return 301 https://\$host\$request_uri; - } -} - -server { - listen 443 ssl http2; - server_name _; - ssl_certificate $ssl_cert_path; - ssl_certificate_key $ssl_key_path; - include /appsmith-stacks/data/certificate/conf/options-ssl-nginx.conf; - ssl_dhparam /appsmith-stacks/data/certificate/conf/ssl-dhparams.pem; -" -else - echo " - listen ${PORT:-80} default_server; - server_name $custom_domain; -" -fi -) - - client_max_body_size 150m; - - index index.html; - error_page 404 /; - - # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors - add_header Content-Security-Policy "frame-ancestors ${APPSMITH_ALLOWED_FRAME_ANCESTORS-'self' *}"; - - $additional_downstream_headers - - location /.well-known/acme-challenge/ { - root /appsmith-stacks/data/certificate/certbot; - } - - location = /supervisor { - return 301 /supervisor/; - } - - location /supervisor/ { - proxy_http_version 1.1; - proxy_buffering off; - proxy_max_temp_file_size 0; - proxy_redirect off; - proxy_set_header Host \$http_host/supervisor/; - proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto \$origin_scheme; - proxy_set_header X-Forwarded-Host \$origin_host; - proxy_set_header Connection ""; - proxy_pass http://localhost:9001/; - } - - proxy_set_header X-Forwarded-Proto \$origin_scheme; - proxy_set_header X-Forwarded-Host \$origin_host; - proxy_set_header Forwarded \$final_forwarded; - - location / { - try_files /loading.html \$uri /index.html =404; - } - - location = /info { - default_type application/json; - alias /opt/appsmith/info.json; - } - - location ~ ^/static/(js|css|media)\b { - # Files in these folders are hashed, so we can set a long cache time. - add_header Cache-Control "max-age=31104000, immutable"; # 360 days - $additional_downstream_headers - access_log off; - } - - # If the path has an extension at the end, then respond with 404 status if the file not found. - location ~ ^/(?!supervisor/).*\.[a-z]+$ { - try_files \$uri =404; - } - - location /api { - proxy_read_timeout ${APPSMITH_SERVER_TIMEOUT:-60}; - proxy_send_timeout ${APPSMITH_SERVER_TIMEOUT:-60}; - proxy_pass http://localhost:8080; - } - - location /oauth2 { - proxy_pass http://localhost:8080; - } - - location /login { - proxy_pass http://localhost:8080; - } - - location /rts { - proxy_pass http://localhost:${APPSMITH_RTS_PORT:-8091}; - proxy_http_version 1.1; - proxy_set_header Host \$host; - proxy_set_header Connection 'upgrade'; - proxy_set_header Upgrade \$http_upgrade; - } -} -EOF diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf index f3b6d37252..0b7ab6d0e5 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf @@ -1,5 +1,5 @@ [program:editor] -command=/opt/appsmith/run-with-env.sh /opt/appsmith/run-nginx.sh +command=/opt/appsmith/run-with-env.sh /opt/appsmith/run-caddy.sh priority=25 autostart=true autorestart=true