feat: Caddy (#28081)

This PR replaces NGINX and Certbot with Caddy.

1. Auto-HTTPS when custom domain is set, is handled by Caddy.
2. If past certs exist, that were provisioned by Certbot in older
Appsmith versions, we configure Caddy to make use of them. But this only
applies if the certs aren't already expired. If they're expired, point 1
applies.
3. If custom certs are provided in `ssl` folder, Caddy will be
configured to use them.
4. Incoming `Forwarded` header is not passed to any reverse proxies. So
redirect URL is correctly computed on Google Cloud Run.
5. All other route configurations are exactly as they are in NGINX
today.

Caddy configuration file is generated in the `caddy-reconfigure.mjs`
script, which will also reload Caddy with the new configuration.
This commit is contained in:
Shrikant Sharat Kandula 2023-12-05 10:47:36 +05:30 committed by GitHub
parent 54012c5c86
commit 4d24aba331
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 191 additions and 488 deletions

View File

@ -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 - \ RUN cd ./utils && npm install --only=prod && npm install --only=prod -g . && cd - \
&& chmod 0644 /etc/cron.d/* \ && 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. # Disable setuid/setgid bits for the files inside container.
&& find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true \ && 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 \ && mkdir -p /.mongodb/mongosh /appsmith-stacks \
&& chmod ugo+w /etc /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-check=/watchtower-hooks/pre-check.sh
LABEL com.centurylinklabs.watchtower.lifecycle.pre-update=/watchtower-hooks/pre-update.sh LABEL com.centurylinklabs.watchtower.lifecycle.pre-update=/watchtower-hooks/pre-update.sh

View File

@ -31,7 +31,7 @@ public class InstanceConfig implements ApplicationListener<ApplicationReadyEvent
private final InstanceConfigHelper instanceConfigHelper; private final InstanceConfigHelper instanceConfigHelper;
private static final String WWW_PATH = System.getenv("NGINX_WWW_PATH"); private static final String WWW_PATH = System.getenv("WWW_PATH");
@Override @Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {

View File

@ -0,0 +1,133 @@
import * as fs from "fs"
import {dirname} from "path"
import {spawnSync} from "child_process"
import {X509Certificate} from "crypto"
const APPSMITH_CUSTOM_DOMAIN = process.env.APPSMITH_CUSTOM_DOMAIN ?? null
const CaddyfilePath = process.env.TMP + "/Caddyfile"
let certLocation = null
if (APPSMITH_CUSTOM_DOMAIN != null) {
try {
fs.accessSync("/appsmith-stacks/ssl/fullchain.pem", fs.constants.R_OK)
certLocation = "/appsmith-stacks/ssl"
} catch (_) {
// no custom certs, see if old certbot certs are there.
const letsEncryptCertLocation = "/etc/letsencrypt/live/" + APPSMITH_CUSTOM_DOMAIN
const fullChainPath = letsEncryptCertLocation + `/fullchain.pem`
try {
fs.accessSync(fullChainPath, fs.constants.R_OK)
console.log("Old Let's Encrypt cert file exists, now checking if it's expired.")
if (!isCertExpired(fullChainPath)) {
certLocation = letsEncryptCertLocation
}
} catch (_) {
// no certs there either, ignore.
}
}
}
const tlsConfig = certLocation == null ? "" : `tls ${certLocation}/fullchain.pem ${certLocation}/privkey.pem`
const parts = []
parts.push(`
{
admin 127.0.0.1:2019
persist_config off
acme_ca_root /etc/ssl/certs/ca-certificates.crt
servers {
trusted_proxies static 0.0.0.0/0
}
}
(file_server) {
file_server {
precompressed br gzip
disable_canonical_uris
}
}
(reverse_proxy) {
reverse_proxy {
to 127.0.0.1:{args[0]}
header_up -Forwarded
}
}
(all-config) {
log {
output stdout
}
skip_log /api/v1/health
header {
-Server
Content-Security-Policy "frame-ancestors ${process.env.APPSMITH_ALLOWED_FRAME_ANCESTORS ?? "'self' *"}"
X-Content-Type-Options "nosniff"
}
request_body {
max_size 150MB
}
handle {
root * {$WWW_PATH}
try_files /loading.html /index.html
import file_server
}
root * /opt/appsmith/editor
@file file
handle @file {
import file_server
skip_log
}
error /static/* 404
handle /info {
root * /opt/appsmith
rewrite * /info.json
import file_server
}
@backend path /api/* /oauth2/* /login/*
handle @backend {
import reverse_proxy 8080
}
handle /rts/* {
import reverse_proxy 8091
}
redir /supervisor /supervisor/
handle_path /supervisor/* {
import reverse_proxy 9001
}
handle_errors {
respond "{err.status_code} {err.status_text}" {err.status_code}
}
}
localhost:80 127.0.0.1:80 {
import all-config
}
${APPSMITH_CUSTOM_DOMAIN || ":80"} {
import all-config
${tlsConfig}
}
`)
fs.mkdirSync(dirname(CaddyfilePath), { recursive: true })
fs.writeFileSync(CaddyfilePath, parts.join("\n"))
spawnSync("/opt/caddy/caddy", ["fmt", "--overwrite", CaddyfilePath])
spawnSync("/opt/caddy/caddy", ["reload", "--config", CaddyfilePath])
function isCertExpired(path) {
const cert = new X509Certificate(fs.readFileSync(path, "utf-8"))
console.log(path, cert)
return new Date(cert.validTo) < new Date()
}

View File

@ -9,7 +9,7 @@ stacks_path=/appsmith-stacks
export SUPERVISORD_CONF_TARGET="$TMP/supervisor-conf.d/" # export for use in supervisord.conf export SUPERVISORD_CONF_TARGET="$TMP/supervisor-conf.d/" # export for use in supervisord.conf
export MONGODB_TMP_KEY_PATH="$TMP/mongodb-key" # export for use in supervisor process mongodb.conf export MONGODB_TMP_KEY_PATH="$TMP/mongodb-key" # export for use in supervisor process mongodb.conf
mkdir -pv "$SUPERVISORD_CONF_TARGET" "$NGINX_WWW_PATH" mkdir -pv "$SUPERVISORD_CONF_TARGET" "$WWW_PATH"
# ip is a reserved keyword for tracking events in Mixpanel. Instead of showing the ip as is Mixpanel provides derived properties. # ip is a reserved keyword for tracking events in Mixpanel. Instead of showing the ip as is Mixpanel provides derived properties.
# As we want derived props alongwith the ip address we are sharing the ip address in separate keys # As we want derived props alongwith the ip address we are sharing the ip address in separate keys
@ -347,11 +347,6 @@ configure_supervisord() {
cp "$supervisord_conf_source/redis.conf" "$SUPERVISORD_CONF_TARGET" cp "$supervisord_conf_source/redis.conf" "$SUPERVISORD_CONF_TARGET"
mkdir -p "$stacks_path/data/redis" mkdir -p "$stacks_path/data/redis"
fi fi
if ! [[ -e "/appsmith-stacks/ssl/fullchain.pem" ]] || ! [[ -e "/appsmith-stacks/ssl/privkey.pem" ]]; then
if [[ -n "${APPSMITH_CUSTOM_DOMAIN-}" ]]; then
cp "$supervisord_conf_source/cron.conf" "$SUPERVISORD_CONF_TARGET"
fi
fi
if [[ $runEmbeddedPostgres -eq 1 ]]; then if [[ $runEmbeddedPostgres -eq 1 ]]; then
cp "$supervisord_conf_source/postgres.conf" "$SUPERVISORD_CONF_TARGET" cp "$supervisord_conf_source/postgres.conf" "$SUPERVISORD_CONF_TARGET"
fi fi
@ -443,23 +438,20 @@ init_postgres || runEmbeddedPostgres=0
} }
init_loading_pages(){ init_loading_pages(){
local starting_page="/opt/appsmith/templates/appsmith_starting.html" export XDG_DATA_HOME=/appsmith-stacks/data # so that caddy saves tls certs and other data under stacks/data/caddy
local initializing_page="/opt/appsmith/templates/appsmith_initializing.html" export XDG_CONFIG_HOME=/appsmith-stacks/configuration
local editor_load_page="$NGINX_WWW_PATH/loading.html" mkdir -p "$XDG_DATA_HOME" "$XDG_CONFIG_HOME"
cp "$initializing_page" "$NGINX_WWW_PATH/index.html" cp templates/loading.html "$WWW_PATH"
# TODO: Also listen on 443, if HTTP certs are available. if [[ -z "${APPSMITH_ALLOWED_FRAME_ANCESTORS-}" ]]; then
cat <<EOF > "$TMP/nginx-app.conf" # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors
server { export APPSMITH_ALLOWED_FRAME_ANCESTORS="'self'"
listen ${PORT:-80} default_server; else
location / { # Remove any extra rules that may be present in the frame ancestors value. This is to prevent this env variable from
try_files \$uri \$uri/ /index.html =404; # 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
EOF node caddy-reconfigure.mjs
# Start nginx page to display the Appsmith is Initializing page /opt/caddy/caddy start --config "$TMP/Caddyfile"
nginx
# Update editor nginx page for starting page
cp "$starting_page" "$editor_load_page"
} }
# Main Section # 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 # 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} mkdir -p /appsmith-stacks/logs/{supervisor,backend,cron,editor,rts,mongodb,redis,postgres,appsmithctl}
# Stop nginx gracefully
nginx -s quit
# Handle CMD command # Handle CMD command
exec "$@" exec "$@"

View File

@ -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
}

View File

@ -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();

View File

@ -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

View File

@ -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"

View File

@ -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 <<EOF > "$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 <<EOF > "$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;"

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
python3 /opt/appsmith/starting-page-init.py python3 /opt/appsmith/starting-page-init.py
rm -f "$NGINX_WWW_PATH/loading.html" rm -f "$WWW_PATH/loading.html"

View File

@ -9,7 +9,7 @@ import urllib.request
LOADING_TEMPLATE_PAGE = r'/opt/appsmith/templates/appsmith_starting.html' 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" BACKEND_HEALTH_ENDPOINT = "http://localhost:8080/api/v1/health"
LOG_FILE = r'/appsmith-stacks/logs/backend/starting_page_init.log' LOG_FILE = r'/appsmith-stacks/logs/backend/starting_page_init.log'
LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

View File

@ -1,87 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" http-equiv="refresh" content="5"/>
<link
rel="shortcut icon"
href="https://assets.appsmith.com/appsmith-favicon-orange.ico"
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>Appsmith</title>
</head>
<body>
<div class="main">
<p class="bold-text">
Please wait
</p>
<p>Appsmith is initializing. This might take a few minutes.</p>
<div class="loader"></div>
</div>
<style>
body,
html {
height: 100%;
overflow-x: hidden;
width: 100%;
background-color: #fff;
margin: 0;
color: #182026;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Open Sans, Helvetica Neue, Icons16, sans-serif;
font-size: 14px;
font-weight: 400;
letter-spacing: 0;
}
.main {
display: flex;
align-items: center;
height: 90%;
flex-direction: column;
margin-top: 5%;
text-align: center;
}
.bold-text {
font-family: system-ui;
font-weight: 700;
font-size: 24px;
margin: 24px 0 0;
}
.body-text {
margin: 8px 0 0;
}
/* Safari */
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loader {
border: 4px solid #f3f3f3;
border-radius: 50%;
border-top: 4px solid #939090;
width: 30px;
height: 30px;
-webkit-animation: spin 1s linear infinite; /* Safari */
animation: spin 1s linear infinite;
}
</style>
</body>
</html>

View File

@ -14,10 +14,8 @@
</head> </head>
<body> <body>
<div class="main"> <div class="main">
<p class="bold-text"> <p class="bold-text">Appsmith is starting.</p>
Appsmith is starting. <p>Please wait until Appsmith is ready. This may take a few minutes. </p>
</p>
<p>Please wait until Appsmith is ready. This process usually takes a minute. </p>
<div class="loader"></div> <div class="loader"></div>
</div> </div>

View File

@ -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 <<EOF > "$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

View File

@ -1,5 +1,5 @@
[program:editor] [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 priority=25
autostart=true autostart=true
autorestart=true autorestart=true