entrypoint.sh 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. #!/bin/bash
  2. # Origin: https://github.com/Melo-Professional/MeshCentral-Stylish-UI
  3. stylishui_base_url="https://github.com/Melo-Professional/MeshCentral-Stylish-UI/archive/refs"
  4. stylishui_compat="https://raw.githubusercontent.com/Melo-Professional/MeshCentral-Stylish-UI/refs/heads/main/metadata/compat.json"
  5. function graceful_shutdown() {
  6. echo "Received SIGTERM from the container host. Cleaning up..."
  7. kill -SIGINT $meshcentral_pid
  8. echo "MeshCentral process stopped. Exiting..."
  9. exit 0
  10. }
  11. trap graceful_shutdown SIGTERM
  12. function test_url() {
  13. wget --spider $1 &> /dev/null
  14. if [[ $? -eq 0 ]]; then
  15. echo "is ok."
  16. return 0
  17. else
  18. echo "is NOT ok."
  19. return 1
  20. fi
  21. }
  22. function dynamic_config() {
  23. # BEGIN DATABASE CONFIGURATION FIELDS
  24. USE_MONGODB=${USE_MONGODB,,}
  25. if [[ $USE_MONGODB =~ ^(true|yes)$ ]]; then
  26. echo "Enabling MongoDB-connector..."
  27. if [[ -n "$MONGO_URL" ]]; then
  28. echo "MONGO_URL is set, using that..."
  29. else
  30. MONGO_URL="${MONGO_URL:-$MONGO_USERNAME:$MONGO_PASS@}$MONGO_HOST:$MONGO_PORT"
  31. fi
  32. #ESCAPED_MONGO_URL=$(echo "$MONGO_URL" | sed 's/[\/&?=:]/\\&/g')
  33. sed -i 's/"_mongoDb"/"mongoDb"/' "$CONFIG_FILE"
  34. jq --arg mongo_url "$MONGO_URL" \
  35. '.settings.mongoDb = $mongo_url' \
  36. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  37. else
  38. echo "Disabling MongoDB-connector..."
  39. sed -i 's/"mongoDb"/"_mongoDb"/' "$CONFIG_FILE"
  40. fi
  41. USE_POSTGRESQL=${USE_POSTGRESQL,,}
  42. if [[ $USE_POSTGRESQL =~ ^(true|yes)$ ]]; then
  43. echo "Enabling PostgreSQL-connector..."
  44. sed -i 's/"_postgres"/"postgres"/' "$CONFIG_FILE"
  45. jq --arg psql_host "$PSQL_HOST" \
  46. --arg psql_port "$PSQL_PORT" \
  47. --arg psql_user "$PSQL_USER" \
  48. --arg psql_pass "$PSQL_PASS" \
  49. --arg psql_db "$PSQL_DATABASE" \
  50. '.settings.postgres.host = $psql_host |
  51. .settings.postgres.port = $psql_port |
  52. .settings.postgres.user = $psql_user |
  53. .settings.postgres.password = $psql_pass |
  54. .settings.postgres.database = $psql_db' \
  55. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  56. else
  57. echo "Disabling PostgreSQL-connector..."
  58. sed -i 's/"postgres"/"_postgres"/' "$CONFIG_FILE"
  59. fi
  60. USE_MARIADB=${USE_MARIADB,,}
  61. if [[ $USE_MARIADB =~ ^(true|yes)$ ]]; then
  62. echo "Enabling MariaDB-connector..."
  63. sed -i 's/"_mariaDB"/"mariaDB"/' "$CONFIG_FILE"
  64. jq --arg mariadb_host "$MARIADB_HOST" \
  65. --arg mariadb_port "$MARIADB_PORT" \
  66. --arg mariadb_user "$MARIADB_USER" \
  67. --arg mariadb_pass "$MARIADB_PASS" \
  68. --arg mariadb_db "$MARIADB_DATABASE" \
  69. '.settings.mariaDB.host = $mariadb_host |
  70. .settings.mariaDB.port = $mariadb_port |
  71. .settings.mariaDB.user = $mariadb_user |
  72. .settings.mariaDB.password = $mariadb_pass |
  73. .settings.mariaDB.database = $mariadb_db' \
  74. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  75. else
  76. echo "Disabling MariaDB-connector..."
  77. sed -i 's/"mariaDB"/"_mariaDB"/' "$CONFIG_FILE"
  78. fi
  79. # END DATABASE CONFIGURATION FIELDS
  80. # Doing the bulk with JQ utility. Given the remaining variables an opportunity with Sed.
  81. # The way this works is if the environment variable is empty, it will add a _ in front of the variable, commenting it.
  82. # This will make the default value apply, as per: https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json
  83. echo "Compiling given environment variables..."
  84. echo "If defaults are going to get applied, refer to: https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json"
  85. # SESSIONKEY
  86. if [[ ${REGEN_SESSIONKEY,,} =~ ^(true|yes)$ ]]; then
  87. echo "Regenerating Session-Key because REGENSESSIONKEY is 'true' or 'yes'"
  88. SESSION_KEY=$(tr -dc 'A-Z0-9' < /dev/urandom | fold -w 96 | head -n 1)
  89. sed -i 's/"_sessionKey"/"sessionKey"/' "$CONFIG_FILE"
  90. jq --arg session_key "$SESSION_KEY" \
  91. '.settings.sessionKey = $session_key' \
  92. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  93. else
  94. echo "REGENSESSIONKEY is not 'true' or 'yes', therefore it's being kept as is."
  95. fi
  96. # HOSTNAME
  97. if [[ -n $HOSTNAME ]]; then
  98. echo "Setting hostname (cert)... $HOSTNAME"
  99. jq --arg hostname "$HOSTNAME" \
  100. '.settings.cert = $hostname' \
  101. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  102. else
  103. echo "Invalid or no hostname, defaulting to 'localhost', value given: $HOSTNAME"
  104. jq --arg hostname "localhost" \
  105. '.settings.cert = $hostname' \
  106. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  107. fi
  108. # PORT
  109. if [[ -n $PORT ]]; then
  110. echo "Setting port... $PORT"
  111. sed -i 's/"_port"/"port"/' "$CONFIG_FILE"
  112. jq --argjson port "$PORT" \
  113. '.settings.port = $port' \
  114. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  115. else
  116. echo "Invalid or no port, defaulting to 443"
  117. jq --argjson port 443 \
  118. '.settings.port = $port' \
  119. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  120. fi
  121. # ALIAS_PORT
  122. if [[ -n $ALIAS_PORT ]]; then
  123. echo "Setting aliasPort... $ALIAS_PORT"
  124. sed -i 's/"_aliasPort"/"aliasPort"/' "$CONFIG_FILE"
  125. jq --argjson alias_port "$ALIAS_PORT" \
  126. '.settings.aliasPort = $alias_port' \
  127. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  128. fi
  129. # REDIR_PORT
  130. if [[ -n $REDIR_PORT ]]; then
  131. echo "Setting redirport... $REDIR_PORT"
  132. sed -i 's/"_redirPort"/"redirPort"/' "$CONFIG_FILE"
  133. jq --argjson redirport "$REDIR_PORT" \
  134. '.settings.redirPort = $redirport' \
  135. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  136. else
  137. echo "Invalid or no redirport, defaulting to 80"
  138. jq --argjson redirport 80 \
  139. '.settings.redirPort = $redirport' \
  140. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  141. fi
  142. # ALLOWPLUGINS
  143. ALLOW_PLUGINS=${ALLOW_PLUGINS,,}
  144. if [[ $ALLOW_PLUGINS =~ ^(true|false)$ ]]; then
  145. echo "Setting plugins... $ALLOW_PLUGINS"
  146. sed -i 's/"_plugins"/"plugins"/' "$CONFIG_FILE"
  147. jq --argjson allow_plugins "$ALLOW_PLUGINS" \
  148. '.settings.plugins.enabled = $allow_plugins' \
  149. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  150. else
  151. echo "Invalid or no ALLOWPLUGINS value given, commenting out so default applies... Value given: $ALLOW_PLUGINS"
  152. sed -i 's/"plugins":/"_plugins":/g' "$CONFIG_FILE"
  153. fi
  154. # WEBRTC
  155. WEBRTC=${WEBRTC,,}
  156. if [[ $WEBRTC =~ ^(true|false)$ ]]; then
  157. echo "Setting WebRTC... $WEBRTC"
  158. sed -i 's/"_WebRTC"/"WebRTC"/' "$CONFIG_FILE"
  159. jq --argjson webrtc "$WEBRTC" \
  160. '.settings.WebRTC = $webrtc' \
  161. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  162. #sed -i "s/\"WebRTC\": *[a-z]*/\"WebRTC\": $WEBRTC/" "$CONFIG_FILE"
  163. else
  164. echo "Invalid or no WEBRTC value given, commenting out so default applies... Value given: $WEBRTC"
  165. sed -i 's/"WebRTC":/"_WebRTC":/g' "$CONFIG_FILE"
  166. fi
  167. # IFRAME
  168. IFRAME=${IFRAME,,}
  169. if [[ $IFRAME =~ ^(true|false)$ ]]; then
  170. echo "Setting AllowFraming... $IFRAME"
  171. sed -i 's/"_AllowFraming"/"AllowFraming"/' "$CONFIG_FILE"
  172. jq --argjson allow_framing "$IFRAME" \
  173. '.settings.AllowFraming = $allow_framing' \
  174. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  175. else
  176. echo "Invalid or no IFRAME value given, commenting out so default applies... Value given: $IFRAME"
  177. sed -i 's/"AllowFraming":/"_AllowFraming":/g' "$CONFIG_FILE"
  178. fi
  179. # TLS_OFFLOAD
  180. TLS_OFFLOAD=${TLS_OFFLOAD,,}
  181. if [[ $TLS_OFFLOAD =~ ^(true|false)$ ]]; then
  182. echo "Setting TLSOffload... $TLS_OFFLOAD"
  183. sed -i 's/"_TLSOffload"/"TLSOffload"/' "$CONFIG_FILE"
  184. jq --argjson tls_offload "$TLS_OFFLOAD" \
  185. '.settings.TLSOffload = $tls_offload' \
  186. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  187. else
  188. echo "Invalid or no TLS_OFFLOAD value given, commenting out so default applies... Value given: $TLS_OFFLOAD"
  189. sed -i 's/"TLSOffload":/"_TLSOffload":/g' "$CONFIG_FILE"
  190. fi
  191. # trustedProxy
  192. if [[ -n $TRUSTED_PROXY ]]; then
  193. echo "Setting trustedProxy... - $TRUSTED_PROXY"
  194. if [[ $TRUSTED_PROXY == "all" ]] || [[ $TRUSTED_PROXY == "true" ]]; then
  195. sed -i 's/"_trustedProxy"/"trustedProxy"/' "$CONFIG_FILE"
  196. jq --argjson trusted_proxy "true" \
  197. '.settings.trustedProxy = $trusted_proxy' \
  198. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  199. else
  200. sed -i 's/"_trustedProxy"/"trustedProxy"/' "$CONFIG_FILE"
  201. jq --argjson trusted_proxy "$TRUSTED_PROXY" \
  202. '.settings.trustedProxy = $trusted_proxy' \
  203. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  204. fi
  205. fi
  206. # ALLOW_NEW_ACCOUNTS
  207. ALLOW_NEW_ACCOUNTS=${ALLOW_NEW_ACCOUNTS,,}
  208. if [[ $ALLOW_NEW_ACCOUNTS =~ ^(true|false)$ ]]; then
  209. echo "Setting NewAccounts... $ALLOW_NEW_ACCOUNTS"
  210. sed -i 's/"_NewAccounts"/"NewAccounts"/' "$CONFIG_FILE"
  211. jq --argjson new_accounts "$ALLOW_NEW_ACCOUNTS" \
  212. '.domains[""].NewAccounts = $new_accounts' \
  213. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  214. else
  215. echo "Invalid or no ALLOW_NEW_ACCOUNTS value given, commenting out so default applies... Value given: $ALLOW_NEW_ACCOUNTS"
  216. sed -i 's/"NewAccounts":/"_NewAccounts":/g' "$CONFIG_FILE"
  217. fi
  218. # LOCALSESSIONRECORDING
  219. LOCAL_SESSION_RECORDING=${LOCAL_SESSION_RECORDING,,}
  220. if [[ $LOCAL_SESSION_RECORDING =~ ^(true|false)$ ]]; then
  221. echo "Setting localSessionRecording... $LOCAL_SESSION_RECORDING"
  222. sed -i 's/"_localSessionRecording"/"localSessionRecording"/' "$CONFIG_FILE"
  223. jq --argjson session_recording "$LOCAL_SESSION_RECORDING" \
  224. '.domains[""].localSessionRecording = $session_recording' \
  225. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  226. else
  227. echo "Invalid or no LOCALSESSIONRECORDING value given, commenting out so default applies... Value given: $LOCAL_SESSION_RECORDING"
  228. sed -i 's/"localSessionRecording":/"_localSessionRecording":/g' "$CONFIG_FILE"
  229. fi
  230. # MINIFY
  231. MINIFY=${MINIFY,,}
  232. if [[ $MINIFY =~ ^(true|false)$ ]]; then
  233. echo "Setting minify... $MINIFY"
  234. sed -i 's/"_minify"/"minify"/' "$CONFIG_FILE"
  235. jq --argjson minify "$MINIFY" \
  236. '.domains[""].minify = $minify' \
  237. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  238. #sed -i "s/\"minify\": *[a-z]*/\"minify\": $MINIFY/" "$CONFIG_FILE"
  239. else
  240. echo "Invalid or no MINIFY value given, commenting out so default applies... Value given: $MINIFY"
  241. sed -i 's/"minify":/"_minify":/g' "$CONFIG_FILE"
  242. fi
  243. # ALLOWED_ORIGIN
  244. ALLOWED_ORIGIN=${ALLOWED_ORIGIN,,}
  245. if [[ $ALLOWED_ORIGIN =~ ^(true|false)$ ]]; then
  246. echo "Setting allowedOrigin... $ALLOWED_ORIGIN"
  247. sed -i 's/"_allowedOrigin"/"allowedOrigin"/' "$CONFIG_FILE"
  248. jq --argjson allowed_origin "$ALLOWED_ORIGIN" \
  249. '.domains[""].allowedOrigin = $allowed_origin' \
  250. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  251. else
  252. echo "Invalid or no ALLOWED_ORIGIN value given, commenting out so default applies... Value given: $ALLOWED_ORIGIN"
  253. sed -i 's/"allowedOrigin":/"_allowedOrigin":/g' "$CONFIG_FILE"
  254. fi
  255. # certUrl
  256. if [[ -n $REVERSE_PROXY ]] && [[ -n $REVERSE_PROXY_TLS_PORT ]]; then
  257. REVERSE_PROXY_STRING="${REVERSE_PROXY}:${REVERSE_PROXY_TLS_PORT}"
  258. echo "Setting certUrl... - $REVERSE_PROXY_STRING"
  259. sed -i 's/"_certUrl"/"certUrl"/' "$CONFIG_FILE"
  260. jq --arg cert_url "$REVERSE_PROXY_STRING" \
  261. '.domains[""].certUrl = $cert_url' \
  262. "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE"
  263. #sed -i "s/\"certUrl\": *[a-z]*/\"certUrl\": $REVERSE_PROXY_STRING/" "$CONFIG_FILE"
  264. else
  265. echo "Invalid or no REVERSE_PROXY and/or REVERSE_PROXY_TLS_PORT value given, commenting out so default applies... Value(s) given: $REVERSE_PROXY_STRING"
  266. sed -i 's/"certUrl":/"_certUrl":/g' "$CONFIG_FILE"
  267. fi
  268. cat "$CONFIG_FILE"
  269. }
  270. function install_stylishui() {
  271. # Start by testing if we can determine compatibility
  272. printf "Testing compatibility schema URL..."
  273. if ! test_url $stylishui_compat; then
  274. echo "Compat URL failed."
  275. return 1
  276. fi
  277. if [[ ${STYLISHUI_FORCE_LATEST,,} =~ ^(true|yes)$ ]]; then
  278. echo "Overriding to main branch..."
  279. full_url="${stylishui_base_url}/heads/main.tar.gz"
  280. else
  281. # Retrieve the values we need to determine compatibility
  282. compat_data=$(curl -fsSL $stylishui_compat)
  283. meshcentral_version=$(jq -r '.version' /opt/meshcentral/meshcentral/package.json)
  284. # Target the StylishUI version we need for our present Meshcentral version
  285. compat_version=$(echo "$compat_data" | jq -r --arg mcv "$meshcentral_version" \
  286. '.compatibility[] | select(.meshcentral==$mcv) | .stylishui')
  287. echo "Data: MeshCentral: $meshcentral_version, matched StylishUI: $compat_version"
  288. # From the data gathered above, compile the whole URL.
  289. full_url="${stylishui_base_url}/tags/${compat_version}.tar.gz"
  290. fi
  291. # Test if we can reach the data/content URL on github
  292. printf "Testing content URL..."
  293. if ! test_url $full_url; then
  294. echo "StylishUI URL failed."
  295. return 1
  296. fi
  297. # Lets download and install the UI
  298. wget -O /tmp/stylishui.tar.gz $full_url > /dev/null
  299. tar -xzf /tmp/stylishui.tar.gz -C /tmp
  300. web_folder=$(find /tmp -name meshcentral-web)
  301. # Check if we have some integrity
  302. if [[ -z $web_folder ]]; then
  303. echo "Installation failed, cleaning..."
  304. rm /tmp/stylishui*
  305. return 1
  306. fi
  307. # Looks good!
  308. echo "Found extracted contents at: ${web_folder}"
  309. if [[ -d /opt/meshcentral/meshcentral-web/public ]]; then
  310. mkdir -p /tmp/web-backup
  311. find /opt/meshcentral/meshcentral-web/public -maxdepth 1 -type f -exec mv {} /tmp/web-backup/ \;
  312. rm -rf /opt/meshcentral/meshcentral-web/public
  313. fi
  314. echo "Merging!"
  315. mv "${web_folder}/"* /opt/meshcentral/meshcentral-web/
  316. if [[ -d /tmp/web-backup ]]; then
  317. mv /tmp/web-backup/* /opt/meshcentral/meshcentral-web/public/ 2>/dev/null || true
  318. rm -rf /tmp/web-backup
  319. fi
  320. return 0
  321. }
  322. ### Start MeshCentral Docker Container.
  323. ### BEGIN MAIN CHAIN
  324. # Make the start more cleared when restarted.
  325. echo "-------------------------------------------------------------"
  326. date
  327. if [ -n "$CONFIG_FILE" ]; then
  328. echo "Config file: $CONFIG_FILE"
  329. else
  330. exit 1
  331. fi
  332. # Failsafe to create a new config if the expected config is not there.
  333. if [ -f "${CONFIG_FILE}" ]; then
  334. echo "Pre-existing config found, not recreating..."
  335. else
  336. if [ ! -d $(dirname "$CONFIG_FILE") ]; then
  337. echo "Creating meshcentral-data directory..."
  338. mkdir -p /opt/meshcentral/meshcentral-data
  339. fi
  340. echo "Placing template into the relevant directory: $(dirname $CONFIG_FILE)"
  341. cp /opt/meshcentral/config.json.template "${CONFIG_FILE}"
  342. fi
  343. if [[ ${DYNAMIC_CONFIG,,} =~ ^(true|yes)$ ]]; then
  344. echo "-------------------------------------------------------------"
  345. echo "Using Dynamic Configuration values..."
  346. dynamic_config
  347. echo "-------------------------------------------------------------"
  348. else
  349. echo "Leaving config as-is. Dynamic Configuration is off."
  350. fi
  351. if [[ ${INSTALL_STYLISHUI,,} =~ ^(true|yes)$ ]]; then
  352. echo "-------------------------------------------------------------"
  353. echo "Reached StylishUI install trigger, installing..."
  354. if ! install_stylishui; then
  355. echo "Something fatal happened in the StylishUI install. Skipping..."
  356. else
  357. echo "StylishUI has been installed!"
  358. fi
  359. echo "-------------------------------------------------------------"
  360. fi
  361. # Actually start MeshCentral.
  362. node /opt/meshcentral/meshcentral/meshcentral --configfile "${CONFIG_FILE}" "${ARGS}" >> /proc/1/fd/1 &
  363. meshcentral_pid=$!
  364. wait "$meshcentral_pid"
  365. ### END MAIN CHAIN