├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── example ├── hello.js ├── node-hello.service └── node-hello.socket ├── lib └── systemd.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | node_modules 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "curly": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "undef": true, 13 | "strict": false, 14 | "trailing": true, 15 | "smarttabs": true 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.11" 5 | before_script: 6 | - npm install -g grunt-cli 7 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | // Project configuration. 6 | grunt.initConfig({ 7 | jshint: { 8 | all: [ 9 | 'Gruntfile.js', 10 | 'lib/*.js', 11 | ], 12 | options: { 13 | jshintrc: '.jshintrc', 14 | } 15 | } 16 | }); 17 | 18 | // These plugins provide necessary tasks. 19 | grunt.loadNpmTasks('grunt-contrib-jshint'); 20 | grunt.loadNpmTasks('grunt-release'); 21 | 22 | // By default, lint and run all tests. 23 | grunt.registerTask('default', ['jshint']); 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011-2014 by Ruben Vermeersch 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 above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ⚠⚠⚠ No longer maintained! See [@derhuerst/systemd](https://github.com/derhuerst/node-systemd) for an alternative. ⚠⚠⚠ 2 | 3 | --- 4 | 5 | # systemd for Node.js 6 | 7 | Adds support for running node.js as a socket-activated service under systemd. 8 | 9 | More info on the how and why: https://rocketeer.be/articles/deploying-node-js-with-systemd/ 10 | 11 | For more background on socket activation: http://0pointer.de/blog/projects/socket-activation.html 12 | 13 | Obviously, this will only work on Linux distributions with systemd (such as Fedora). 14 | 15 | ## Usage 16 | 17 | You can install the latest version via npm: 18 | 19 | ```sh 20 | $ npm install systemd 21 | ``` 22 | 23 | Require the systemd module and pass 'systemd' as a parameter to listen(): 24 | 25 | ```javascript 26 | require('systemd'); 27 | 28 | var http = require('http'); 29 | http.createServer(function (req, res) { 30 | res.writeHead(200, {'Content-Type': 'text/plain'}); 31 | res.end('Hello World\n'); 32 | }).listen('systemd'); 33 | ``` 34 | 35 | Install a systemd socket file (e.g.: /etc/systemd/system/node-hello.socket): 36 | 37 | ```ini 38 | [Socket] 39 | ListenStream=1337 40 | 41 | [Install] 42 | WantedBy=sockets.target 43 | ``` 44 | 45 | Install a systemd service file (e.g.: /etc/systemd/system/node-hello.service): 46 | 47 | ```ini 48 | # Adjust according to man 5 systemd.exec 49 | 50 | [Service] 51 | ExecStart=/path/to/bin/node /path/to/hello.js 52 | StandardOutput=syslog 53 | User=nobody 54 | Group=nobody 55 | ``` 56 | 57 | Be sure to substitute the paths to node and your script! 58 | 59 | * ⚠ __Run node directly__ or make sure your startup helper scripts 60 | can hand over the sockets. `npm start` [probably won't work][issue-11]. 61 | 62 | [issue-11]: https://github.com/rubenv/node-systemd/issues/11 63 | 64 | Reload the systemd daemon so that it picks up the new unit files: 65 | 66 | ```sh 67 | $ systemctl --system daemon-reload 68 | ``` 69 | 70 | Enable and start the socket: 71 | 72 | ```sh 73 | $ systemctl enable node-hello.socket 74 | $ systemctl start node-hello.socket 75 | ``` 76 | 77 | Check the status of the socket: 78 | 79 | ```sh 80 | $ systemctl status node-hello.socket 81 | node-hello.socket 82 | Loaded: loaded (/etc/systemd/system/node-hello.socket) 83 | Active: active (listening) since Sat, 15 Oct 2011 20:27:47 +0200; 2s ago 84 | CGroup: name=systemd:/system/node-hello.socket 85 | ``` 86 | 87 | Great, it's running! 88 | 89 | Check the status of the service, not running yet: 90 | 91 | ```sh 92 | $ systemctl status node-hello.service 93 | node-hello.service 94 | Loaded: loaded (/etc/systemd/system/node-hello.service) 95 | Active: inactive (dead) 96 | CGroup: name=systemd:/system/node-hello.service 97 | ``` 98 | 99 | Do a request to your service: 100 | 101 | ```sh 102 | $ curl -i http://localhost:1337/ 103 | HTTP/1.1 200 OK 104 | Content-Type: text/plain 105 | Connection: keep-alive 106 | Transfer-Encoding: chunked 107 | 108 | Hello World 109 | ``` 110 | 111 | Check again, now it will be running: 112 | 113 | ```sh 114 | $ systemctl status node-hello.service 115 | node-hello.service 116 | Loaded: loaded (/etc/systemd/system/node-hello.service) 117 | Active: active (running) since Sat, 15 Oct 2011 20:32:10 +0200; 38s ago 118 | Main PID: 1159 (node) 119 | CGroup: name=systemd:/system/node-hello.service 120 | └ 1159 /path/to/bin/node /path/to/hello.js 121 | ``` 122 | 123 | ## Only listen to systemd when running under systemd 124 | 125 | You can make the systemd usage conditional by checking for the systemd environment variable: 126 | 127 | ```javascript 128 | var http = require('http'); 129 | 130 | require('systemd'); 131 | 132 | var port = process.env.LISTEN_PID > 0 ? 'systemd' : 1337; 133 | http.createServer(function (req, res) { 134 | res.writeHead(200, {'Content-Type': 'text/plain'}); 135 | res.end('Hello World\n'); 136 | }).listen(port); 137 | ``` 138 | 139 | This makes it possible to run the script stand-alone in development, yet use systemd when started through systemd. 140 | 141 | ## Contributing 142 | 143 | A jshint file is included to check code style. 144 | 145 | Before submitting a pull request, please check your code. For convenience, I've also added a grunt file. 146 | 147 | Install the dev dependencies: 148 | 149 | ```sh 150 | $ npm install --dev 151 | ``` 152 | 153 | Install the grunt cli if you haven't already done so: 154 | 155 | ```sh 156 | $ npm -g install grunt-cli 157 | ``` 158 | 159 | Run it: 160 | 161 | ```sh 162 | $ grunt 163 | ``` 164 | 165 | 166 | ## License 167 | 168 | (The MIT License) 169 | 170 | Copyright (C) 2011-2014 by Ruben Vermeersch 171 | 172 | Permission is hereby granted, free of charge, to any person obtaining a copy 173 | of this software and associated documentation files (the "Software"), to deal 174 | in the Software without restriction, including without limitation the rights 175 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 176 | copies of the Software, and to permit persons to whom the Software is 177 | furnished to do so, subject to the following conditions: 178 | 179 | The above copyright notice and this permission notice shall be included in 180 | all copies or substantial portions of the Software. 181 | 182 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 183 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 184 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 185 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 186 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 187 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 188 | THE SOFTWARE. 189 | 190 | -------------------------------------------------------------------------------- /example/hello.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | require('../lib/systemd'); 4 | 5 | var port = process.env.LISTEN_PID > 0 ? 'systemd' : 1337; 6 | http.createServer(function (req, res) { 7 | res.writeHead(200, {'Content-Type': 'text/plain'}); 8 | res.end('Hello World\n'); 9 | }).listen(port); 10 | -------------------------------------------------------------------------------- /example/node-hello.service: -------------------------------------------------------------------------------- 1 | # Adjust according to man 5 systemd.exec 2 | 3 | [Service] 4 | ExecStart=/path/to/bin/node /path/to/hello.js 5 | StandardOutput=syslog 6 | User=nobody 7 | Group=nobody 8 | -------------------------------------------------------------------------------- /example/node-hello.socket: -------------------------------------------------------------------------------- 1 | [Socket] 2 | ListenStream=1337 3 | 4 | [Install] 5 | WantedBy=sockets.target 6 | -------------------------------------------------------------------------------- /lib/systemd.js: -------------------------------------------------------------------------------- 1 | var net = require('net'); 2 | 3 | var Server = net.Server.prototype; 4 | var PipeWrap = process.binding('pipe_wrap'); 5 | var Pipe = PipeWrap.Pipe; 6 | 7 | var oldListen = Server.listen; 8 | Server.listen = function () { 9 | var self = this; 10 | var backlog; 11 | var callback; 12 | 13 | if (arguments[0] === 'systemd') { 14 | if (typeof arguments[1] === 'function') { 15 | callback = arguments[1]; 16 | } else if (typeof arguments[1] === 'number') { 17 | backlog = arguments[1]; 18 | callback = arguments[2]; 19 | } 20 | 21 | if (!process.env.LISTEN_FDS || parseInt(process.env.LISTEN_FDS, 10) !== 1) { 22 | throw(new Error('No or too many file descriptors received.')); 23 | } 24 | 25 | if (callback) { 26 | self.once('listening', callback); 27 | } 28 | 29 | if (PipeWrap.constants && typeof PipeWrap.constants.SOCKET !== 'undefined') { 30 | self._handle = new Pipe(PipeWrap.constants.SOCKET); 31 | } 32 | else { 33 | self._handle = new Pipe(); 34 | } 35 | self._handle.open(3); 36 | self._listen2(null, -1, -1, backlog); 37 | } else { 38 | oldListen.apply(self, arguments); 39 | } 40 | return self; 41 | }; 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "systemd", 3 | "version": "0.4.0", 4 | "main": "./lib/systemd.js", 5 | "description": "systemd socket activation support for Node.js", 6 | "keywords": [ 7 | "systemd" 8 | ], 9 | "url": "http://github.com/rubenv/node-systemd", 10 | "repository": "git://github.com/rubenv/node-systemd.git", 11 | "bugs": { 12 | "url": "https://github.com/rubenv/node-systemd/issues" 13 | }, 14 | "author": { 15 | "name": "Ruben Vermeersch", 16 | "email": "ruben@rocketeer.be", 17 | "url": "http://rocketeer.be/" 18 | }, 19 | "contributors": [], 20 | "licenses": [ 21 | { 22 | "type": "MIT", 23 | "url": "https://github.com/rubenv/node-systemd/blob/master/LICENSE" 24 | } 25 | ], 26 | "engines": { 27 | "node": ">=0.6.11 <0.11.0" 28 | }, 29 | "devDependencies": { 30 | "grunt": "~0.4.0", 31 | "grunt-contrib-jshint": "~0.8.0", 32 | "grunt-release": "~0.7.0" 33 | } 34 | } 35 | --------------------------------------------------------------------------------