The problem was a missing dependency that wasn’t on the server but was on my local machine. In our case, it was a Devart.Data.Linq dll.
To get to that answer, I turned on IIS tracing for 500 errors. That gave a little bit of information, but the really helpful thing was in the web.config setting the <system.web><customErrors mode="Off"/></system.web>
This pointed to a missing dynamically-loaded dependency. After adding this dependency and telling it to be copied locally, the server started working.