CaraOne 1.4 – Changing the BackOffice IP (Second NIC)

Scale Logic internal procedure. Placeholders: OLD_IP = the IP CaraOne was installed on; NEW_IP = the IP the BackOffice should be served on.

What this does

This procedure moves only the BackOffice web interface (port 9092) to NEW_IP. The CaraOne backend stays on OLD_IP: Ray, the Node Manager (9091) and the REST API (9090). The browser loads the BackOffice page from NEW_IP and then calls the Node Manager directly at OLD_IP:9091, so any machine used to open the BackOffice must be able to reach OLD_IP:9091.

This is not a full node re-IP. Ray's address is set by NODE_IP / HEAD_NODE_IP in /opt/caraone/head_node_runner.sh, and moving the whole node is a separate job (see Notes).

Prerequisites

Confirm NEW_IP is configured and up on the server. If it is not, nginx will fail to bind.

ip addr | grep NEW_IP

Step 1 – Back up the files you will touch

sudo su
cp /etc/nginx/sites-enabled/backoffice.conf /root/backoffice.conf.bak
cp /var/www/backoffice/config.json /root/config.json.bak
cp /opt/caraone/dist/node_registry.json /root/node_registry.json.bak
cp /opt/caraone/dist/settings/settings.json /root/settings.json.bak

Step 2 – Change the nginx listen address

Edit /etc/nginx/sites-enabled/backoffice.conf and change only the first listen line:

listen NEW_IP:9092;

Do not change the proxy_pass line in the /api/ block. It must stay pointed at OLD_IP:9091, because that is where the Node Manager listens.

nginx -t
systemctl restart nginx

Step 3 – Leave BackOffice config.json pointing at OLD_IP

/var/www/backoffice/config.json tells the browser where the backend is. Both hosts must stay on OLD_IP and keep the http:// prefix:

{
  "mainNode":    { "port": 9090, "host": "http://OLD_IP", "user": "admin" },
  "nodeManager": { "port": 9091, "host": "http://OLD_IP" }
}

Do not point these at NEW_IP. Nothing listens on NEW_IP:9091, and the BackOffice will show "An unhandled error has occurred."

Step 4 – Do not change REST_API_IP in settings.json

Changing REST_API_IP to NEW_IP and restarting does not move the backend. Ray and the Node Manager stay on OLD_IP, and the Node Manager registers a second, incomplete entry for the same host in node_registry.json, which crashes the BackOffice dashboard (see Troubleshooting).

Step 5 – Verify

ss -tulpn | grep -E '9091|9092'
curl -s -o /dev/null -w "%{http_code}\n" http://NEW_IP:9092

Expected: 9092 listening on NEW_IP, 9091 listening on OLD_IP, and curl returns 200.

Then open http://NEW_IP:9092 in a browser, hard-reload (Ctrl+Shift+R), log in, and confirm the dashboard shows exactly one node with live status. Test from a user workstation as well as from the server itself.

Step 6 – Save a known-good copy

mkdir -p /root/known-good-$(date +%F)
cp /etc/nginx/sites-enabled/backoffice.conf /var/www/backoffice/config.json /opt/caraone/dist/node_registry.json /opt/caraone/dist/settings/settings.json /root/known-good-$(date +%F)/

Troubleshooting

"An unhandled error has occurred" – page loads, dashboard never appears

Check /var/log/nginx/backoffice_access.log. If the only requests are /, /_framework/blazor.boot.json, /config.json and /version.txt, the browser loaded the app but cannot reach the backend. Check the hosts in config.json and confirm something is listening on that IP and port with ss -tulpn. Also confirm the user's workstation can route to OLD_IP:9091.

"An unhandled error has occurred" – after login

Open the browser console (F12, Console tab) and reload. A NullReferenceException in CaraOneBackOffice.Components.NodeComponent means node_registry.json has a duplicate entry for the same hostname, usually left behind after an IP change. The stale entry is missing "active_type". The getClusterStatus response in the console will list two nodes with the same name.

Fix (Troubleshooting Guide §07.2):

cat /opt/caraone/dist/node_registry.json
cp /opt/caraone/dist/node_registry.json /root/node_registry.json.bak
systemctl stop caraone_node_manager
vi /opt/caraone/dist/node_registry.json      # remove the stale IP's block, keep OLD_IP
python3 -m json.tool /opt/caraone/dist/node_registry.json > /dev/null && echo JSON_OK
systemctl start caraone_node_manager
cat /opt/caraone/dist/node_registry.json

Stop the Node Manager before editing, or it may rewrite the file underneath you. After it starts, the file should show one entry with "connected": true, and the stale IP should not come back. Hard-reload the BackOffice.

nginx fails to start

Look for: bind() to NEW_IP:9092 failed (99: Cannot assign requested address). NEW_IP is not up on the server. Bring the interface up first, then restart nginx.

Finding files

node_registry.json is at /opt/caraone/dist/node_registry.json. Do not use find / on these servers; it crawls the media mounts and can run for a very long time. Use: find /opt /etc /var/lib -name <file>

Rollback

Restore the files from Step 1, then:

nginx -t
systemctl restart nginx
systemctl stop caraone_node_manager
systemctl start caraone_node_manager

Notes

  • Installer updates: running linux_setup with --update asks for the node IP and will likely reset backoffice.conf to it. After any CaraOne update, check the listen line and re-apply Step 2 if needed.

  • Reboots: if NEW_IP comes up after nginx starts at boot, nginx will fail to bind and the BackOffice will be down. After the first reboot, check systemctl status nginx.

  • Client Server URL: CaraOne clients connect to the REST API on OLD_IP:9090. Do not change client Server URLs as part of this procedure.

  • Users on the NEW_IP network only: if they cannot route to OLD_IP:9091, the dashboard will fail for them. The untested option is an nginx listener on NEW_IP:9091 that forwards to OLD_IP:9091. Confirm with Obvious Future before deploying.

  • Full node re-IP (Ray, Node Manager, REST API): not covered here. Check with Obvious Future for the supported method; re-running the installer IP selection is the likely path.

  • settings.json is rewritten by CaraOne whenever it loads (defaults are merged in, and a .bak and .lock appear). Always back it up before editing and validate it afterwards.