Assuming that your application doesn't need write access to the application data (which it really shouldn't), we do the following:
We break the users into two classes -
<app> being the application name. They are both part of a group
node-<app>. Those aren't the actual names we use for the nosy ones out there.
We do the following:
1) For building the application, we always build on a separate machine, and then have a npm
dist script which places only the files needed to run the application into a
/dist directory and ships a tarred copy of this directory to our deploy server. The advantage of this is twofold - we know exactly what's going into the deploy and we can make sure that any dev-deps in
.git directories, and other data doesn't get added to production machines. It also means that when GitHub/Npm/etc. goes down, it doesn't break autoscaling etc. - our deploy server just delivers the prebuilt tarball.
2) We use our configuration management system to create a log directory in a standardized location which can be written to by
node-<app>-runtime with permissions 640. The path is provided to the application by a standard Environment Variable. Our log processing daemon automatically picks these up and ships them to a remote server.
3) Our deploy system places the application files in a specific place and sets them to be owned by
node-<app>-data with permissions 640. The path is provided to the application by a standard Environment Variable.
The only other bit of advice I have is to always make sure you are setting
NODE_ENV=production. Many node modules use this convention to turn off debugging symbols, or improve performance (
express comes to mind).