chore: Run NGINX with readonly root FS support (#27453)

Part of supporting readonly root filesystem, gets NGINX to start without
doing any writes to the filesystem, except for in `/tmp`.
This commit is contained in:
Shrikant Sharat Kandula 2023-09-27 13:38:47 +05:30 committed by GitHub
parent 439af21522
commit 2f5405d86d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 53 additions and 31 deletions

View File

@ -53,7 +53,8 @@ RUN rm -rf \
VOLUME [ "/appsmith-stacks" ] VOLUME [ "/appsmith-stacks" ]
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
ENV TMP /tmp/appsmith ENV TMP="/tmp/appsmith"
ENV NGINX_WWW_PATH="$TMP/www"
# Add backend server - Application Layer # Add backend server - Application Layer
ARG JAR_FILE=./app/server/dist/server-*.jar ARG JAR_FILE=./app/server/dist/server-*.jar
@ -81,9 +82,10 @@ COPY ./app/client/packages/rts/package.json ./app/client/packages/rts/dist rts/
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 entrypoint.sh renew-certificate.sh healthcheck.sh /watchtower-hooks/*.sh \ && chmod +x entrypoint.sh renew-certificate.sh healthcheck.sh templates/nginx-app.conf.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
# Update path to load appsmith utils tool as default # Update path to load appsmith utils tool as default
ENV PATH /opt/appsmith/utils/node_modules/.bin:$PATH ENV PATH /opt/appsmith/utils/node_modules/.bin:$PATH

View File

@ -7,7 +7,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" mkdir -pv "$SUPERVISORD_CONF_TARGET" "$NGINX_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
@ -392,15 +392,19 @@ init_postgres || runEmbeddedPostgres=0
} }
init_loading_pages(){ init_loading_pages(){
# The default NGINX configuration includes an IPv6 listen directive. But not all
# servers support it, and we don't need it. So we remove it here before starting
# NGINX.
sed -i '/\[::\]:80 default_server;/d' /etc/nginx/sites-available/default
local starting_page="/opt/appsmith/templates/appsmith_starting.html" local starting_page="/opt/appsmith/templates/appsmith_starting.html"
local initializing_page="/opt/appsmith/templates/appsmith_initializing.html" local initializing_page="/opt/appsmith/templates/appsmith_initializing.html"
local editor_load_page="/opt/appsmith/editor/loading.html" local editor_load_page="$NGINX_WWW_PATH/loading.html"
# Update default nginx page for initializing page cp "$initializing_page" "$NGINX_WWW_PATH/index.html"
cp "$initializing_page" /var/www/html/index.nginx-debian.html # TODO: Also listen on 443, if HTTP certs are available.
cat <<EOF > "$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 # Start nginx page to display the Appsmith is Initializing page
nginx nginx
# Update editor nginx page for starting page # Update editor nginx page for starting page

View File

@ -9,10 +9,7 @@ init_ssl_cert() {
mkdir -p "$data_path/www" mkdir -p "$data_path/www"
echo "Re-generating nginx config template with domain" echo "Re-generating nginx config template with domain"
bash "/opt/appsmith/templates/nginx-app.conf.sh" "0" "$APPSMITH_CUSTOM_DOMAIN" \ /opt/appsmith/templates/nginx-app.conf.sh "0" "$APPSMITH_CUSTOM_DOMAIN"
| envsubst "$(printf '$%s,' $(env | grep -Eo '^APPSMITH_[A-Z0-9_]+'))" \
| sed -e 's|\${\(APPSMITH_[A-Z0-9_]*\)}||g' \
> /etc/nginx/sites-available/default
echo "Start Nginx to verify certificate" echo "Start Nginx to verify certificate"
nginx nginx

View File

@ -0,0 +1,27 @@
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

@ -65,14 +65,13 @@ if [[ -n ${APPSMITH_CUSTOM_DOMAIN-} ]] && [[ -z ${DYNO-} ]]; then
fi fi
fi fi
bash /opt/appsmith/templates/nginx-app.conf.sh "$use_https" "${APPSMITH_CUSTOM_DOMAIN-}" > /etc/nginx/sites-available/default /opt/appsmith/templates/nginx-app.conf.sh "$use_https" "${APPSMITH_CUSTOM_DOMAIN-}"
cp -r /opt/appsmith/editor/* "$NGINX_WWW_PATH"
apply-env-vars() { apply-env-vars() {
original="$1" original="$1"
served="$2" served="$2"
if [[ ! -f $original ]]; then
cp -v "$served" "$original"
fi
node -e ' node -e '
const fs = require("fs") const fs = require("fs")
const content = fs.readFileSync("'"$original"'", "utf8").replace( const content = fs.readFileSync("'"$original"'", "utf8").replace(
@ -86,6 +85,6 @@ apply-env-vars() {
popd popd
} }
apply-env-vars /opt/appsmith/index.html.original /opt/appsmith/editor/index.html apply-env-vars /opt/appsmith/editor/index.html "$NGINX_WWW_PATH/index.html"
exec nginx -g "daemon off;error_log stderr info;" 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 /opt/appsmith/editor/loading.html rm -f "$NGINX_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 = r'/opt/appsmith/editor/loading.html' LOADING_PAGE_EDITOR = os.getenv("NGINX_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

@ -22,7 +22,7 @@ additional_downstream_headers='
add_header X-Content-Type-Options "nosniff"; add_header X-Content-Type-Options "nosniff";
' '
cat <<EOF cat <<EOF > "$TMP/nginx-app.conf"
map \$http_x_forwarded_proto \$origin_scheme { map \$http_x_forwarded_proto \$origin_scheme {
default \$http_x_forwarded_proto; default \$http_x_forwarded_proto;
'' \$scheme; '' \$scheme;
@ -41,9 +41,6 @@ map \$http_forwarded \$final_forwarded {
# redirect log to stdout for supervisor to capture # redirect log to stdout for supervisor to capture
access_log /dev/stdout; access_log /dev/stdout;
server_tokens off;
more_set_headers 'Server: ';
server { server {
$( $(
@ -72,10 +69,6 @@ fi
client_max_body_size 150m; client_max_body_size 150m;
gzip on;
gzip_types *;
root /opt/appsmith/editor;
index index.html; index index.html;
error_page 404 /; error_page 404 /;