City Hall IT

Moving SALTO Space to a new server, and the port that wouldn't let go

Moving our door access server to Windows Server 2025 with the database left in place: no official guide, a stale URL reservation and a firewall surprise.

File no.
CH-0003
Filed
Reading time
11 min
On this page
  1. The short version
  2. Where we started
  3. No guide for this exact move
  4. Installing on the new server
  5. Cutting over
  6. Turning on HTTPS, and "The Dance"
  7. Chasing the firewall, which wasn't the problem
  8. The next morning: the actual cause
  9. Retiring the old server
  10. One last firewall surprise
  11. What I'd tell myself before starting
  12. Checklist for your own move

We're trying not to leave the Windows Server 2019 retirement to the last minute, so we're starting with the "low-hanging fruit": services that should be easy to move and low impact if something goes wrong. First up was SALTO Space, the platform that runs our door access control. It manages more than a hundred doors and a few hundred cardholders, and I've worked with SALTO for years, so it looked like a good warm-up.

It turned out to be a two-day job. Here's what happened, and what I'd tell anyone making the same move.

The short version

If you're here from a search engine with the same problem, here's the order that ended up working:

  1. Back up the Space database in SQL Server Management Studio.
  2. Build the new server and install the same Space version you're already running. Upgrade later as a separate step.
  3. Let the installer fail at the database step. The software still installs.
  4. Stop and disable the services on the old server.
  5. In the ProAccess Space Configuration tool on the new server, set the service account, point it at the existing database and start the services.
  6. Sign in to Space and confirm it as the primary install when it asks. After that there's no going back.
  7. Turn on HTTPS. If the web interface won't come up, look for a leftover HTTP.sys URL reservation on the web port (netsh http show urlacl).
  8. Open the web port with a port rule in Windows Defender Firewall. A program rule doesn't cover it.

The details, and the detours, are below.

Where we started

Space was running on a Windows Server 2019 VM, with its database on our dedicated SQL Server. The new home was a VM built from our standard Windows Server 2025 template. Because the database lives on its own server, the new VM didn't need extra disk. I set the name and IP address, joined it to the domain and installed the patches released since the template was last updated.

When I went to the SALTO software area to download the installer, I found we were a couple of releases behind: we were on 6.12.2.3, and the current release was 6.14.2.3. That raised the first real question.

No guide for this exact move

SALTO has good documentation for the pieces around this job:

None of them cover moving Space to a new server while leaving the database where it is. The unofficial write-ups I found all assumed the database moves with the application. So I had to choose between upgrading in place and then moving, or moving first and upgrading later.

I chose to move first and upgrade later, so only one thing would change at a time. Before touching anything, I took a full backup of the Space database in SQL Server Management Studio, so I had a known-good point to restore to if things went sideways.

The software area only offers current versions, so the 6.12.2.3 installer came from the old server's installers folder. Never delete old installers.

Installing on the new server

I treated this as a fresh install and followed the install guide, with a few changes.

Signing in as the service account. Our Space services run under a domain service account, and I wanted to run the installer as that account. RDP refused it, which is as it should be for a service account. I signed in with my admin account, added the service account to the server's local Administrators group, and signed back in as the service account.

The database step. I kept the default install path, since Space is the only thing on this server. At the database screen I picked Use existing SQL Server to upgrade an existing database or create a new one, then chose to upgrade the existing database. That gave me pause, since it was the same version, but there's no "just connect" option. The upgrade step failed with an error saying NT SERVICE\ProAccessSpaceService had no access to the database.

That's expected: the installer assumes Space runs under its local virtual service account, and ours runs under a domain account. I backed out to look for a better way and didn't find one. When I signed back in to try again, the software was already installed. Only the database step had failed, and the configuration tool can finish that part.

Cutting over

I told the team I was taking the old server offline, then stopped the Space services on the 2019 server and set them to Disabled. Stopping them isn't enough: a reboot or a well-meaning coworker could start them again, and two Space servers talking to the same database and the same doors is a mess you don't want.

