├── .gitignore ├── index.js ├── package.json ├── readme.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var exec = require('child_process').exec 4 | var Reload = require('nginx-reload') 5 | 6 | module.exports = Vhosts 7 | 8 | function Vhosts(opts, onChange) { 9 | if (!(this instanceof Vhosts)) return new Vhosts(opts, onChange) 10 | if (typeof opts === 'function') { 11 | onChange = opts 12 | opts = {} 13 | } 14 | this.opts = opts || {} 15 | this.confDir = this.opts.confDir || '/etc/nginx/conf.d/' 16 | this.onChange = onChange || function noop(){} 17 | this.nginx = Reload(this.opts, function (running) { 18 | if (onChange) onChange(running) 19 | }) 20 | } 21 | 22 | Vhosts.prototype.config = function(opts) { 23 | return '' 24 | + 'upstream ' + opts.name + ' {\n' 25 | + ' server 127.0.0.1:' + opts.port + ';\n' 26 | + '}\n' 27 | + 'server {\n' 28 | + ' listen 80;\n' 29 | + ' server_name ' + opts.domain + ';\n' 30 | + ' location / {\n' 31 | + ' proxy_pass http://' + opts.name + ';\n' 32 | + ' proxy_set_header X-Forwarded-For $remote_addr;\n' 33 | + ' proxy_buffering off;\n' 34 | + ' }\n' 35 | + '}\n' 36 | } 37 | 38 | Vhosts.prototype.write = function(opts, cb) { 39 | var self = this 40 | var config = opts.config || this.config(opts) 41 | var confPath = path.join(this.confDir, opts.name + '.conf') 42 | fs.writeFile(confPath, config, function(err) { 43 | if (err) return cb(err) 44 | self.nginx.reload(cb) 45 | }) 46 | } 47 | 48 | Vhosts.prototype.end = function() { 49 | this.nginx.end() 50 | } 51 | 52 | Vhosts.prototype.remove = function(name, cb) { 53 | var self = this 54 | var confPath = path.join(this.confDir, name + '.conf') 55 | fs.unlink(confPath, function(err) { 56 | if (err) return cb(err) 57 | self.nginx.reload(cb) 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nginx-vhosts", 3 | "version": "0.0.8", 4 | "description": "Programmatically add or remove vhosts to a running Nginx instance", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "author": "max ogden", 10 | "license": "BSD", 11 | "dependencies": { 12 | "nginx-reload": "~0.0.7" 13 | }, 14 | "devDependencies": {}, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/maxogden/nginx-vhosts.git" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/maxogden/nginx-vhosts/issues" 21 | }, 22 | "homepage": "https://github.com/maxogden/nginx-vhosts" 23 | } 24 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # nginx-vhosts 2 | 3 | [![NPM](https://nodei.co/npm/nginx-vhosts.png)](https://nodei.co/npm/nginx-vhosts/) 4 | 5 | Programmatically add or remove vhosts to a running Nginx instance. 6 | 7 | To use this you should have your Nginx configuration file set up such that the `http` section has a `include` directive for all `.conf` files in a certain folder on your machine, e.g.: 8 | 9 | ``` 10 | http { 11 | ## 12 | # Virtual Host Configs 13 | ## 14 | 15 | include /etc/nginx/conf.d/*.conf; 16 | include /etc/nginx/sites-enabled/*; 17 | } 18 | ``` 19 | 20 | The machine configured with the configuration about would use either `/etc/nginx/conf.d/` or `/etc/nginx/sites-enabled/` as the `confDir` below. Note that the official [Ubuntu PPA](http://wiki.nginx.org/Install#Ubuntu_PPA) for Nginx has it configured this way by default. 21 | 22 | See also: 23 | 24 | - https://github.com/maxogden/install-nginx-on-ubuntu 25 | - https://github.com/maxogden/nginx-reload 26 | 27 | ### api 28 | 29 | #### `var vhosts = require('nginx-vhosts')(opts, onStopStart)` 30 | 31 | `onStopStart` is passed to and called from [nginx-reload](https://github.com/maxogden/nginx-reload) 32 | 33 | ```js 34 | var vhosts = require('nginx-vhosts')(opts, function running(isRunning) { 35 | // isRunning is a boolean, true if nginx is running, false if it is not 36 | // this function will get called whenever nginx stops or starts 37 | // note: .reload() does not trigger this function, as nginx does not 38 | // actually stop during a configuration reload 39 | } 40 | ``` 41 | 42 | `opts` defaults to: 43 | 44 | ```js 45 | { 46 | confDir: '/usr/local/etc/nginx/conf.d/', 47 | pidLocation: '/var/run/nginx.pid' 48 | } 49 | ``` 50 | 51 | #### `vhosts.write(opts, cb)` 52 | 53 | ```js 54 | vhosts.write({ 55 | name: 'test', 56 | port: '8080', 57 | domain: 'test.local' 58 | }, function(err, stdout, stderr) { 59 | // err, stdout, and stderr from the nginx configuration reload 60 | }) 61 | ``` 62 | 63 | This writes a new configuration file to the configuration directory and then tells Nginx to reload its configuration. In the above example it would configure Nginx to proxy requests from `test.local` to `localhost:8080` 64 | 65 | You can also supply your own config file: 66 | 67 | ```js 68 | vhosts.write({ 69 | name: 'test', 70 | config: 'upstream foo { server 127.0.0.1:8080 } ...' 71 | }, cb) 72 | ``` 73 | 74 | Note: it may take Nginx a few seconds to finish reloading the configuration after the callback is called. 75 | 76 | #### `vhosts.remove(name, cb)` 77 | 78 | ```js 79 | vhosts.remove('test', function(err, stdout, stderr) { 80 | 81 | }) 82 | ``` 83 | 84 | This removes a configuration file and tells Nginx to reload its configuration. 85 | 86 | Note: it may take Nginx a few seconds to finish reloading the configuration after the callback is called. 87 | 88 | ### run the tests 89 | 90 | There are integration tests available, provided you have the following things set up: 91 | 92 | - your nginx is configured to store a `pid` file in '/var/run/nginx.pid' 93 | - your nginx is configured to `include` confs for `http` from `/usr/local/etc/nginx/conf.d/` 94 | - you have `test.local` in your `/etc/hosts` as an entry for `localhost` 95 | 96 | ``` 97 | npm install 98 | sudo npm test 99 | ``` 100 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var Vhosts = require('./') 2 | var request = require('request') 3 | var test = require('tape') 4 | var http = require('http') 5 | 6 | var pizzaServer = http.createServer(function(req, res) { res.end('pizza') }).listen(8080) 7 | var shouldStop 8 | var opts = { 9 | confDir: '/usr/local/etc/nginx/conf.d/', 10 | pidLocation: '/var/run/nginx.pid' 11 | } 12 | 13 | test('.write() writes a new vhost', function(t) { 14 | var vhosts = Vhosts(opts, function running(isRunning) { 15 | if (isRunning) return writeConfig() 16 | if (!isRunning) return vhosts.nginx.start(function(err) { 17 | shouldStop = true 18 | if (err) throw err 19 | }) 20 | }) 21 | 22 | function writeConfig() { 23 | request('http://test.local', function(err, resp, body) { 24 | t.false(err, 'no error') 25 | t.true(body.toString().indexOf('pizza') === -1, 'no vhost') 26 | vhosts.write({ 27 | name: 'test', 28 | port: '8080', 29 | domain: 'test.local' 30 | }, function(err, stdout, stderr) { 31 | t.false(err, 'wrote vhost test') 32 | // give nginx 250ms to reload configuration 33 | setTimeout(function() { 34 | request('http://test.local', function(err, resp, body) { 35 | t.false(err, 'no error') 36 | t.true(body.toString().indexOf('pizza') > -1, 'vhost') 37 | t.end() 38 | vhosts.nginx.end() 39 | }) 40 | }, 250) 41 | }) 42 | }) 43 | } 44 | }) 45 | 46 | test('.remove() should remove a vhost', function(t) { 47 | var vhosts = Vhosts(opts, function running(isRunning) { 48 | if (isRunning) return removeConfig() 49 | }) 50 | 51 | function removeConfig() { 52 | request('http://test.local', function(err, resp, body) { 53 | t.false(err, 'no error') 54 | t.true(body.toString().indexOf('pizza') > -1, 'is vhosting') 55 | vhosts.remove('test', function(err) { 56 | t.false(err, 'removed vhost test') 57 | // give nginx 250ms to reload configuration 58 | setTimeout(function() { 59 | request('http://test.local', function(err, resp, body) { 60 | t.false(err, 'no error') 61 | t.true(body.toString().indexOf('pizza') === -1, 'not vhosting') 62 | vhosts.nginx.end() 63 | if (shouldStop) vhosts.nginx.stop() 64 | pizzaServer.close() 65 | t.end() 66 | }) 67 | }, 250) 68 | }) 69 | }) 70 | } 71 | }) 72 | --------------------------------------------------------------------------------