When we started to develop NodeJS applications, our main concern was how to deploy, distribute, manage and maintain the applications in a production environment.
In a local environment, you have full control over all the aspects of the OS, including user permissions, applications installed, etc. However, when working in an enterprise environment, you have to deal with several constraints.
We didn’t have a proper way to deploy the applications. At first, we just copied the files, installed all the required NPM modules (and any other required library) and just run the program. Using different NodeJS versions for different applications in the same server was almost impossible. We couldn’t use any tool to handle several NodeJS versions installed at the same time (like NVM). The application files (other than the JS code itself) were scattered all over the host. The configuration and log files were stored inside the application folder, instead of being in a more common location.
Because of these problems, the whole thing was a mess, we needed to organize the whole deployment process, focusing on the following aspects:
- Standardizing folder structure and file location.
- Running the application as a service.
- Simplifying maintenance tasks, log rotation, version upgrading.
- Complying with Linux applications standards.
First of all, we decided to use Linux native tools to manage the application deployment and proper running.
- To handle the logs behaviour, we use Logrotate.
- To deploy and upgrade, we use Debian Software Package.
- To run the application as a service, we use Upstart.
We defined a proper file location:
- Application Files:
- Upstart settings:
- Logrotate settings:
- NodeJS installations:
- NPM Cache:
With Logrotate, we define the log rotation and what to do with the old log files.
Logrotate config file example:
Debian Software Package
We used Debian Software Package to accomplish the following:
- Enforcing the file location.
- Checking and Installing NodeJS versions.
- Creating an application exclusive user.
- Installing NPM dependencies having full control over the files created.
This was done through two of the files store inside a DEB file, preinst and postinst.
With this file we run a script to check if the NodeJS version needed is already installed. If that’s not the case, we access the archives of nodejs.org, download the installation package and extract it in a predefined path. We also check/create a user (with the application name as username).
In this config file we configure the NPM cache folder location, to centralize all the modules in case we install more than one NodeJS app in the same server. After that, we run NPM to install every dependency. Once the NPM process is done, we configure the ownership of all the files involved in the running (application, configuration, log files and home folder). To conclude we stop the service and restart with the new changes.
Example of a shell script to generate the .deb package:
With Upstart, we handle the way the application is being executed. Setting it as a Linux service, and making it executable when the server is rebooted. In the config file we also define: The NodeJS version used to execute. The user that is running the application (this will always be the already created user). The log file that will store the information written by the application in the standard out and standard error.
Upstart script example:
Hope this is helpful! What other techniques or tools do you use or know?