2021-09-01 05:32:08 +00:00
#!/usr/bin/env bash
set -e
2023-01-27 10:35:00 +00:00
set -o xtrace
2021-09-01 05:32:08 +00:00
2022-06-01 05:44:27 +00:00
stacks_path = /appsmith-stacks
function get_maximum_heap( ) {
2022-03-24 07:47:36 +00:00
resource = $( ulimit -u)
echo " Resource : $resource "
if [ [ " $resource " -le 256 ] ] ; then
maximum_heap = 128
elif [ [ " $resource " -le 512 ] ] ; then
maximum_heap = 256
fi
}
2022-06-01 05:44:27 +00:00
function setup_backend_heap_arg( ) {
2022-03-24 07:47:36 +00:00
if [ [ ! -z ${ maximum_heap } ] ] ; then
export APPSMITH_JAVA_HEAP_ARG = " -Xmx ${ maximum_heap } m "
fi
}
2022-01-31 07:57:01 +00:00
init_env_file( ) {
CONF_PATH = "/appsmith-stacks/configuration"
ENV_PATH = " $CONF_PATH /docker.env "
TEMPLATES_PATH = "/opt/appsmith/templates"
2022-04-05 14:52:52 +00:00
# Build an env file with current env variables. We single-quote the values, as well as escaping any single-quote characters.
printenv | grep -E '^APPSMITH_|^MONGO_' | sed " s/'/'\"'\"'/; s/=/='/; s/ $/'/ " > " $TEMPLATES_PATH /pre-define.env "
2022-06-01 05:44:27 +00:00
2022-01-31 07:57:01 +00:00
echo "Initialize .env file"
if ! [ [ -e " $ENV_PATH " ] ] ; then
# Generate new docker.env file when initializing container for first time or in Heroku which does not have persistent volume
echo "Generating default configuration file"
mkdir -p " $CONF_PATH "
2022-04-15 12:14:08 +00:00
local default_appsmith_mongodb_user = "appsmith"
local generated_appsmith_mongodb_password = $(
2022-01-31 07:57:01 +00:00
tr -dc A-Za-z0-9 </dev/urandom | head -c 13
2022-03-03 03:10:29 +00:00
echo ""
2022-01-31 07:57:01 +00:00
)
2022-04-15 12:14:08 +00:00
local generated_appsmith_encryption_password = $(
2022-01-31 07:57:01 +00:00
tr -dc A-Za-z0-9 </dev/urandom | head -c 13
2022-03-03 03:10:29 +00:00
echo ""
2022-01-31 07:57:01 +00:00
)
2022-04-15 12:14:08 +00:00
local generated_appsmith_encription_salt = $(
2022-01-31 07:57:01 +00:00
tr -dc A-Za-z0-9 </dev/urandom | head -c 13
2022-03-03 03:10:29 +00:00
echo ""
2022-01-31 07:57:01 +00:00
)
2022-04-15 12:14:08 +00:00
local generated_appsmith_supervisor_password = $(
2022-03-24 07:47:36 +00:00
tr -dc A-Za-z0-9 </dev/urandom | head -c 13
echo ''
)
2022-04-15 12:14:08 +00:00
bash " $TEMPLATES_PATH /docker.env.sh " " $default_appsmith_mongodb_user " " $generated_appsmith_mongodb_password " " $generated_appsmith_encryption_password " " $generated_appsmith_encription_salt " " $generated_appsmith_supervisor_password " > " $ENV_PATH "
2022-01-31 07:57:01 +00:00
fi
2022-03-03 03:10:29 +00:00
echo "Load environment configuration"
2022-01-31 07:57:01 +00:00
set -o allexport
. " $ENV_PATH "
. " $TEMPLATES_PATH /pre-define.env "
set +o allexport
}
2022-06-01 05:44:27 +00:00
setup_proxy_variables( ) {
export NO_PROXY = " ${ NO_PROXY -localhost,127.0.0.1 } "
# If one of HTTPS_PROXY or https_proxy are set, copy it to the other. If both are set, prefer HTTPS_PROXY.
if [ [ -n ${ HTTPS_PROXY - } ] ] ; then
export https_proxy = " $HTTPS_PROXY "
elif [ [ -n ${ https_proxy - } ] ] ; then
export HTTPS_PROXY = " $https_proxy "
fi
# If one of HTTP_PROXY or http_proxy are set, copy it to the other. If both are set, prefer HTTP_PROXY.
if [ [ -n ${ HTTP_PROXY - } ] ] ; then
export http_proxy = " $HTTP_PROXY "
elif [ [ -n ${ http_proxy - } ] ] ; then
export HTTP_PROXY = " $http_proxy "
fi
}
2022-01-31 07:57:01 +00:00
unset_unused_variables( ) {
# Check for enviroment vairalbes
2022-03-03 03:10:29 +00:00
echo "Checking environment configuration"
2022-01-31 07:57:01 +00:00
if [ [ -z " ${ APPSMITH_MAIL_ENABLED } " ] ] ; then
unset APPSMITH_MAIL_ENABLED # If this field is empty is might cause application crash
fi
if [ [ -z " ${ APPSMITH_OAUTH2_GITHUB_CLIENT_ID } " ] ] || [ [ -z " ${ APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET } " ] ] ; then
unset APPSMITH_OAUTH2_GITHUB_CLIENT_ID # If this field is empty is might cause application crash
unset APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET
fi
if [ [ -z " ${ APPSMITH_OAUTH2_GOOGLE_CLIENT_ID } " ] ] || [ [ -z " ${ APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET } " ] ] ; then
unset APPSMITH_OAUTH2_GOOGLE_CLIENT_ID # If this field is empty is might cause application crash
unset APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET
fi
if [ [ -z " ${ APPSMITH_GOOGLE_MAPS_API_KEY } " ] ] ; then
unset APPSMITH_GOOGLE_MAPS_API_KEY
fi
if [ [ -z " ${ APPSMITH_RECAPTCHA_SITE_KEY } " ] ] || [ [ -z " ${ APPSMITH_RECAPTCHA_SECRET_KEY } " ] ] || [ [ -z " ${ APPSMITH_RECAPTCHA_ENABLED } " ] ] ; then
unset APPSMITH_RECAPTCHA_SITE_KEY # If this field is empty is might cause application crash
unset APPSMITH_RECAPTCHA_SECRET_KEY
unset APPSMITH_RECAPTCHA_ENABLED
fi
}
2022-02-09 09:02:46 +00:00
check_mongodb_uri( ) {
2022-03-03 03:10:29 +00:00
echo "Checking APPSMITH_MONGODB_URI"
2022-02-09 09:02:46 +00:00
isUriLocal = 1
if [ [ $APPSMITH_MONGODB_URI = = *"localhost" * || $APPSMITH_MONGODB_URI = = *"127.0.0.1" * ] ] ; then
2022-03-03 03:10:29 +00:00
echo "Detected local MongoDB"
2022-02-09 09:02:46 +00:00
isUriLocal = 0
fi
}
init_mongodb( ) {
if [ [ $isUriLocal -eq 0 ] ] ; then
2022-03-03 03:10:29 +00:00
echo "Initializing local database"
2022-07-20 15:12:23 +00:00
MONGO_DB_PATH = " $stacks_path /data/mongodb "
2022-02-09 09:02:46 +00:00
MONGO_LOG_PATH = " $MONGO_DB_PATH /log "
MONGO_DB_KEY = " $MONGO_DB_PATH /key "
mkdir -p " $MONGO_DB_PATH "
touch " $MONGO_LOG_PATH "
2022-07-20 15:12:23 +00:00
if [ [ ! -f " $MONGO_DB_KEY " ] ] ; then
openssl rand -base64 756 > " $MONGO_DB_KEY "
2022-02-09 09:02:46 +00:00
fi
2022-09-19 08:19:27 +00:00
use-mongodb-key " $MONGO_DB_KEY "
2022-02-09 09:02:46 +00:00
fi
}
init_replica_set( ) {
2022-03-03 03:10:29 +00:00
echo "Checking initialized database"
2021-11-16 11:02:28 +00:00
shouldPerformInitdb = 1
for path in \
" $MONGO_DB_PATH /WiredTiger " \
" $MONGO_DB_PATH /journal " \
" $MONGO_DB_PATH /local.0 " \
" $MONGO_DB_PATH /storage.bson " ; do
if [ -e " $path " ] ; then
shouldPerformInitdb = 0
2022-02-09 09:02:46 +00:00
break
2021-11-16 11:02:28 +00:00
fi
done
2022-03-10 04:46:16 +00:00
2022-02-09 09:02:46 +00:00
if [ [ $shouldPerformInitdb -gt 0 && $isUriLocal -eq 0 ] ] ; then
2022-03-03 03:10:29 +00:00
echo "Initializing Replica Set for local database"
2021-11-16 11:02:28 +00:00
# Start installed MongoDB service - Dependencies Layer
mongod --fork --port 27017 --dbpath " $MONGO_DB_PATH " --logpath " $MONGO_LOG_PATH "
2022-03-03 03:10:29 +00:00
echo "Waiting 10s for MongoDB to start"
2021-11-16 11:02:28 +00:00
sleep 10
2022-03-03 03:10:29 +00:00
echo "Creating MongoDB user"
2023-01-27 10:35:00 +00:00
mongosh "127.0.0.1/appsmith" --eval " db.createUser({
user: '$APPSMITH_MONGODB_USER' ,
pwd: '$APPSMITH_MONGODB_PASSWORD' ,
roles: [ {
role: 'root' ,
db: 'admin'
} , 'readWrite' ]
}
) "
2022-03-03 03:10:29 +00:00
echo "Enabling Replica Set"
2021-11-16 11:02:28 +00:00
mongod --dbpath " $MONGO_DB_PATH " --shutdown || true
2022-09-19 08:19:27 +00:00
mongod --fork --port 27017 --dbpath " $MONGO_DB_PATH " --logpath " $MONGO_LOG_PATH " --replSet mr1 --keyFile /mongodb-key --bind_ip localhost
2022-03-03 03:10:29 +00:00
echo "Waiting 10s for MongoDB to start with Replica Set"
2021-11-16 11:02:28 +00:00
sleep 10
2023-01-27 10:35:00 +00:00
mongosh " $APPSMITH_MONGODB_URI " --eval 'rs.initiate()'
2021-11-16 11:02:28 +00:00
mongod --dbpath " $MONGO_DB_PATH " --shutdown || true
fi
2022-02-09 09:02:46 +00:00
if [ [ $isUriLocal -gt 0 ] ] ; then
2023-02-18 01:23:33 +00:00
if [ [ -f /proc/cpuinfo ] ] && ! grep --quiet avx /proc/cpuinfo; then
echo "====================================================================================================" >& 2
echo "==" >& 2
echo "== AVX instruction not found in your CPU. Appsmith's embedded MongoDB may not start. Please use an external MongoDB instance instead." >& 2
echo "== See https://docs.appsmith.com/getting-started/setup/instance-configuration/custom-mongodb-redis#custom-mongodb for instructions." >& 2
echo "==" >& 2
echo "====================================================================================================" >& 2
fi
2022-03-03 03:10:29 +00:00
echo "Checking Replica Set of external MongoDB"
2022-02-09 09:02:46 +00:00
fix: Fix replicaset check to not require ClusterMonitor role (#19997)
In the `entrypoint.sh` script, we check if the MongoDB in use, has
replicaSet initiated or not. This is usually done with a `rs.initiate()`
on the cluster.
We need the replicaSet to be enabled on MongoDB, since the backend
server relies on MongoDB `changeStream`s, which is a feature, only
available if replicaSet is enabled.
However, to use the `changeStream` APIs, having the `read` or
`readWrite` role on MongoDB is enough. But the check we do in
`entrypoint.sh`, runs `rs.status()` to see if `replicaSet` is initiated.
This `rs.status()` call, unfortunately, requires the `ClusterMonitor`
role, unlike the `changeStream` API.
To tackle this, we created the `appsmithctl check_replica_set` command.
This command would attempt to use the `changeStream` API, and report
success or failure. But this failed on certain configurations, where
MongoDB was running as a single-node-cluster, on localhost, or a
local/internal network. This was an edge case.
That edge case is solved by this PR. With this, we can use `appsmithctl
check-replica-set` in the `entrypoint.sh` again.
2023-02-07 00:08:37 +00:00
if appsmithctl check-replica-set; then
echo "MongoDB ReplicaSet is enabled"
2022-02-09 09:02:46 +00:00
else
fix: Fix replicaset check to not require ClusterMonitor role (#19997)
In the `entrypoint.sh` script, we check if the MongoDB in use, has
replicaSet initiated or not. This is usually done with a `rs.initiate()`
on the cluster.
We need the replicaSet to be enabled on MongoDB, since the backend
server relies on MongoDB `changeStream`s, which is a feature, only
available if replicaSet is enabled.
However, to use the `changeStream` APIs, having the `read` or
`readWrite` role on MongoDB is enough. But the check we do in
`entrypoint.sh`, runs `rs.status()` to see if `replicaSet` is initiated.
This `rs.status()` call, unfortunately, requires the `ClusterMonitor`
role, unlike the `changeStream` API.
To tackle this, we created the `appsmithctl check_replica_set` command.
This command would attempt to use the `changeStream` API, and report
success or failure. But this failed on certain configurations, where
MongoDB was running as a single-node-cluster, on localhost, or a
local/internal network. This was an edge case.
That edge case is solved by this PR. With this, we can use `appsmithctl
check-replica-set` in the `entrypoint.sh` again.
2023-02-07 00:08:37 +00:00
echo -e "\033[0;31m***************************************************************************************\033[0m"
echo -e "\033[0;31m* MongoDB Replica Set is not enabled *\033[0m"
echo -e "\033[0;31m* Please ensure the credentials provided for MongoDB, has `readWrite` role. *\033[0m"
echo -e "\033[0;31m***************************************************************************************\033[0m"
2022-02-09 09:02:46 +00:00
exit 1
fi
fi
2021-09-01 05:32:08 +00:00
}
2022-09-19 08:19:27 +00:00
use-mongodb-key( ) {
2023-01-27 10:35:00 +00:00
# This is a little weird. We copy the MongoDB key file to `/mongodb-key`, so that we can reliably set its permissions to 600.
# What affects the reliability of this? When the host machine of this Docker container is Windows, file permissions cannot be set on files in volumes.
# So the key file should be somewhere inside the container, and not in a volume.
cp -v " $1 " /mongodb-key
2022-09-19 08:19:27 +00:00
chmod 600 /mongodb-key
2022-01-10 11:49:29 +00:00
}
# Keep Let's Encrypt directory persistent
mount_letsencrypt_directory( ) {
2021-11-23 04:09:13 +00:00
echo "Mounting Let's encrypt directory"
2021-11-16 11:02:28 +00:00
rm -rf /etc/letsencrypt
mkdir -p /appsmith-stacks/{ letsencrypt,ssl}
ln -s /appsmith-stacks/letsencrypt /etc/letsencrypt
2021-09-01 05:32:08 +00:00
}
2022-06-01 05:44:27 +00:00
is_empty_directory( ) {
[ [ -d $1 && -z " $( ls -A " $1 " ) " ] ]
}
check_setup_custom_ca_certificates( ) {
local stacks_ca_certs_path
stacks_ca_certs_path = " $stacks_path /ca-certs "
local container_ca_certs_path
container_ca_certs_path = "/usr/local/share/ca-certificates"
if [ [ -d $stacks_ca_certs_path ] ] ; then
if [ [ ! -L $container_ca_certs_path ] ] ; then
if is_empty_directory " $container_ca_certs_path " ; then
rmdir -v " $container_ca_certs_path "
else
echo "The 'ca-certificates' directory inside the container is not empty. Please clear it and restart to use certs from 'stacks/ca-certs' directory." >& 2
return
fi
fi
ln --verbose --force --symbolic --no-target-directory " $stacks_ca_certs_path " " $container_ca_certs_path "
elif [ [ ! -e $container_ca_certs_path ] ] ; then
rm -vf " $container_ca_certs_path " # If it exists as a broken symlink, this will be needed.
mkdir -v " $container_ca_certs_path "
fi
if [ [ -n " $( ls " $stacks_ca_certs_path " /*.pem 2>/dev/null) " ] ] ; then
echo "Looks like you have some '.pem' files in your 'ca-certs' folder. Please rename them to '.crt' to be picked up autatically." .
fi
update-ca-certificates --fresh
}
2021-09-01 05:32:08 +00:00
configure_supervisord( ) {
2021-11-16 11:02:28 +00:00
SUPERVISORD_CONF_PATH = "/opt/appsmith/templates/supervisord"
2021-11-23 06:43:10 +00:00
if [ [ -n " $( ls -A /etc/supervisor/conf.d) " ] ] ; then
2021-11-23 04:09:13 +00:00
rm -f "/etc/supervisor/conf.d/" *
2021-11-16 11:02:28 +00:00
fi
cp -f " $SUPERVISORD_CONF_PATH /application_process/ " *.conf /etc/supervisor/conf.d
# Disable services based on configuration
2022-03-24 07:47:36 +00:00
if [ [ -z " ${ DYNO } " ] ] ; then
if [ [ $isUriLocal -eq 0 ] ] ; then
cp " $SUPERVISORD_CONF_PATH /mongodb.conf " /etc/supervisor/conf.d/
fi
if [ [ $APPSMITH_REDIS_URL = = *"localhost" * || $APPSMITH_REDIS_URL = = *"127.0.0.1" * ] ] ; then
cp " $SUPERVISORD_CONF_PATH /redis.conf " /etc/supervisor/conf.d/
2023-01-23 12:20:37 +00:00
# Initialize Redis rdb directory
local redis_db_path = " $stacks_path /data/redis "
mkdir -p " $redis_db_path "
2022-03-24 07:47:36 +00:00
# Enable saving Redis session data to disk more often, so recent sessions aren't cleared on restart.
2023-01-23 12:20:37 +00:00
sed -i \
-e 's/^save 60 10000$/save 15 1/g' \
-e " s|^dir /var/lib/redis $|dir ${ redis_db_path } |g " \
/etc/redis/redis.conf
2022-03-24 07:47:36 +00:00
fi
if ! [ [ -e "/appsmith-stacks/ssl/fullchain.pem" ] ] || ! [ [ -e "/appsmith-stacks/ssl/privkey.pem" ] ] ; then
cp " $SUPERVISORD_CONF_PATH /cron.conf " /etc/supervisor/conf.d/
fi
2021-11-16 11:02:28 +00:00
fi
2021-09-01 05:32:08 +00:00
}
2022-04-01 06:58:03 +00:00
# This is a workaround to get Redis working on diffent memory pagesize
# https://github.com/appsmithorg/appsmith/issues/11773
check_redis_compatible_page_size( ) {
local page_size
page_size = " $( getconf PAGE_SIZE) "
if [ [ $page_size -gt 4096 ] ] ; then
echo " Compile Redis stable with page size of $page_size "
echo "Downloading Redis source..."
curl https://download.redis.io/redis-stable.tar.gz -L | tar xvz
cd redis-stable/
echo "Compiling Redis from source..."
make && make install
echo "Cleaning up Redis source..."
cd ..
rm -rf redis-stable/
else
echo " Redis is compatible with page size of $page_size "
fi
}
2021-09-01 05:32:08 +00:00
# Main Section
2022-01-31 07:57:01 +00:00
init_env_file
2022-06-01 05:44:27 +00:00
setup_proxy_variables
2022-01-31 07:57:01 +00:00
unset_unused_variables
2022-06-01 05:44:27 +00:00
2022-02-09 09:02:46 +00:00
check_mongodb_uri
2022-03-24 07:47:36 +00:00
if [ [ -z " ${ DYNO } " ] ] ; then
# Don't run MongoDB if running in a Heroku dyno.
init_mongodb
init_replica_set
2022-06-01 05:44:27 +00:00
else
2022-04-08 13:18:23 +00:00
# These functions are used to limit heap size for Backend process when deployed on Heroku
get_maximum_heap
setup_backend_heap_arg
2022-09-29 11:49:24 +00:00
# set the hostname for heroku dyno
export HOSTNAME = "heroku_dyno"
2022-03-24 07:47:36 +00:00
fi
2022-06-01 05:44:27 +00:00
check_setup_custom_ca_certificates
2021-11-23 04:09:13 +00:00
mount_letsencrypt_directory
2022-06-01 05:44:27 +00:00
2022-04-01 06:58:03 +00:00
check_redis_compatible_page_size
2022-06-01 05:44:27 +00:00
2021-09-01 05:32:08 +00:00
configure_supervisord
2022-03-24 07:47:36 +00:00
CREDENTIAL_PATH = "/etc/nginx/passwords"
if ! [ [ -e " $CREDENTIAL_PATH " ] ] ; then
echo "Generating Basic Authentication file"
printf " $APPSMITH_SUPERVISOR_USER : $( openssl passwd -apr1 $APPSMITH_SUPERVISOR_PASSWORD ) " > " $CREDENTIAL_PATH "
fi
2021-09-14 13:31:06 +00:00
# Ensure the restore path exists in the container, so an archive can be copied to it, if need be.
mkdir -p /appsmith-stacks/data/{ backup,restore}
2021-10-19 07:29:55 +00:00
# Create sub-directory to store services log in the container mounting folder
mkdir -p /appsmith-stacks/logs/{ backend,cron,editor,rts,mongodb,redis}
2021-09-01 05:32:08 +00:00
# Handle CMD command
2021-09-14 13:31:06 +00:00
exec " $@ "