{"id":18390639,"url":"https://github.com/aspnetde/nodejs-webserver-guide","last_synced_at":"2025-07-12T09:33:07.858Z","repository":{"id":24729268,"uuid":"28141485","full_name":"aspnetde/nodejs-webserver-guide","owner":"aspnetde","description":"Node.js Webserver Guide - Install and run Node.js and MongoDB on Ubuntu","archived":false,"fork":false,"pushed_at":"2015-09-03T19:28:50.000Z","size":150,"stargazers_count":100,"open_issues_count":1,"forks_count":16,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-05T03:41:44.399Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aspnetde.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-17T14:51:32.000Z","updated_at":"2025-02-06T00:40:45.000Z","dependencies_parsed_at":"2022-09-08T05:41:07.289Z","dependency_job_id":null,"html_url":"https://github.com/aspnetde/nodejs-webserver-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aspnetde/nodejs-webserver-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspnetde%2Fnodejs-webserver-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspnetde%2Fnodejs-webserver-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspnetde%2Fnodejs-webserver-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspnetde%2Fnodejs-webserver-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aspnetde","download_url":"https://codeload.github.com/aspnetde/nodejs-webserver-guide/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspnetde%2Fnodejs-webserver-guide/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264972147,"owners_count":23691375,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T01:48:40.719Z","updated_at":"2025-07-12T09:33:07.819Z","avatar_url":"https://github.com/aspnetde.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Node.js Web Server Guide\n\n## Purpose\n\nThe main purpose of this guide is to summarize all the steps one has to take to get Node.js and MongoDB up and running on a Ubuntu web server. It is not 100% complete but it covers hopefully the most things you need to know to run different Node.js applications behind nginx, using MongoDB as a database.\n\nIf you find anything you can't agree with, please let me know. Send me an email or just a pull request and I will see if I am able to fix this ;-).\n\nThis guide contains some details regarding security that won't necessarily matter if you only want to run a single website on your server. In that case take a look at [\"Setting up Ubuntu Server for running a single Website with Node.js and MongoDB\"](https://github.com/aspnetde/ubuntu-nodejs-mongodb-guide).\n\n## Initial server installation\n\n### Make Tools\n\nThe make tools are essential to build some npm packages and other stuff. So it’s generally a good idea to install them early.\n\n\tsudo apt-get install gcc make build-essential\n\n(If the installation of build-essential fails, see Misc/Missing packages section).\n\n### nginx\n\n\tsudo apt-get install nginx\n\t\nOnce the setup of nginx is complete, you should be able to call http://{server_ip} and see the default page with the “Welcome to nginx!” headline.\n\nAlso make sure the server starts automatically after booting the system (Should be enabled by default):\n\n\tsudo update-rc.d nginx defaults\n\t\n### Node.js\n\n\twget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.14.0/install.sh | bash\n\n\t# Refresh Path\n\tsource ~/.profile\n\n\t# Use latest Node.JS version\n\tnvm install v0.11.13\n\t\n\t# Make it default\n\tnvm use default v0.11.13\n\n### Bower\n\n\tsudo npm install bower -g\n\n### PM2\n\nPM2 manages the different node applications running on this server.\n\n\tsudo npm install pm2 -g\n\n\n### Glances\n\nGlances can be used to monitor the overall state of the server.\n\n\tsudo apt-get install python-pip build-essential python-dev\n\tsudo pip install Glances\n\tsudo apt-get install lm-sensors\n\tsudo pip install PySensors\n\n### Git\n\n\tsudo apt-get install git\n\n### Zip\n\n\tsudo apt-get install zip\n\n### MongoDB\n\nFor a detailed explanation see [http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/](http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/).\n\n#### Install the database service\n\n\tsudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10\n\techo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list\n\tsudo apt-get update\n\tsudo apt-get install -y mongodb-org\n\n#### Pin the current version\n\n\techo \"mongodb-org hold\" | sudo dpkg --set-selections\n\techo \"mongodb-org-server hold\" | sudo dpkg --set-selections\n\techo \"mongodb-org-shell hold\" | sudo dpkg --set-selections\n\techo \"mongodb-org-mongos hold\" | sudo dpkg --set-selections\n\techo \"mongodb-org-tools hold\" | sudo dpkg --set-selections\n\n#### Set up security\n\n\n##### Set up mongod.conf\n\n\n\tsudo vi /etc/mongod.conf \n\nSet:\n\n\tauth = true\n\tbind_ip = 127.0.0.1\n\n##### Add admin user\n\nOpen the Mongo Console with `mongo`.\n\n\tuse admin\n\tdb.createUser({ user: \"\u003cusername\u003e\",\n          pwd: \"\u003cpassword\u003e\",\n          roles: [ \"userAdminAnyDatabase\",\n                   \"dbAdminAnyDatabase\",\n                   \"readWriteAnyDatabase\"\n\n\t]})\n\n##### Restart the service\n\n\tsudo service mongod restart\n\n## Installation of a new website\n\n### Create a MongoDB database\n\n\tmongo -u admin -p {adminpassword} --authenticationDatabase admin\n\nAdd a MongoDB user for the website\n\n\tuse website-com\n\tdb.createUser(\n    {\n      user: \"website-com\",\n      pwd: \"{newpassword}\",\n      roles: [\n\t\t{ role: \"readWrite\", db: \"website-com\" }\n\t]})\n\n### Add the website’s directories\n\nWebsites are organized as follows:\n\n\nThe main identifier is the domain name of a website, while dots are replaced by dashes. \n\nDirectory | Path\n------------ | -------------\nSingle website’s root | /var/www/xyz-com\nSingle website’s Git repository\t | /var/www/xyz-com/repo\nSingle website’s web root | /var/www/xyz-com/www\n\nExamples: \n\n- blog.xyz.de =\u003e blog-xyz-de\n- website.com =\u003e website-com\n\t\n### Add a dedicated website user\n\nUse the domain name for the user’s name:\n\n\tsudo adduser website-com\n\n### Make the user the owner of the website’s directories\n\nIn `/var/www` execute:\n\n\tsudo chown website-com website-com –R\n\n### Create a Git repository\n\nIn `/var/www/website-com/repo` run\n\n\tgit init --bare\n\n### Add the Git deployment hook\n\nThis hook is used to deploy changes made to the master repository. It can be customized for each website depending on the specific needs.\n\nGo to `/var/www/website-com/repo/hooks` and create a new file called “post-receive”:\n\n\tvi post-receive\n\t\nAdd the following commands to it:\n\n\t#!/bin/bash\n\n\t# Make this executable: chmod +x post-receive\n\n\tPREPARATION_DIR=\"/var/www/website-com/repo/$(uuidgen)\"\n\tWEBSITE_ROOT=\"/var/www/website-com/www\"\n\tPM2_APP_NAME=\"website-com\"\n\n\techo \"Deployment started\"\n\n\tread oldrev newrev branch\n\n\tif [[ $branch =~ .*/master$ ]];\n\tthen\n    \techo \"Master received. Deploying to production...\"\n\n    \t# Creates a temporary working directory\n\t    mkdir $PREPARATION_DIR\n\n    \t# Checks out the master from the repository\n\t    GIT_WORK_TREE=\"$PREPARATION_DIR\" git checkout -f\n\n    \t# Installing all npm and bower modules/packages\n\t    cd $PREPARATION_DIR\n\t    npm install --allow-root\n\t    bower install --allow-root\n\n\t    # Removes all files in the Website's root\n    \tcd $WEBSITE_ROOT\n\t\trm -rf *\n\n\t\t# Copies all files over\n\t\tcd $PREPARATION_DIR\n\t\tcp -r . $WEBSITE_ROOT\n\n\t\t# Restart the Website via PM2\n\t\tpm2 restart $PM2_APP_NAME\n\n\t\t# Removes the preparation directory\n\t\trm -R $PREPARATION_DIR\n\telse\n    \techo \"$branch successfully received. Nothing to do: only the master branch may be deployed on this server.\"\n\tfi\n\n\techo \"Deployment finished\"\n\nRemember the value of **PM2_APP_NAME** and use it as an identifier for your pm2 application later.\n\nAfter saving, make the script executable:\n\n\tchmod +x post-receive\n\n### Push your application to your repository\n\nBy cloning your deployment repository on your local development machine and pushing the first version to the master branch, you should receive a fresh version at `/var/www/website-com/www` (Check with `ls –l`).\n\n\tgit clone ssh://{username}@{ipaddress}/var/www/website-com/repo website-com\n\nMake sure the user you’re connecting with has the necessary rights to run the Git repository. It’s recommended to connect with the user you have just created before to run the website, because he/she has the necessary access rights.\n\n### Set up PM2\n\n#### Give the user temporary root privilige\n\nCall `visudo` and add the following line:\n\n\t{username} ALL=(ALL:ALL) ALL\n\n#### Run the startup script\n\nTo start pm2 with the system:\n\n\tpm2 startup ubuntu\n\t\nPM2 will tell you, you have to run this command as root, and print the full command to execute, for example:\n\n\tsudo env PATH=$PATH:/home/{username}/.nvm/v0.10.32/bin pm2 startup ubuntu -u {username}\n\n#### Remove root privilege\n\nCall `visudo` again and remove the line you did just add before.\n\n#### Start your application \n\n\tcd /var/www/website-com/www/\n\tpm2 start app.js --name \"website-com\"\n\n**Note: The PM2 instance is now running in the context if your website's user. This is especially useful to limit file access, but you can't see any other PM2 process or applications as you could see if running all websites under one single user.**\n\nIf everything works PM2 reponds with `Process {nameofstarting.js}` launched. Wait a few seconds and use\n\n\tpm2 list\n\nfor a fresh status update. For more information see\n\n\tpm2 help\n\n### Configure the website in nginx\n\nWe’re using a single configuration, which can be found at:\n\n\tsudo vi /etc/nginx/sites-available/default\n\nnginx is running as a reverse proxy to handle all the public stuff on port 80 for us. It then passes all the traffic we want to to our node application.\n\n\tserver {\n    \tlisten 80;\n\n\t    server_name your-domain.com;\n\n    \tlocation / {\n        \tproxy_pass http://localhost:{YOUR_PORT};\n\t        proxy_http_version 1.1;\n    \t    proxy_set_header Upgrade $http_upgrade;\n        \tproxy_set_header Connection 'upgrade';\n\t        proxy_set_header Host $host;\n    \t    proxy_cache_bypass $http_upgrade;\n\t    }\n\t}\n\nAfter saving the configuration, use\n\n\tsudo service nginx reload\n\nto tell the server it should use it.\n\n## Backup\n\nAs I am currently using a Hetzner server, I am also able to use 100 GB backup space which they offer free of charge. But anyway: If you're not hosting your server at Hetzner this may also apply to your actual hosting environment.\n\n### Directory structure\n\nDirectory | Path\n------------ | -------------\nBackup Root | /var/backup\nWebsite Backups | /var/backup/www\nMongoDB Backups | /var/backup/mongo\nnginx Backups | /var/backup/nginx\n\n### MongoDB\n\n#### Backup user\n\nThere needs to be a user with a backup role to create backups of all databases:\n\n\tuse admin\n\tdb.createUser(\n    \t{\n\t      user: \"backup”,\n    \t  pwd: \"{newpassword}\",\n\t      roles: [{ role: \"backup\", db: \"admin\" }]\n    \t}\n\t)\n\n#### Backup script\n\nSave the following shell script as `/var/backup/create-backup-for-mongo` and make it executable:\n\n\t#!/bin/bash\n\n\techo \"Mongo Backup started\"\n\n\tADMIN_USERNAME=\"backup\"\n\tADMIN_PASSWORD=\"{password}\"\n\n\tBACKUP_TARGET_ROOT=\"/var/backup/mongo\"\n\tCURRENT_BACKUP_TARGET=\"$BACKUP_TARGET_ROOT/$(uuidgen)\"\n\n\t# Remove all but the latest 30 backups\n\tcd $BACKUP_TARGET_ROOT\n\trm -rf `ls -t | tail -n +30`\n\n\t# Back up all the databases to a new directory\n\tmongodump -u $ADMIN_USERNAME -p $ADMIN_PASSWORD -o $CURRENT_BACKUP_TARGET --authenticationDatabase admin\n\n\tzip -r \"$(uuidgen).zip\" $CURRENT_BACKUP_TARGET\n\trm -rf  $CURRENT_BACKUP_TARGET\n\n\techo \"Mongo Backup finished\"\n\n#### Websites\n\nCreate the script `/var/backup/create-backup-for-www` and make it executable:\n\n\t#!/bin/bash\n\n\techo \"WWW Backup started\"\n\n\tBACKUP_SOURCE=\"/var/www\"\n\n\tBACKUP_TARGET_ROOT=\"/var/backup/www\"\n\tCURRENT_BACKUP_TARGET=\"$BACKUP_TARGET_ROOT/$(uuidgen)\"\n\tcd $BACKUP_TARGET_ROOT\n\trm -rf `ls -t | tail -n +30`\n\n\t# Back up all the websites to a new directory\n\trsync -a -E -c --stats $BACKUP_SOURCE $CURRENT_BACKUP_TARGET\n\n\tzip -r \"$(uuidgen).zip\" $CURRENT_BACKUP_TARGET\n\trm -rf  $CURRENT_BACKUP_TARGET\n\n\techo \"WWW Backup finished\"\n\t\n#### nginx\n\nCreate the script `/var/backup/create-backup-for-nginx` and make it executable:\n\n\t#!/bin/bash\n\n\techo \"nginx Backup started\"\n\n\tBACKUP_SOURCE=\"/etc/nginx\"\n\n\tBACKUP_TARGET_ROOT=\"/var/backup/nginx\"\n\tCURRENT_BACKUP_TARGET=\"$BACKUP_TARGET_ROOT/$(uuidgen)\"\n\n\t# Remove all but the latest 30 backups\n\tcd $BACKUP_TARGET_ROOT\n\trm -rf `ls -t | tail -n +30`\n\n\trsync -a -E -c --stats $BACKUP_SOURCE $CURRENT_BACKUP_TARGET\n\n\tzip -r \"$(uuidgen).zip\" $CURRENT_BACKUP_TARGET\n\trm -rf  $CURRENT_BACKUP_TARGET\n\n\techo \"nginx Backup finished\"\n\n### Mount the backup server \n\n\n#### Install cifs-utils\n\n\tsudo apt-get install cifs-utils\n\n##### Mounting\n\nThis will mount the backup server as a local drive and it will reconnect on each reboot (it’s a single line added to fstab).\n\n\tsudo vi /etc/fstab \n\n \n\t//u100445.your-backup.de/backup /mnt/backup-server       cifs    iocharset=utf8,rw,credentials=/var/backup/backup-credentials.txt,uid={localusername},gid={localusergroupid},file_mode=0660,dir_mode=0770 0       0\n\n(If you are not aware of the group id, just type `id` and it will be displayed for the current user (in case you want to mount the drive in his/her context)).\n\n#### Credentials\n\n\tvi /var/backup/backup-credentials.txt\n\t\nSet:\n\n\tusername={username}\n\tpassword={password}\n\n#### Transfer script\n\nCreate a script that combines all backup actions and that finally transfers everything from the current backup folder to the backup server. Save that script as `/var/backup/create-and-transfer-backups` and make it executable.\n\n\t#!/bin/bash\n\n\techo \"Global Backup started\"\n\n\t#Important: use absolute paths to be independent of the user context\n\t/var/backup/create-backup-for-mongo\n\t/var/backup/create-backup-for-www\n\t/var/backup/create-backup-for-nginx\n\n\trsync -avzE --delete --stats /var/backup /mnt/backup-server\n\n\techo \"Global Backup finished\"\n\n#### Schedule backup\n\n\tsudo vi /etc/crontab \n\nSet:\n\n\n\t# m  h  dom mon dow user command\n\t10 14 *   *   *   root bash /var/backup/create-and-transfer-backups\n\n(Runs the backup every day at 2:10 pm.)\n\n\n## Miscellaneous\n\n\n### Commands\n\nAction | Command\n------------ | -------------\nChange User name |\tpasswd\nGrant root priviliges | visudo, add: {username} ALL=(ALL:ALL) ALL\nSystem UpdateS: Fetching the list of available updates\t| sudo apt-get update\nSystem UpdateS: Strictly upgrading the current packages | sudo apt-get upgrade\nSystem UpdateS: Installing updates (new ones) | sudo apt-get dist-upgrade\nReboot | sudo reboot\nRemove a directory and its sub-directories recursively | rm –R {directoryname} \nRemove everything, files and directories | sudo rm -rf *\nShow current network settings | ifconfig\nMake rudi the owner of a directory | chown -R rudi {directoryname}\nStart a system service | sudo service {servicename} start\nRestart a system service | sudo service {servicename} restart\nStop a system service | sudo service {servicename} stop\nReload a system service | sudo service {servicename} reload\nSee who’s the owner of a process | ps aux | grep {processname}\nchmod Details |\t[http://serverfault.com/a/357109](http://serverfault.com/a/357109) \u0026 [http://linuxcommand.org/lts0070.php](http://linuxcommand.org/lts0070.php)  \nGrant a Role in MongoDB afterwards |\tdb.grantRolesToUser(\"username\", [{ role: \"readWrite\", db: \"dbname\" }])\nMake a shell script executable |chmod +x {scriptname}\n\n\n### Add a SSH shortcut (on the development machine)\n\nCreate (or edit) a file named config in `~/.ssh/` (User's root directory)\n\n\tHost username\n    \tHostName xxx.xxx.xxx.xxx\n    \tUser username\n\nNow just type `ssh username` in terminal.\n\n### Packages via apt-get not available?\n\nIf some packages are not available via apt-get, take a look at the sources configuration:\n\n\tsudo vi /etc/apt/sources.list\n\nIf the extras and the archive repositories are commented out, just remove the comments.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faspnetde%2Fnodejs-webserver-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faspnetde%2Fnodejs-webserver-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faspnetde%2Fnodejs-webserver-guide/lists"}