First of all, do NOT run services as the root user… but you probably already knew that!
Traditionally this problem is solved by running a reverse proxy (for example NGINX or Apache) that will forward the incoming traffic to the local Node.js service. This has the benefit that the user running the Node.js service does not need any special privileges and only need to set up the service to bind to localhost on higher port numbers. NGINX / Apache does of course start as root but makes sure to drop it’s privileges to another user and group by issuing setuid() and setgid().
So, the easiest way to get your Node.js service up and running on port 80 and 443 (or any other Privileged port) is to set the capabilities for the node process, so that it can bind to those ports. That way you can still run them as you normal user (or as a service user, which is preferred).
user@server:~/$ whereis node node: /usr/local/bin/node user@server:~/$ sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/node
The drawback with this approach is that any user can listen on privileged ports through the node executable. However it’s still easier than setting up a reverse proxy.
An alternative way is to manually implement process.setuid() and process.setgid() in Node, but this will than require that you start the node process as root which is more error prone.