With appropriate vectoring of requests and server-side state (i.e. having an indirection at the appropriate point), you can do live upgrades almost anywhere. I was doing it with ASP.NET years ago; concurrent versions of the application running, new sessions getting the latest version, while old sessions ran with whatever version they started with, all on the same machine, in the same ASP.NET worker process etc. as desired.
Of course, if you want to maintain things like existing TCP connections while not having multiple versions of application code running simultaneously, it gets much harder, but that approach also restricts how drastic an upgrade you can perform - ultimately, all the socket handles, file handles, etc. need to be assigned to all the right fields.
Just so you know, the approach Erlang takes is to keep old, active versions of applications around in memory. File handles and such are never reassigned to newer versions. Applications are garbage collected once they are no longer active.
Old, active versions of _processes_. An application is typically made up of many interacting processes. The application is supposed to be robust to most processes terminating -- in fact, it's often the ways errors and exceptions are handled.
"Live-upgrades to IRCCloud.com with Erlang/OTP" would be a better title :)