On the new server, I opened the ProAccess Space Configuration tool as administrator:

  • Service Properties: changed the logon account from the virtual service account to our domain service account.
  • Database: pointed it at the existing SQL Server instance and database. I was signed in as the service account, so I could test with Windows authentication. The connection test passed and the database checked out.
  • Service Ports: Enable TCP/IP ports for web application was already checked. I saved, went back to Service Properties and started the services.

The services came up green, and I signed in to Space with our existing credentials.

The "primary install" warning

Right after sign-in, Space showed a large orange warning. We use JustIN Mobile, and Space had noticed it was now running somewhere new. Paraphrasing, since I didn't think to grab a screenshot: if this is a duplicate, stop; if this is a new install that should be the primary, make it the primary.

I confirmed it as the primary, which officially ended the "just testing" phase. Everything else checked out: the controllers showed up in the SALTO Network view, and so did the mobile encoder, which is usually the first device to sulk after any network or power change.

Know before you click it: once you confirm the new server as primary, there's no going back to the old one. Have your rollback plan settled before you sign in.

Turning on HTTPS, and "The Dance"

The new install was serving plain HTTP. That wasn't acceptable: it goes against general practice and against SALTO's own security recommendations, which are worth reading in full. The old server used a certificate from our internal certificate authority, so browsers on staff machines trusted it without a warning.

On the Service Ports tab I checked Use HTTPS, generated a self-signed certificate to prove the setting worked, selected it and clicked Save. The tool replied that you can't save while the services are running.

That message became the theme of the project. Every change went the same way, which I started calling The Dance:

  1. Service Properties: Stop the services.
  2. Service Ports: make the change and confirm it stuck.
  3. Save.
  4. Service Properties: Start the services.

With the self-signed certificate, the site loaded with the expected browser warning, and Space worked behind it. Next I requested a web server certificate from our internal CA, selected it in the drop-down and did The Dance.

The warning was still there. I cleared the cache and tried a private window, and it was still there. I inspected the certificate and found a typo in the server name. Another Dance: I turned HTTPS off, deleted both the self-signed and the misspelled certificates in the Certificates console, requested a new one (checking every character this time), turned HTTPS back on and selected the new certificate.

The services started. The URL didn't load at all.

Chasing the firewall, which wasn't the problem

Our 2025 template turns Windows Defender Firewall on, and none of the old server's rules come along to a new VM. That made the firewall the obvious suspect. I added an exception for the SALTO service: no change. I loosened the rules all the way to any/any/any: no change. I turned the firewall off for the domain profile: still no change.

Event Viewer and the firewall logs showed nothing useful. The clue was in the configuration tool itself. SALTO's check configuration page shows an error icon, and the same icon was sitting in the bottom-left corner of my configuration tool. The documentation only says to contact SALTO support, but now I knew something inside Space was failing.

The thing that misled me: the Space service reports "running" even when its web server fails to start. I'm used to services that are either on or off. In hindsight it makes sense, since doors should keep working even when the admin website is down. But it means a green status doesn't tell you the web interface is up.

The Service Ports tab has Verify buttons for each port. The TCP/IP port (8099 by default) passed. The web and SALTO Authentication port (8100 by default) failed. netstat agreed:

netstat -ano | findstr LISTENING
# 8099 and 8102 were listening. 8100 was missing.

As a test, I moved the web port to 8443 and did The Dance. Both ports verified, and the site loaded from the server and from my desk. By then it was well past the end of the day. The rest of the team uses Space too, and I didn't want to hand them a new port just to cover a problem I hadn't actually solved, so I stopped for the night.

The next morning: the actual cause

I moved the port back to 8100, the error icon came back with it, and 8100 again wasn't listening. Something was holding onto that port specifically.

The answer was in Space's own log, which I hadn't seen mentioned in the documentation. It's in the install folder, under Logs\SaltoService.log:

