├── .gitignore ├── LICENSE ├── README.md ├── bin └── make-deb.sh ├── package.json └── templates ├── etc,init,node-PACKAGE.conf ├── etc,logrotate.d,PACKAGE ├── etc,monit,monitrc.d,PACKAGE ├── etc,nginx,sites-available,node-PACKAGE ├── etc,nginx,sites-available,node-PACKAGE-ssl └── home,node,.bowerrc /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Iļja Ketris 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Packaging node.js application into a .deb file 2 | 3 | Use this script to prepare your `node.js` web application for deployment on Debian-based system (only Ubuntu is tested). 4 | You don't need any Debian tools for that, just the shell, `tar` and `ar`. 5 | 6 | ### Installation 7 | 8 | npm install nodeb 9 | 10 | ### Invocation 11 | 12 | From your project's root: 13 | 14 | nodeb 15 | 16 | If all goes well, `.deb` file will be created. 17 | 18 | ### Options 19 | 20 | -n don't include node_modules/, bower_components/, components/ in the package 21 | -o don't generate nginx config for insecure (http) server 22 | -p (default 80) 23 | -s generate nginx config for secure (https) server 24 | -t copy templates to nodeb_templates/ for customization and exit 25 | -u (default "node") 26 | -v show generated files on stdout 27 | -w . If given, nginx config files will be created 28 | 29 | 30 | ### What's included 31 | 32 | The package will be installed in `/opt`. 33 | 34 | Files for `upstart`, `monit`, `logrotate`, and optionally `nginx` are created. `npm install` 35 | will be run on target system. 36 | 37 | If `-s` option is given, nginx configuration for https reverse proxy server is generated. Study the 38 | [templates](https://github.com/punund/nodeb/tree/master/templates), or customize them using `-t`. 39 | 40 | ### References 41 | 42 | http://blog.coolaj86.com/articles/how-to-create-a-debian-installer.html 43 | 44 | https://synack.me/blog/deploying-code-with-packages 45 | -------------------------------------------------------------------------------- /bin/make-deb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | fatecho() { echo -e '\E[31m' "\n$1\n" '\e[0m' ; } 4 | 5 | DEBUG= # 'v' for verbose t?ar 6 | 7 | export nbPort=80 8 | export nbUser=node 9 | export nbWeb= 10 | export nbSsl= 11 | export nbNoins= 12 | 13 | proxy_sock=/var/run/proxy.sock 14 | web_server_group=www-data 15 | 16 | dir=`dirname $(readlink -f $0)` 17 | 18 | while getopts "p:tu:w:sovn" opt; do 19 | case $opt in 20 | n) 21 | nbNoassets='--exclude=node_modules --exclude=bower_components --exclude=components' 22 | ;; 23 | u) 24 | nbUser=$OPTARG 25 | ;; 26 | o) 27 | nbNoins=1 28 | ;; 29 | p) 30 | nbPort=$OPTARG 31 | ;; 32 | s) 33 | nbSsl=1 34 | ;; 35 | t) 36 | [[ -e nodeb_templates ]] && { 37 | fatecho \"nodeb_templates\" exists, delete it first. Not executing. >&2 38 | } || { 39 | cp -a $dir/../templates nodeb_templates/ 40 | echo nodeb_templates/ created. 41 | } 42 | exit 0 43 | ;; 44 | v) 45 | verbose=1 46 | ;; 47 | w) 48 | nbWeb=$OPTARG 49 | ;; 50 | \?) 51 | cat <<-EOH >&2 52 | 53 | Valid options: 54 | 55 | -n don't include node_modules/, bower_components/, components/ in the package 56 | -o don't generate nginx config for insecure (http) server 57 | -p (default 80) 58 | -s generate nginx config for secure (https) server 59 | -t copy templates to nodeb_templates/ for customization and exit 60 | -u (default "node") 61 | -v show generated files on stdout 62 | -w . If given, nginx config files will be created 63 | 64 | EOH 65 | exit 1 66 | ;; 67 | esac 68 | done 69 | 70 | pdir=$PWD 71 | 72 | TDIR=`mktemp -d` 73 | RDIR=`mktemp -d` 74 | 75 | trap "rm -fr $TDIR $RDIR" SIGHUP SIGINT SIGTERM SIGQUIT EXIT 76 | 77 | node -e ' 78 | pkg = require("./package.json") 79 | 80 | console.log("set -a") 81 | console.log("Source=" + pkg.name) 82 | console.log("Package=" + pkg.name) 83 | console.log("Version=" + pkg.version) 84 | console.log("Priority=extra") 85 | console.log("Maintainer=\"" + pkg.author + "\"") 86 | console.log("Architecture=all") 87 | console.log("Depends=\"${nodejs:Depends}\"") 88 | console.log("Description=\"" + pkg.description + "\"") 89 | console.log("Exec=\"" + pkg.config.start + "\"") 90 | ' | { source /dev/stdin 91 | 92 | if [ -z "$Exec" -o -z "$Package" ] ; then 93 | echo 94 | echo '*** Error: package.json must contain at least "name" and "config":{"start":...} values. ***' >&2 95 | echo 96 | exit 1 97 | fi 98 | 99 | export Command=${Exec%% *} 100 | export CommandArgs=${Exec#* } 101 | 102 | # some vars to preserve in nginx files 103 | 104 | for keepit in uri is_args args host http_upgrade remote_addr proxy_add_x_forwarded_for ; do 105 | export $keepit=\$${keepit} 106 | done 107 | 108 | Name=node-$Package 109 | 110 | [[ -d nodeb_templates ]] && 111 | cd nodeb_templates || 112 | cd $dir/../templates 113 | 114 | [[ $nbWeb ]] || rm -fr $RDIR/etc/nginx/ 115 | [[ $nbSsl ]] || rm -fr $RDIR/etc/nginx/sites-available/node-$Package-ssl 116 | [[ $nbNoins ]] && rm -fr $RDIR/etc/nginx/sites-available/node-$Package 117 | 118 | for src in *; do 119 | dst=${src//,//} 120 | dst=${dst/PACKAGE/$Package} 121 | dstdir=`dirname $dst` 122 | 123 | mkdir -p $RDIR/$dstdir 124 | envsubst < $src > $RDIR/$dst 125 | [[ $verbose ]] && { 126 | echo -e '\E[37;44m' 127 | echo -e $dst '\E[0m' 128 | cat $RDIR/$dst 129 | } 130 | done 131 | 132 | 133 | cat > $TDIR/control < $TDIR/postinst </dev/null 2>&1 || { 150 | echo >&2 "I require npm but it's not installed. Aborting." 151 | exit 1 152 | } 153 | echo "Running npm...." 154 | cd /opt/$Package 155 | sudo -H -u $nbUser npm i 156 | } 157 | echo "Starting $Name" 158 | start $Name 159 | EOD 160 | 161 | [[ $nbSsl ]] && 162 | cat >> $TDIR/postinst <> $TDIR/postinst </dev/null 179 | 180 | [ -d $proxy_sock ] || { 181 | mkdir $proxy_sock 182 | chown www-data:www-data $proxy_sock 183 | } 184 | 185 | chmod 3770 $proxy_sock 186 | 187 | echo "Restarting nginx" 188 | service nginx restart 189 | EOD 190 | 191 | 192 | cat > $TDIR/preinst </dev/null 2>&1 || { 195 | echo 196 | echo /usr/bin/nodejs is required. Abort. 197 | echo 198 | exit 1 199 | } 200 | 201 | id $nbUser > /dev/null 2>&1 && { 202 | ln -f -s /usr/bin/nodejs /usr/bin/node 203 | } || { 204 | echo 205 | echo Please create user "$nbUser" first. Abort. 206 | echo 207 | exit 1 208 | } 209 | EOD 210 | 211 | cat > $TDIR/prerm < debian-binary 236 | 237 | debfile=$pdir/$Package.deb 238 | ar r$DEBUG $debfile debian-binary control.tar.gz data.tar.gz 2>/dev/null 239 | 240 | fatecho "$debfile created." 241 | } 242 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodeb", 3 | "version": "0.2.7", 4 | "description": "Converting node.js application into a Debian package", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git://github.com/punund/nodeb.git" 11 | }, 12 | "keywords": [ 13 | "node", 14 | "deb", 15 | "debian" 16 | ], 17 | "bin": { 18 | "nodeb": "./bin/make-deb.sh" 19 | }, 20 | "author": "Iļja Ketris", 21 | "license": "MIT", 22 | "readmeFilename": "README.md", 23 | "gitHead": "96f3fbc488524eebc4138e14dfa0b5bd86bf86e0" 24 | } 25 | -------------------------------------------------------------------------------- /templates/etc,init,node-PACKAGE.conf: -------------------------------------------------------------------------------- 1 | description "$Description" 2 | author "$Maintainer" 3 | 4 | env USER=$nbUser 5 | env PATH=/sbin:/bin:/usr/bin 6 | 7 | start on (local-filesystems and net-device-up IFACE=eth0) 8 | stop on [06] 9 | 10 | respawn 11 | script 12 | export HOME=/opt/$Package 13 | export NODE_ENV=production 14 | chdir /opt/$Package 15 | exec start-stop-daemon --chdir /opt/$Package \ 16 | --chuid $nbUser \ 17 | --start --make-pidfile \ 18 | --pidfile /var/run/$Package.pid \ 19 | --exec $Command -- $CommandArgs >> /var/log/$Name.log 2>&1 20 | end script 21 | 22 | pre-start script 23 | echo "[`date -u '+%F %T %Z'`] (sys) Starting" >> /var/log/$Name.log 24 | end script 25 | 26 | pre-stop script 27 | echo "[`date -u '+%Y-%m-%d %T %Z'`] (sys) Stopping" >> /var/log/$Name.log 28 | end script 29 | -------------------------------------------------------------------------------- /templates/etc,logrotate.d,PACKAGE: -------------------------------------------------------------------------------- 1 | /var/log/$Name.log { 2 | rotate 7 3 | daily 4 | missingok 5 | notifempty 6 | sharedscripts 7 | copytruncate 8 | compress 9 | } 10 | -------------------------------------------------------------------------------- /templates/etc,monit,monitrc.d,PACKAGE: -------------------------------------------------------------------------------- 1 | check process $Name with pidfile "/var/run/$Name.pid" 2 | start program = "/sbin/start $Name" 3 | stop program = "/sbin/stop $Name" 4 | if failed port $nbPort with timeout 15 seconds then restart 5 | 6 | -------------------------------------------------------------------------------- /templates/etc,nginx,sites-available,node-PACKAGE: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | 4 | server_name $nbWeb; 5 | 6 | location / { 7 | proxy_pass http://unix:/var/run/proxy.sock/$Name.80:$uri$is_args$args; 8 | proxy_http_version 1.1; 9 | proxy_set_header Upgrade $http_upgrade; 10 | proxy_set_header Connection 'upgrade'; 11 | proxy_set_header Host $host; 12 | proxy_cache_bypass $http_upgrade; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /templates/etc,nginx,sites-available,node-PACKAGE-ssl: -------------------------------------------------------------------------------- 1 | server { 2 | listen 443; 3 | 4 | server_name $nbWeb; 5 | 6 | ssl on; 7 | ssl_certificate /opt/ssl/$Package/production.pem; 8 | ssl_certificate_key /opt/ssl/$Package/production.key; 9 | 10 | # add_header Strict-Transport-Security max-age=500; 11 | 12 | location / { 13 | proxy_pass http://unix:/var/run/proxy.sock/$Name.443:$uri$is_args$args; 14 | proxy_cache_bypass $http_upgrade; 15 | proxy_redirect off; 16 | proxy_http_version 1.1; 17 | 18 | proxy_set_header Upgrade $http_upgrade; 19 | proxy_set_header Connection 'upgrade'; 20 | proxy_set_header Host $host; 21 | proxy_set_header X-Real-IP $remote_addr; 22 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 23 | proxy_set_header X-NginX-Proxy true; 24 | proxy_set_header X-SSL 1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /templates/home,node,.bowerrc: -------------------------------------------------------------------------------- 1 | { "storage" : 2 | { "packages" : ".bower-cache" 3 | , "registry" : ".bower-registry" 4 | } 5 | , "tmp" : ".bower-tmp" 6 | } 7 | --------------------------------------------------------------------------------