Fix Node-RED container net: extra_hosts, CODE HTTPS, force-recreate
Detect host LAN IP and CODE URL so OCS/Collabora work unattended on each VM. Avoid 127.0.1.1 Nextcloud DNS and HTTP-to-TLS CODE.
This commit is contained in:
+10
-2
@@ -5,10 +5,16 @@
|
|||||||
NEXTCLOUD_URL=https://cloud.hannesahlin.se
|
NEXTCLOUD_URL=https://cloud.hannesahlin.se
|
||||||
NEXTCLOUD_PUBLIC_URL=https://cloud.hannesahlin.se
|
NEXTCLOUD_PUBLIC_URL=https://cloud.hannesahlin.se
|
||||||
|
|
||||||
# Collabora CODE — bridge IP auto-detected if COLLABORA_IP is empty
|
# Collabora CODE
|
||||||
|
# COLLABORA_URL: https://code:9980 när CODE delar Docker-nätverk med Node-RED
|
||||||
|
# (integrate-into-nodered.sh connectar CODE till nodernätet automatiskt).
|
||||||
|
# Fallback om 'code' inte kan resolvas: https://<CODE-IP>:9980.
|
||||||
|
# ALDRIG http://127.0.0.1:9980 eller http://host.docker.internal:9980 —
|
||||||
|
# CODE lyssnar bara på HTTPS internt och kör inte på Node-RED-värden.
|
||||||
|
# verifyTls=false sätts i nc-collab-config-noden (self-signed cert internt).
|
||||||
CODE_CONTAINER=code
|
CODE_CONTAINER=code
|
||||||
COLLABORA_IP=
|
COLLABORA_IP=
|
||||||
COLLABORA_URL=
|
COLLABORA_URL=https://code:9980
|
||||||
|
|
||||||
# Existing Node-RED install (integrate mode)
|
# Existing Node-RED install (integrate mode)
|
||||||
NODERED_DIR=
|
NODERED_DIR=
|
||||||
@@ -18,6 +24,8 @@ INSTALL_USER=
|
|||||||
|
|
||||||
# Sidecar mode (not default)
|
# Sidecar mode (not default)
|
||||||
NC_HOST=cloud.hannesahlin.se
|
NC_HOST=cloud.hannesahlin.se
|
||||||
|
# Host-LAN-IP för extra_hosts. Tomt = auto-detekteras av integrate-into-
|
||||||
|
# nodered.sh (hostname -I, 192.168.x/10.x), fallback 192.168.1.26.
|
||||||
NC_HOST_IP=
|
NC_HOST_IP=
|
||||||
TZ=Europe/Stockholm
|
TZ=Europe/Stockholm
|
||||||
NODERED_CREDENTIAL_SECRET=change-this-secret-in-production
|
NODERED_CREDENTIAL_SECRET=change-this-secret-in-production
|
||||||
|
|||||||
+2
-1
@@ -13,8 +13,9 @@ services:
|
|||||||
PORT: "1881"
|
PORT: "1881"
|
||||||
TZ: ${TZ:-Europe/Stockholm}
|
TZ: ${TZ:-Europe/Stockholm}
|
||||||
NEXTCLOUD_URL: ${NEXTCLOUD_URL:-https://cloud.hannesahlin.se}
|
NEXTCLOUD_URL: ${NEXTCLOUD_URL:-https://cloud.hannesahlin.se}
|
||||||
COLLABORA_URL: ${COLLABORA_URL:-http://172.17.0.2:9980}
|
COLLABORA_URL: ${COLLABORA_URL:-https://code:9980}
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
- "cloud.hannesahlin.se:${NC_HOST_IP:-192.168.1.26}"
|
- "cloud.hannesahlin.se:${NC_HOST_IP:-192.168.1.26}"
|
||||||
volumes:
|
volumes:
|
||||||
- nodered_collab_data:/data
|
- nodered_collab_data:/data
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ NODERED_CONTAINER="${NODERED_CONTAINER:-nextcloud-node-red}"
|
|||||||
NODERED_PORT="${NODERED_PORT:-1880}"
|
NODERED_PORT="${NODERED_PORT:-1880}"
|
||||||
CODE_CONTAINER="${CODE_CONTAINER:-code}"
|
CODE_CONTAINER="${CODE_CONTAINER:-code}"
|
||||||
COLLABORA_IP="${COLLABORA_IP:-}"
|
COLLABORA_IP="${COLLABORA_IP:-}"
|
||||||
|
# Aldrig http://127.0.0.1:9980 eller http://host.docker.internal:9980
|
||||||
|
case "${COLLABORA_URL:-https://code:9980}" in
|
||||||
|
http://127.0.0.1:*|http://localhost:*|http://host.docker.internal:*|\
|
||||||
|
https://127.0.0.1:*|https://localhost:*|https://host.docker.internal:*|"")
|
||||||
|
COLLABORA_URL="https://code:9980" ;;
|
||||||
|
*) COLLABORA_URL="${COLLABORA_URL}" ;;
|
||||||
|
esac
|
||||||
NEXTCLOUD_URL="${NEXTCLOUD_URL:-https://cloud.hannesahlin.se}"
|
NEXTCLOUD_URL="${NEXTCLOUD_URL:-https://cloud.hannesahlin.se}"
|
||||||
[ -n "${NEXTCLOUD_URL}" ] || NEXTCLOUD_URL="https://cloud.hannesahlin.se"
|
[ -n "${NEXTCLOUD_URL}" ] || NEXTCLOUD_URL="https://cloud.hannesahlin.se"
|
||||||
|
|
||||||
@@ -69,6 +76,7 @@ PKG_SRC="${INSTALL_DIR}" \
|
|||||||
NODERED_PORT="${NODERED_PORT}" \
|
NODERED_PORT="${NODERED_PORT}" \
|
||||||
CODE_CONTAINER="${CODE_CONTAINER}" \
|
CODE_CONTAINER="${CODE_CONTAINER}" \
|
||||||
COLLABORA_IP="${COLLABORA_IP}" \
|
COLLABORA_IP="${COLLABORA_IP}" \
|
||||||
|
COLLABORA_URL="${COLLABORA_URL}" \
|
||||||
NEXTCLOUD_URL="${NEXTCLOUD_URL}" \
|
NEXTCLOUD_URL="${NEXTCLOUD_URL}" \
|
||||||
INSTALL_USER="${INSTALL_USER:-}" \
|
INSTALL_USER="${INSTALL_USER:-}" \
|
||||||
bash "${SCRIPT_DIR}/scripts/integrate-into-nodered.sh"
|
bash "${SCRIPT_DIR}/scripts/integrate-into-nodered.sh"
|
||||||
|
|||||||
@@ -146,6 +146,45 @@ code_bridge_ip() {
|
|||||||
docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{if eq $k "bridge"}}{{$v.IPAddress}}{{end}}{{end}}' "${CODE_CONTAINER}" 2>/dev/null
|
docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{if eq $k "bridge"}}{{$v.IPAddress}}{{end}}{{end}}' "${CODE_CONTAINER}" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Host-LAN-IP för extra_hosts (detektera; fallback 192.168.1.26)
|
||||||
|
detect_host_lan_ip() {
|
||||||
|
local ip=""
|
||||||
|
if command -v hostname >/dev/null 2>&1; then
|
||||||
|
ip="$(hostname -I 2>/dev/null | tr ' ' '\n' \
|
||||||
|
| grep -E '^(192\.168|10)\.[0-9]+\.[0-9]+\.[0-9]+$' | head -n1 || true)"
|
||||||
|
fi
|
||||||
|
if [ -z "${ip}" ] && command -v ip >/dev/null 2>&1; then
|
||||||
|
ip="$(ip -4 addr show scope global 2>/dev/null | awk '/inet /{print $2}' | cut -d/ -f1 \
|
||||||
|
| grep -E '^(192\.168|10)\.' | head -n1 || true)"
|
||||||
|
fi
|
||||||
|
if [ -z "${ip}" ]; then
|
||||||
|
warn "Kunde inte detektera host-LAN-IP — fallback 192.168.1.26"
|
||||||
|
ip="192.168.1.26"
|
||||||
|
fi
|
||||||
|
HOST_LAN_IP="${ip}"
|
||||||
|
log "Host-LAN-IP: ${HOST_LAN_IP}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Skriv NC_HOST_IP i nextcloud-node-red/.env så compose-substitutionen plockar upp den
|
||||||
|
write_nodered_env_ip() {
|
||||||
|
local envfile="${NODERED_DIR}/.env"
|
||||||
|
local existing=""
|
||||||
|
if [ -f "${envfile}" ]; then
|
||||||
|
existing="$(grep -E '^NC_HOST_IP=[[:alnum:].:]+' "${envfile}" 2>/dev/null | tail -n1 | cut -d= -f2 || true)"
|
||||||
|
fi
|
||||||
|
if [ -n "${existing}" ]; then
|
||||||
|
log "${envfile} har redan NC_HOST_IP=${existing} — behåller"
|
||||||
|
HOST_LAN_IP="${existing}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ -f "${envfile}" ] && grep -q '^NC_HOST_IP=' "${envfile}" 2>/dev/null; then
|
||||||
|
run_as_root sed -i "s|^NC_HOST_IP=.*|NC_HOST_IP=${HOST_LAN_IP}|" "${envfile}"
|
||||||
|
else
|
||||||
|
run_as_root bash -c "echo 'NC_HOST_IP=${HOST_LAN_IP}' >> '${envfile}'"
|
||||||
|
fi
|
||||||
|
log "NC_HOST_IP=${HOST_LAN_IP} → ${envfile}"
|
||||||
|
}
|
||||||
|
|
||||||
detect_code_ip() {
|
detect_code_ip() {
|
||||||
local ip
|
local ip
|
||||||
ip="$(code_bridge_ip)"
|
ip="$(code_bridge_ip)"
|
||||||
@@ -202,6 +241,8 @@ resolve_paths() {
|
|||||||
|
|
||||||
detect_nodered_dir
|
detect_nodered_dir
|
||||||
detect_code_ip
|
detect_code_ip
|
||||||
|
detect_host_lan_ip
|
||||||
|
write_nodered_env_ip
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_sidecar_if_any() {
|
stop_sidecar_if_any() {
|
||||||
@@ -316,13 +357,85 @@ EOF
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Krav: docker network connect <nodered-nät> code — ignorerar already connected
|
||||||
connect_code_network() {
|
connect_code_network() {
|
||||||
log "Connecting ${NODERED_CONTAINER} to Docker bridge (CODE)"
|
local net
|
||||||
if docker network inspect bridge --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | grep -q "${NODERED_CONTAINER}"; then
|
net="$(docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{printf "%s\n" $k}}{{end}}' "${NODERED_CONTAINER}" 2>/dev/null \
|
||||||
log "Already connected to bridge"
|
| grep -v '^bridge$' | head -n1)"
|
||||||
else
|
[ -n "${net}" ] || die "No Node-RED compose network on ${NODERED_CONTAINER}"
|
||||||
docker network connect bridge "${NODERED_CONTAINER}" 2>/dev/null || warn "Could not connect bridge — check manually"
|
|
||||||
|
if docker network inspect "${net}" --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | grep -qw "${CODE_CONTAINER}"; then
|
||||||
|
log "Already connected: ${CODE_CONTAINER} on ${net}"
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log "Connecting ${CODE_CONTAINER} → ${net}"
|
||||||
|
if ! docker network connect "${net}" "${CODE_CONTAINER}" 2>/dev/null; then
|
||||||
|
if docker network inspect "${net}" --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | grep -qw "${CODE_CONTAINER}"; then
|
||||||
|
log "Already connected (race): ${CODE_CONTAINER} on ${net}"
|
||||||
|
else
|
||||||
|
warn "Could not connect ${CODE_CONTAINER} → ${net} — COLLABORA_URL fallar tillbaka till CODE-IP"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
compose_service_name() {
|
||||||
|
local svc
|
||||||
|
svc="$(docker inspect -f '{{index .Config.Labels "com.docker.compose.service"}}' "${NODERED_CONTAINER}" 2>/dev/null || true)"
|
||||||
|
echo "${svc:-node-red}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Recreate utan 'docker compose down' — volymer (node-red-data) bevaras.
|
||||||
|
# ExtraHosts måste vara ifyllda efteråt.
|
||||||
|
recreate_nodered_service() {
|
||||||
|
local service extra
|
||||||
|
service="$(compose_service_name)"
|
||||||
|
|
||||||
|
log "Recreating ${service} (--no-deps --force-recreate, volymer bevaras)..."
|
||||||
|
if ! compose_run up -d --no-deps --force-recreate "${service}"; then
|
||||||
|
warn "force-recreate misslyckades — rm + up --no-deps (volymen node-red-data ligger kvar)"
|
||||||
|
run_as_root docker rm -f "${NODERED_CONTAINER}" 2>/dev/null || true
|
||||||
|
compose_run up -d --no-deps "${service}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for _ in $(seq 1 10); do
|
||||||
|
extra="$(docker inspect -f '{{len .HostConfig.ExtraHosts}}' "${NODERED_CONTAINER}" 2>/dev/null || echo 0)"
|
||||||
|
[ "${extra}" != "0" ] && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
if [ -z "${extra:-0}" ] || [ "${extra}" = "0" ]; then
|
||||||
|
die "ExtraHosts är [] på ${NODERED_CONTAINER} efter recreate — kontrollera extra_hosts i ${NODERED_DIR}/docker-compose.yml"
|
||||||
|
fi
|
||||||
|
log "ExtraHosts (${extra}): $(docker inspect -f '{{json .HostConfig.ExtraHosts}}' "${NODERED_CONTAINER}")"
|
||||||
|
}
|
||||||
|
|
||||||
|
# COLLABORA_URL: https://code:9980 primärt, fallback https://<CODE-IP>:9980.
|
||||||
|
# Aldrig http://127.0.0.1:9980 eller http://host.docker.internal:9980.
|
||||||
|
resolve_collabora_url() {
|
||||||
|
local url="${COLLABORA_URL:-https://code:9980}"
|
||||||
|
case "${url}" in
|
||||||
|
http://127.0.0.1:*|http://localhost:*|http://host.docker.internal:*|\
|
||||||
|
https://127.0.0.1:*|https://localhost:*|https://host.docker.internal:*)
|
||||||
|
warn "Otillåten COLLABORA_URL '${url}' — tvingar https://code:9980"
|
||||||
|
url="https://code:9980"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Fallback till CODE-IP om 'code' inte kan resolvas från nod-containern
|
||||||
|
if ! docker exec "${NODERED_CONTAINER}" getent hosts code >/dev/null 2>&1; then
|
||||||
|
local ip
|
||||||
|
ip="$(docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$v.IPAddress}} {{end}}' "${CODE_CONTAINER}" 2>/dev/null | awk '{print $1}')"
|
||||||
|
[ -n "${ip}" ] || ip="${COLLABORA_IP:-}"
|
||||||
|
if [ -n "${ip}" ]; then
|
||||||
|
warn "'code' inte resolvbart från ${NODERED_CONTAINER} — fallback https://${ip}:9980"
|
||||||
|
url="https://${ip}:9980"
|
||||||
|
else
|
||||||
|
die "Varken 'code'-DNS eller CODE-IP tillgänglig — kan inte sätta COLLABORA_URL"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
COLLABORA_URL="${url}"
|
||||||
|
log "COLLABORA_URL=${COLLABORA_URL}"
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuild_nodered() {
|
rebuild_nodered() {
|
||||||
@@ -334,7 +447,7 @@ rebuild_nodered() {
|
|||||||
else
|
else
|
||||||
compose_run build
|
compose_run build
|
||||||
fi
|
fi
|
||||||
compose_run up -d
|
recreate_nodered_service
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_nodered() {
|
wait_nodered() {
|
||||||
@@ -350,18 +463,35 @@ wait_nodered() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
verify_code_from_nodered() {
|
verify_code_from_nodered() {
|
||||||
local code_ip
|
# Krav 7: getent i containern != 127.0.0.1/127.0.1.1 + curl mot CODE och Nextcloud
|
||||||
code_ip="$(code_bridge_ip)"
|
local fail=0 h ip_out
|
||||||
[ -n "${code_ip}" ] || code_ip="${COLLABORA_IP}"
|
for h in cloud.hannesahlin.se docs.hannesahlin.se host.docker.internal code; do
|
||||||
# CODE listens on HTTPS internally (HTTP returns empty reply)
|
ip_out="$(docker exec "${NODERED_CONTAINER}" getent hosts "${h}" 2>/dev/null | awk '{print $1}' | head -n1 || true)"
|
||||||
local url="https://${code_ip}:9980/hosting/capabilities"
|
if [ -z "${ip_out}" ]; then
|
||||||
log "Testing CODE from ${NODERED_CONTAINER}: ${url}"
|
warn "getent ${h}: INGET SVAR"; fail=1
|
||||||
if docker exec "${NODERED_CONTAINER}" curl -sfk "${url}" >/dev/null 2>&1; then
|
elif [ "${ip_out#127.}" != "${ip_out}" ] || [ "${ip_out}" = "::1" ]; then
|
||||||
log "OK: CODE reachable from Node-RED container"
|
warn "getent ${h}: loopback (${ip_out}) — extra_hosts/translering trasig"; fail=1
|
||||||
|
else
|
||||||
|
log "getent ${h}: ${ip_out}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if docker exec "${NODERED_CONTAINER}" curl -sfk "${COLLABORA_URL}/hosting/capabilities" >/dev/null 2>&1; then
|
||||||
|
log "OK: CODE nås från Node-RED: ${COLLABORA_URL}/hosting/capabilities"
|
||||||
else
|
else
|
||||||
warn "CODE not reachable — run: docker network connect bridge ${NODERED_CONTAINER}"
|
warn "CODE inte nåbar: ${COLLABORA_URL}/hosting/capabilities"
|
||||||
warn "nc-collab-config collaboraUrl=https://${code_ip}:9980 (verifyTls=false)"
|
warn "Kör: docker network connect \$(docker inspect -f '{{range \$k,\$_ := .NetworkSettings.Networks}}{{printf \"%s\\n\" \$k}}{{end}}' ${NODERED_CONTAINER} | head -n1) ${CODE_CONTAINER}"
|
||||||
|
fail=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if docker exec "${NODERED_CONTAINER}" curl -sfk https://cloud.hannesahlin.se/status.php >/dev/null 2>&1; then
|
||||||
|
log "OK: Nextcloud nås från Node-RED: https://cloud.hannesahlin.se/status.php"
|
||||||
|
else
|
||||||
|
warn "Nextcloud inte nåbar från Node-RED via https://cloud.hannesahlin.se/status.php"
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return "${fail}"
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
@@ -377,13 +507,14 @@ main() {
|
|||||||
patch_entrypoint
|
patch_entrypoint
|
||||||
rebuild_nodered
|
rebuild_nodered
|
||||||
connect_code_network
|
connect_code_network
|
||||||
|
resolve_collabora_url
|
||||||
wait_nodered
|
wait_nodered
|
||||||
verify_code_from_nodered
|
if ! verify_code_from_nodered; then
|
||||||
|
warn "Verifiering hade fel — se varningarna ovan"
|
||||||
|
fi
|
||||||
|
|
||||||
local host_ip code_ip nc_url
|
local host_ip nc_url
|
||||||
host_ip="$(hostname -I 2>/dev/null | awk '{print $1}' || echo "127.0.0.1")"
|
host_ip="$(hostname -I 2>/dev/null | awk '{print $1}' || echo "127.0.0.1")"
|
||||||
code_ip="$(code_bridge_ip)"
|
|
||||||
[ -n "${code_ip}" ] || code_ip="${COLLABORA_IP}"
|
|
||||||
nc_url="${NEXTCLOUD_URL:-https://cloud.hannesahlin.se}"
|
nc_url="${NEXTCLOUD_URL:-https://cloud.hannesahlin.se}"
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
@@ -394,7 +525,7 @@ Integrating done — same Node-RED on port ${NODERED_PORT}
|
|||||||
|
|
||||||
Create config first (gear → nc-collab-config):
|
Create config first (gear → nc-collab-config):
|
||||||
Nextcloud: ${nc_url}
|
Nextcloud: ${nc_url}
|
||||||
Collabora: https://${code_ip}:9980 (verifyTls=false)
|
Collabora: ${COLLABORA_URL} (verifyTls=false — self-signed internt)
|
||||||
Public WOPI: ${nc_url}
|
Public WOPI: ${nc_url}
|
||||||
Auth: username + app password
|
Auth: username + app password
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user