ERROR WebServiceEndpointModule - Exception Message : The prefix 'https://+:8100/' is already registered.

Space's web server runs on HTTP.sys, the Windows component behind IIS and many self-hosted services. HTTP.sys keeps its own list of URL reservations, separate from the application. The first HTTP-only start had left a reservation for http://+:8100/ behind, and it blocked the HTTPS listener on the same port:

# List URL reservations (run as administrator)
netsh http show urlacl
#   Reserved URL : http://+:8100/
#       User: DOMAIN\svc-account   <- left over from the HTTP-only setup

# Remove the stale reservation
netsh http delete urlacl url=http://+:8100/

After one more Dance (stop, set the port back to 8100, save, start), both ports verified. The site opened from the server and from my desk, sign-in worked, and live monitoring of doors and controllers was working.

If you hit the same error, the certificate binding for the port is also worth checking while you're in netsh:

netsh http show sslcert ipport=0.0.0.0:8100

Retiring the old server

Following our decommission process, I:

  • Renamed the 2019 server and confirmed its Space services were still disabled
  • Rebooted it, then ran ipconfig /registerdns so DNS picked up the new name
  • Added a DNS alias pointing the old name at the new server, so existing bookmarks keep working

Tip: if people reach Space by the old name over HTTPS, the certificate needs that name in its Subject Alternative Names too. Otherwise the alias works and browsers warn about the name mismatch.

One last firewall surprise

All that was left was turning Windows Defender Firewall back on. I used Allow an app or feature through Windows Defender Firewall to allow the SALTO ProAccess Space service on the domain profile, and the site loaded on the server itself. From my desk, the connection timed out.

netstat showed 8100 listening, but under a different process ID from the other two SALTO ports. tasklist matched those two to ProAccessSpace.exe. Port 8100 belonged to System.

That's HTTP.sys again. It runs in the kernel, so traffic to an HTTP.sys listener belongs to the System process (PID 4), not to the program that registered the URL. A firewall rule that allows ProAccessSpace.exe covers the ports that program opens itself, but not its web interface. You need a rule for the port:

# Which process owns the web port? On an HTTP.sys listener it's PID 4 (System).
Get-NetTCPConnection -LocalPort 8100 -State Listen | Select-Object LocalPort, OwningProcess

# Allow the web port on the domain profile.
# Add -RemoteAddress to limit it to your admin and workstation subnets if you can.
New-NetFirewallRule -DisplayName "SALTO Space web (HTTP.sys)" `
  -Direction Inbound -Protocol TCP -LocalPort 8100 -Profile Domain -Action Allow

I added the port rule, refreshed the page on my desk and it loaded, with the firewall on. Migration complete.

What I'd tell myself before starting

  • Move first, upgrade second. Changing one thing at a time made every problem easier to pin down.
  • Keep old installers. The vendor portal only offers current versions.
  • Disable the old services, don't just stop them, and expect to commit the moment you confirm the new server as primary.
  • "Running" doesn't mean the web interface is up. Watch for the error icon in the configuration tool and use the Verify buttons.
  • Read SaltoService.log first. It had the answer the whole time.
  • Anything served by HTTP.sys needs a port rule, and stale URL reservations can block a listener.

Checklist for your own move

  • Back up the Space database
  • Copy the installer for your current version from the old server
  • Build the new server and patch it
  • Install the same version; expect the database step to fail if you use a domain service account
  • Stop and disable the old services
  • In the configuration tool: set the service account, point it at the database, start the services
  • Sign in and confirm the new server as primary
  • Turn on HTTPS with a certificate whose names match every name people will use
  • If the web port won't listen, check SaltoService.log and netsh http show urlacl
  • Add a firewall port rule for the web port, scoped as tightly as you can
  • Rename the old server, register DNS and add an alias for the old name
  • Remove the service account from local Administrators if you only added it for the install
  • Schedule the version upgrade as its own change

We've since upgraded to 6.14.2.3 as its own change, and that will get its own post.