├── .gitignore ├── skeleton ├── etc │ ├── my-test-app.d │ │ └── default.json │ └── init │ │ └── my-test-app.conf ├── hooks │ ├── after-install.sh │ └── before-remove.sh ├── opt │ └── my-test-app │ │ ├── package.json │ │ ├── src │ │ └── my-test-app.js │ │ └── bin │ │ └── my-test-app ├── build-deb.sh ├── build-rpm.sh └── README.md ├── package.json ├── scripts └── copy ├── LICENSE ├── bin └── luukere └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | .DS_Store 4 | dist/*.deb -------------------------------------------------------------------------------- /skeleton/etc/my-test-app.d/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 1337, 3 | "host": "0.0.0.0" 4 | } -------------------------------------------------------------------------------- /skeleton/hooks/after-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME="my-test-app" 4 | 5 | initctl start "${NAME}" -------------------------------------------------------------------------------- /skeleton/hooks/before-remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME="my-test-app" 4 | 5 | initctl stop ${NAME} 6 | 7 | rm -rf /var/run/${NAME}.pid 8 | rm -rf /var/log/${NAME}.log -------------------------------------------------------------------------------- /skeleton/opt/my-test-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-test-app", 3 | "private": true, 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "commander": "^2.7.1", 7 | "config": "^1.12.0", 8 | "npmlog": "^1.2.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /skeleton/etc/init/my-test-app.conf: -------------------------------------------------------------------------------- 1 | description "My Test App" 2 | 3 | start on runlevel [2345] 4 | stop on runlevel [!2345] 5 | 6 | respawn 7 | 8 | script 9 | NAME=my-test-app 10 | exec /opt/${NAME}/bin/${NAME} \ 11 | --node-env="production" \ 12 | --config-dir="/etc/${NAME}.d" \ 13 | --pid-file="/var/run/${NAME}.pid" \ 14 | >>/var/log/${NAME}.log 2>&1 15 | end script -------------------------------------------------------------------------------- /skeleton/opt/my-test-app/src/my-test-app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var log = require('npmlog'); 4 | var config = require('config'); 5 | var net = require('net'); 6 | 7 | var server = net.createServer(function(socket) { 8 | log.info('TCP', 'Connection from %s', socket.remoteAddress); 9 | socket.write('Echo server\r\n'); 10 | socket.pipe(socket); 11 | }); 12 | 13 | server.listen(config.port, config.host); -------------------------------------------------------------------------------- /skeleton/build-deb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME="my-test-app" 4 | VERSION=`cd opt/${NAME} && node -e 'console.log(require("./package").version)'` 5 | 6 | DIR=`pwd` 7 | cd opt/$NAME 8 | npm install 9 | cd $DIR 10 | 11 | mkdir -p dist 12 | rm -rf dist/${NAME}-${VERSION}_*.deb 13 | fpm -s dir -t deb -n ${NAME} -v $VERSION -C . \ 14 | -p dist/${NAME}-VERSION_ARCH.deb \ 15 | -d "nodejs >= 0.10.0" \ 16 | --description "My Test App" \ 17 | --before-remove "hooks/before-remove.sh" \ 18 | --after-install "hooks/after-install.sh" \ 19 | etc opt/my-test-app \ 20 | && echo "Package successfully built" -------------------------------------------------------------------------------- /skeleton/build-rpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME="my-test-app" 4 | VERSION=`cd opt/${NAME} && node -e 'console.log(require("./package").version)'` 5 | 6 | DIR=`pwd` 7 | cd opt/$NAME 8 | npm install 9 | cd $DIR 10 | 11 | mkdir -p dist 12 | rm -rf dist/${NAME}-${VERSION}_*.rpm 13 | fpm -s dir -t rpm -n ${NAME} -v $VERSION -C . \ 14 | -p dist/${NAME}-VERSION_ARCH.rpm \ 15 | -d "nodejs >= 0.10.0" \ 16 | --description "My Test App" \ 17 | --before-remove "hooks/before-remove.sh" \ 18 | --after-install "hooks/after-install.sh" \ 19 | --rpm-os linux \ 20 | etc opt/my-test-app \ 21 | && echo "Package successfully built" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "luukere", 3 | "version": "1.0.5", 4 | "description": "Generate Node.js server application skeletons that can be compiled into Debian .deb packages", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/andris9/luukere.git" 8 | }, 9 | "bin": { 10 | "luukere": "./bin/luukere" 11 | }, 12 | "keywords": [ 13 | "deb", 14 | "ubuntu", 15 | "debian", 16 | "server", 17 | "application" 18 | ], 19 | "author": "Andris Reinman", 20 | "license": "MIT", 21 | "dependencies": { 22 | "commander": "^2.7.1", 23 | "mkdirp": "^0.5.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/copy: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | APP=$1 4 | DESCRIPTION=$2 5 | SOURCE=$3 6 | DESTINATION=$4 7 | 8 | cp -r $SOURCE/ $DESTINATION 9 | 10 | cd $DESTINATION 11 | 12 | # find . -type f | xargs sed -i 's/my-test-app/${APP}/g' 13 | 14 | find ./ -type f -exec sed -i -e "s/my-test-app/${APP}/g;s/My Test App/${DESCRIPTION}/g" {} \; 15 | find . -name "*-e" -type f -print | xargs /bin/rm -f 16 | 17 | mv ./etc/init/my-test-app.conf "./etc/init/${APP}.conf" 18 | mv ./opt/my-test-app/bin/my-test-app "./opt/my-test-app/bin/${APP}" 19 | mv ./opt/my-test-app/src/my-test-app.js "./opt/my-test-app/src/${APP}.js" 20 | mv ./etc/my-test-app.d "./etc/${APP}.d" 21 | mv ./opt/my-test-app "./opt/${APP}" 22 | 23 | echo "Skeleton built to $DESTINATION" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Andris Reinman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 16 | SOFTWARE. -------------------------------------------------------------------------------- /bin/luukere: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var fs = require('fs'); 6 | var program = require('commander'); 7 | var packageData = require('../package.json'); 8 | var path = require('path'); 9 | var mkdirp = require('mkdirp'); 10 | var spawn = require('child_process').spawn; 11 | 12 | program. 13 | version(packageData.version). 14 | usage('[options]'). 15 | option('-a --app ', 'Application name'). 16 | option('-d --description ', 'Application description (optional)', 'Node.js Server Application'). 17 | parse(process.argv); 18 | 19 | if (!program.app) { 20 | program.outputHelp(); 21 | return process.exit(1); 22 | } 23 | 24 | var source = path.join(__dirname, '..', 'skeleton'); 25 | var destination = path.join(process.cwd(), program.app); 26 | 27 | mkdirp(destination, function(err) { 28 | if (err) { 29 | console.error(err); 30 | return process.exit(1); 31 | } 32 | 33 | var copy = spawn(path.join(__dirname, '../scripts/copy'), [program.app, program.description, source, destination]); 34 | 35 | copy.stdout.pipe(process.stdout); 36 | copy.stderr.pipe(process.stderr); 37 | 38 | copy.on('close', function(code) { 39 | process.exit(code); 40 | }); 41 | }); -------------------------------------------------------------------------------- /skeleton/opt/my-test-app/bin/my-test-app: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var fs = require('fs'); 6 | var program = require('commander'); 7 | var packageData = require('../package.json'); 8 | var log = require('npmlog'); 9 | 10 | program. 11 | version(packageData.version). 12 | usage('[options]'). 13 | option('--config-dir ', 'Configuration directory'). 14 | option('--log-level ', 'Log level: info, warn, error', /^(silly|verbose|info|http|warn|error)$/i). 15 | option('--node-env ', 'Node environment, eg. "production"'). 16 | option('--pid-file ', 'PID file location'). 17 | parse(process.argv); 18 | 19 | if (program.logLevel) { 20 | log.level = program.logLevel; 21 | log.info('App', 'Setting log level to %s', program.logLevel); 22 | } 23 | 24 | if (program.configDir) { 25 | process.env.NODE_CONFIG_DIR = program.configDir; 26 | log.info('App', 'Using config files from %s', program.configDir); 27 | } 28 | 29 | if (program.nodeEnv) { 30 | process.env.NODE_ENV = program.nodeEnv; 31 | log.info('App', 'Running as %s environment', program.nodeEnv); 32 | } 33 | 34 | if (program.pidFile) { 35 | fs.writeFileSync(program.pidFile, process.pid); 36 | log.info('App', 'Using pidfile to %s', program.configDir); 37 | } 38 | 39 | require('../src/my-test-app.js'); -------------------------------------------------------------------------------- /skeleton/README.md: -------------------------------------------------------------------------------- 1 | # My Test App 2 | 3 | This is a skeleton of a Node.js server application (the example implements the echo server from Node.js homepage) that can be converted into a deb or a rpm package with [fpm](https://github.com/jordansissel/fpm/wiki). The skeleton was generated with the [luukere](https://www.npmjs.com/package/luukere) command. 4 | 5 | If your application does not include compiled dependencies then you can build the package on any platform, eg. on OSX. 6 | 7 | ## 8 | 9 | ## Directory structure 10 | 11 | Application sources can be found from [opt/app-name](opt/app-name). Upstart script executes [bin/app-name](opt/app-name/bin/app-name) executable which in turn loads the main application file [src/app-name.js](opt/app-name/src/app-name.js) – edit this file as you like, this is the starting point for your application. The aplication is run in respawn mode, so it is automatically restarted if the app exits. 12 | 13 | Configuration folder can be found from [etc/app-name.d](etc/app-name.d), see [config module docs](https://github.com/lorenwest/node-config/wiki/Configuration-Files) for which files and in which order are loaded form this folder (yaml support is not included by default but you can use *.json* and *.js* files). 14 | 15 | ## Building the App 16 | 17 | #### Dependencies 18 | 19 | If you do not yet have [fpm](https://github.com/jordansissel/fpm) installed, install it like this: 20 | 21 | gem install fpm 22 | 23 | If you generate packages in OSX you might need the gnu-tar package which can be installed with Homebrew: 24 | 25 | brew install gnu-tar 26 | 27 | To build rpm packages in OSX you also need to install rpm support with Homebrew: 28 | 29 | brew install rpm 30 | 31 | #### Build 32 | 33 | Once you have the dependencies set up you're all good to go. Generate your application deb package with: 34 | 35 | ./build-deb.sh 36 | 37 | or rpm package with: 38 | 39 | ./build-rpm.sh 40 | 41 | These commands generate a deb or a rpm file to the */dist* folder. You can install the generated package on Ubuntu/Debian like this: 42 | 43 | dpkg -i app-name-1.0.0_amd64.deb 44 | 45 | and on CentOS/RHEL like this: 46 | 47 | rpm -ivh app-name-1.0.0_amd64.rpm 48 | 49 | > The package expects that Node.js is installed from a package (see instructions for Ubuntu [here](https://github.com/joyent/node/wiki/installing-node.js-via-package-manager#debian-and-ubuntu-based-linux-distributions)) and that the installed Node.js version is at least 0.10. 50 | 51 | #### Uninstall package 52 | 53 | If you want to remove the installed app from the server, you can do this in Debian/Ubuntu: 54 | 55 | apt-get remove app-name 56 | 57 | or this in CentOS: 58 | 59 | yum remove app-name 60 | 61 | Uninstalling removes all related files (excluding any files the app itself might have created outside its folder). 62 | 63 | ## License 64 | 65 | [luukere](https://www.npmjs.com/package/luukere) command used to generate this application skeleton is licensed under the MIT license. The generated skeleton is licensed as public domain, so you can make it your own with no hassle. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # luukere 2 | 3 | Generate Node.js server application skeletons that can be compiled into Debian/Ubuntu deb and CentOS rpm packages. 4 | 5 | The skeleton is an application with required components to run it as a server daemon. It already includes a respawning upstart script, configuration folder under /etc, logging to /var/log and so on. You can build your server app and compile it to a Debian/Ubuntu or CentOS package with the included build scripts and not worry about directory strucutres in the server. 6 | 7 | ### What is included in the skeleton? 8 | 9 | * Application code at */opt/app-name* 10 | * Respawning upstart script at */etc/init* (daemon is restarted if it is closed unexpectedly) 11 | * Configuration folder at */etc/app-name.d* 12 | * Log file at */var/log/app-name.log* 13 | * PID file at */var/run/app-name.pid* 14 | 15 | The example application uses [config](http://npmjs.org/package/config) module for configuration (auto-loads configuration from the config folder) and [npmlog](http://npmjs.org/package/npmlog) for logging but you do not have to use these. 16 | 17 | ### What is "luukere"? 18 | 19 | *Luukere* is *skeleton* in Estonian 20 | 21 | ## Install 22 | 23 | Install from npm 24 | 25 | npm install -g luukere 26 | 27 | ## Usage 28 | 29 | ### Generate Skeleton App 30 | 31 | luukere -a "app-name" -d "My Awesome Server App" 32 | 33 | Where 34 | 35 | * **-a** identifies the app name (this is used as a folder name, so don't use spaces etc.) 36 | * **-d** describes the created app 37 | 38 | ## Building the App 39 | 40 | #### Dependencies 41 | 42 | If you do not yet have [fpm](https://github.com/jordansissel/fpm) installed, install it like this: 43 | 44 | gem install fpm 45 | 46 | If you generate packages in OSX you might need the gnu-tar package which can be installed with Homebrew: 47 | 48 | brew install gnu-tar 49 | 50 | To build rpm packages in OSX you also need to install rpm support with Homebrew: 51 | 52 | brew install rpm 53 | 54 | #### Build 55 | 56 | Once you have the dependencies set up you're all good to go. Generate your application deb package with: 57 | 58 | cd app-name 59 | ./build-deb.sh 60 | 61 | or rpm package with: 62 | 63 | cd app-name 64 | ./build-rpm.sh 65 | 66 | Thes commands generate deb and rpm files to the */dist* folder. You can install the generated package on Ubuntu/Debian like this: 67 | 68 | dpkg -i app-name-1.0.0_amd64.deb 69 | 70 | and on CentOS/RHEL like this: 71 | 72 | rpm -ivh app-name-1.0.0_amd64.rpm 73 | 74 | > The package expects that Node.js is installed from a package (see instructions for Ubuntu [here](https://github.com/joyent/node/wiki/installing-node.js-via-package-manager#debian-and-ubuntu-based-linux-distributions)) and that the installed Node.js version is at least 0.10. 75 | 76 | #### Uninstall package 77 | 78 | If you want to remove the installed app from the server, you can do this in Debian/Ubuntu: 79 | 80 | apt-get remove app-name 81 | 82 | or this in CentOS: 83 | 84 | yum remove app-name 85 | 86 | Uninstalling removes all related files (excluding any files the app itself might have created outside its folder). 87 | 88 | ## License 89 | 90 | [luukere](https://www.npmjs.com/package/luukere) is licensed under the MIT license. The generated skeleton is licensed as public domain, so you can make it your own with no hassle. --------------------------------------------------------------------------------