11#! /usr/bin/with-contenv bashio
22
3- # Read required options
3+ # ── Read options ──────────────────────────────────────────────────────────────
44SERVER_MODE=$( bashio::config ' server_mode' )
55NEW_ACCOUNTS=$( bashio::config ' new_accounts' )
66DOMAIN_TITLE=$( bashio::config ' domain_title' )
77SESSION_TIME=$( bashio::config ' session_time' )
88TLS_OFFLOAD=$( bashio::config ' tls_offload' )
99WEB_RTC=$( bashio::config ' web_rtc' )
1010COMPRESSION=$( bashio::config ' compression' )
11+ ALLOW_HQ_DESKTOP=$( bashio::config ' allow_high_quality_desktop' )
1112SELF_UPDATE=$( bashio::config ' self_update' )
1213MAINTENANCE=$( bashio::config ' maintenance_mode' )
14+ NO_2FA=$( bashio::config ' no_2fa' )
15+ SITE_STYLE=$( bashio::config ' site_style' )
16+ GUEST_SHARING=$( bashio::config ' guest_device_sharing' )
17+ ALLOW_FRAMING=$( bashio::config ' allow_framing' )
18+ LOGIN_COUNT=$( bashio::config ' max_invalid_login_count' )
19+ LOGIN_TIME=$( bashio::config ' max_invalid_login_time' )
20+ AUTO_REMOVE=$( bashio::config ' auto_remove_inactive_devices' )
21+ AGENT_PORT=$( bashio::config ' agent_port' )
22+ MPS_PORT=$( bashio::config ' mps_port' )
23+ BACKUP_INTERVAL=$( bashio::config ' backup_interval_hours' )
24+ BACKUP_KEEP=$( bashio::config ' backup_keep_days' )
1325SMTP_ENABLED=$( bashio::config ' smtp_enabled' )
1426
15- # Data path — fixed location inside HA addon data
27+ # ── Paths ─────────────────────────────────────────────────────────────────────
1628DATA_PATH=" /data/meshcentral-data"
1729FILES_PATH=" ${DATA_PATH} /meshcentral-files"
1830BACKUP_PATH=" /data/meshcentral-backups"
1931RECORDINGS_PATH=" ${DATA_PATH} /meshcentral-recordings"
2032CONFIG_FILE=" ${DATA_PATH} /config.json"
2133
22- # Use HA hostname as fallback
34+ # ── Hostname ──────────────────────────────────────────────────────────────────
2335HOSTNAME=$( bashio::info.hostname)
2436if bashio::config.has_value ' hostname' ; then
2537 HOSTNAME=$( bashio::config ' hostname' )
@@ -31,16 +43,14 @@ bashio::log.info "Hostname: ${HOSTNAME}"
3143
3244mkdir -p " ${DATA_PATH} " " ${FILES_PATH} " " ${BACKUP_PATH} " " ${RECORDINGS_PATH} "
3345
34- # Remove old certs on every start so MeshCentral regenerates them with current config
35- # This ensures the cert CN always matches the current IP/hostname
46+ # ── Remove old certs so MeshCentral regenerates with current config ───────────
3647MESHDATA=" ${DATA_PATH} /meshcentral-data"
3748if [ -d " $MESHDATA " ]; then
3849 rm -f " $MESHDATA " /* .crt " $MESHDATA " /* .key 2> /dev/null || true
3950 bashio::log.info " Old certificates removed — will be regenerated with current settings."
4051fi
4152
4253# ── Build settings ────────────────────────────────────────────────────────────
43-
4454SETTINGS=" {}"
4555
4656# Network mode
@@ -49,14 +59,18 @@ if [ "$SERVER_MODE" = "wan" ]; then
4959elif [ " $SERVER_MODE " = " lan" ]; then
5060 SETTINGS=$( echo " $SETTINGS " | jq ' . + {LANonly: true}' )
5161fi
52- # hybrid: neither flag set — MeshCentral default behaviour
5362
54- # Ports — MeshCentral listens directly on external ports to avoid origin mismatch
55- SETTINGS=$( echo " $SETTINGS " | jq ' . + {port: 4430, redirPort: 4431, mpsPort: 4433}' )
63+ # Ports
64+ SETTINGS=$( echo " $SETTINGS " | jq \
65+ --argjson mps " $MPS_PORT " \
66+ ' . + {port: 4430, redirPort: 4431, mpsPort: $mps}' )
67+
68+ # Optional dedicated agent port
69+ if [ " $AGENT_PORT " -gt 0 ] 2> /dev/null; then
70+ SETTINGS=$( echo " $SETTINGS " | jq --argjson v " $AGENT_PORT " ' . + {agentPort: $v}' )
71+ fi
5672
57- # Cert — determines what hostname MeshCentral uses for its certificate
58- # and origin validation. Use cert_url if set (external), otherwise
59- # homeassistant.local which works on any local network without knowing IP.
73+ # Cert / hostname
6074if bashio::config.has_value ' cert_url' ; then
6175 CERT_HOST=$( bashio::config ' cert_url' | sed ' s|https://||' | sed ' s|http://||' | sed ' s|/.*||' )
6276 SETTINGS=$( echo " $SETTINGS " | jq --arg v " $CERT_HOST " ' . + {cert: $v}' )
@@ -67,28 +81,38 @@ SETTINGS=$(echo "$SETTINGS" | jq --argjson v "$TLS_OFFLOAD" '. + {tlsOffload: $v
6781
6882# Trusted proxy (optional)
6983if bashio::config.has_value ' trusted_proxy' ; then
70- TRUSTED_PROXY=$( bashio::config ' trusted_proxy' )
71- SETTINGS=$( echo " $SETTINGS " | jq --arg v " $TRUSTED_PROXY " ' . + {trustedProxy: $v}' )
84+ SETTINGS=$( echo " $SETTINGS " | jq --arg v " $( bashio::config ' trusted_proxy' ) " ' . + {trustedProxy: $v}' )
7285fi
7386
7487# Session
7588SETTINGS=$( echo " $SETTINGS " | jq --argjson v " $SESSION_TIME " ' . + {sessionTime: $v}' )
7689if bashio::config.has_value ' session_key' ; then
77- SESSION_KEY=$( bashio::config ' session_key' )
78- SETTINGS=$( echo " $SETTINGS " | jq --arg v " $SESSION_KEY " ' . + {sessionKey: $v}' )
90+ SETTINGS=$( echo " $SETTINGS " | jq --arg v " $( bashio::config ' session_key' ) " ' . + {sessionKey: $v}' )
7991fi
8092
8193# Features
8294SETTINGS=$( echo " $SETTINGS " | jq \
83- --argjson rtc " $WEB_RTC " \
95+ --argjson rtc " $WEB_RTC " \
8496 --argjson comp " $COMPRESSION " \
85- --argjson upd " $SELF_UPDATE " \
86- ' . + {webRTC: $rtc, compression: $comp, selfUpdate: $upd}' )
97+ --argjson hq " $ALLOW_HQ_DESKTOP " \
98+ --argjson upd " $SELF_UPDATE " \
99+ --argjson fr " $ALLOW_FRAMING " \
100+ ' . + {webRTC: $rtc, compression: $comp, allowHighQualityDesktop: $hq, selfUpdate: $upd, allowFraming: $fr}' )
87101
88102if [ " $MAINTENANCE " = " true" ]; then
89103 SETTINGS=$( echo " $SETTINGS " | jq ' . + {maintenanceMode: true}' )
90104fi
91105
106+ if [ " $NO_2FA " = " true" ]; then
107+ SETTINGS=$( echo " $SETTINGS " | jq ' . + {no2FactorAuth: true}' )
108+ fi
109+
110+ # Invalid login rate limiting
111+ SETTINGS=$( echo " $SETTINGS " | jq \
112+ --argjson cnt " $LOGIN_COUNT " \
113+ --argjson tim " $LOGIN_TIME " \
114+ ' . + {maxInvalidLogin: {count: $cnt, time: $tim}}' )
115+
92116# IP access control (all optional)
93117if bashio::config.has_value ' user_allowed_ip' ; then
94118 SETTINGS=$( echo " $SETTINGS " | jq --arg v " $( bashio::config ' user_allowed_ip' ) " ' . + {userAllowedIP: $v}' )
@@ -103,30 +127,47 @@ if bashio::config.has_value 'agent_blocked_ip'; then
103127 SETTINGS=$( echo " $SETTINGS " | jq --arg v " $( bashio::config ' agent_blocked_ip' ) " ' . + {agentBlockedIP: $v}' )
104128fi
105129
106- # Autobackup — placeres uden for DATA_PATH
107- SETTINGS=$( echo " $SETTINGS " | jq --arg bp " $BACKUP_PATH " ' . + {autoBackup: {backupPath: $bp}}' )
130+ # Autobackup
131+ BACKUP_JSON=$( jq -n \
132+ --arg bp " $BACKUP_PATH " \
133+ --argjson ivl " $BACKUP_INTERVAL " \
134+ --argjson kp " $BACKUP_KEEP " \
135+ ' {backupPath: $bp, backupIntervalHours: $ivl, keepLastDaysBackup: $kp}' )
136+ if bashio::config.has_value ' backup_zip_password' ; then
137+ BACKUP_JSON=$( echo " $BACKUP_JSON " | jq --arg v " $( bashio::config ' backup_zip_password' ) " ' . + {zipPassword: $v}' )
138+ fi
139+ SETTINGS=$( echo " $SETTINGS " | jq --argjson v " $BACKUP_JSON " ' . + {autoBackup: $v}' )
108140
109141# ── Build domain ──────────────────────────────────────────────────────────────
110-
111142DOMAIN=" {}"
112- DOMAIN=$( echo " $DOMAIN " | jq --arg v " $DOMAIN_TITLE " ' . + {title: $v}' )
143+ DOMAIN=$( echo " $DOMAIN " | jq \
144+ --arg ttl " $DOMAIN_TITLE " \
145+ --argjson na " $NEW_ACCOUNTS " \
146+ --argjson ss " $SITE_STYLE " \
147+ --argjson gs " $GUEST_SHARING " \
148+ --argjson ar " $AUTO_REMOVE " \
149+ ' . + {title: $ttl, newAccounts: $na, siteStyle: $ss, guestDeviceSharing: $gs, autoRemoveInactiveDevices: $ar}' )
113150
114151if bashio::config.has_value ' domain_title2' ; then
115152 DOMAIN=$( echo " $DOMAIN " | jq --arg v " $( bashio::config ' domain_title2' ) " ' . + {title2: $v}' )
116153fi
117154
118- DOMAIN=$( echo " $DOMAIN " | jq --argjson v " $NEW_ACCOUNTS " ' . + {newAccounts: $v}' )
155+ if bashio::config.has_value ' welcome_text' ; then
156+ DOMAIN=$( echo " $DOMAIN " | jq --arg v " $( bashio::config ' welcome_text' ) " ' . + {welcomeText: $v}' )
157+ fi
158+
159+ if bashio::config.has_value ' new_accounts_pass' ; then
160+ DOMAIN=$( echo " $DOMAIN " | jq --arg v " $( bashio::config ' new_accounts_pass' ) " ' . + {newAccountsPass: $v}' )
161+ fi
119162
120- # certUrl — required for agents connecting from outside LAN
121163if bashio::config.has_value ' cert_url' ; then
122164 DOMAIN=$( echo " $DOMAIN " | jq --arg v " $( bashio::config ' cert_url' ) " ' . + {certUrl: $v}' )
123165fi
124166
125167DOMAIN=$( echo " $DOMAIN " | jq --arg rp " $RECORDINGS_PATH " \
126168 ' . + {sessionRecording: {filepath: $rp}}' )
127169
128- # ── Build SMTP (only if enabled and host is set) ──────────────────────────────
129-
170+ # ── Build SMTP ────────────────────────────────────────────────────────────────
130171SMTP_JSON=" null"
131172if [ " $SMTP_ENABLED " = " true" ] && bashio::config.has_value ' smtp_host' ; then
132173 SMTP_PORT=587
@@ -146,7 +187,6 @@ if [ "$SMTP_ENABLED" = "true" ] && bashio::config.has_value 'smtp_host'; then
146187fi
147188
148189# ── Assemble and write config.json ────────────────────────────────────────────
149-
150190if [ " $SMTP_JSON " = " null" ]; then
151191 CONFIG=$( jq -n \
152192 --argjson settings " $SETTINGS " \
@@ -168,7 +208,6 @@ if [ "$NEW_ACCOUNTS" = "true" ]; then
168208fi
169209
170210# ── Start MeshCentral ─────────────────────────────────────────────────────────
171-
172211bashio::log.info " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
173212bashio::log.info " MeshCentral is starting..."
174213bashio::log.info " Open in browser (accept certificate warning):"
@@ -177,7 +216,6 @@ bashio::log.info " Or via HTTP redirect:"
177216bashio::log.info " http://homeassistant.local:4431"
178217bashio::log.info " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
179218
180- bashio::log.info " Starting MeshCentral node process..."
181219exec node /opt/meshcentral/node_modules/meshcentral \
182220 --datapath " ${DATA_PATH} " \
183221 --filespath " ${FILES_PATH} "
0 commit comments