Code Monkey home page Code Monkey logo

nginx-conf's Introduction

nginx-conf

nginx-conf is a node module for making changes to an nginx configuration file programmatically.

NPM version

Installation

npm install nginx-conf

This library has no dependencies.

Breaking Changes

Version 2.0.0 changed the way that single directives are accessed. In short, everything is now array-indexed.

// Pre 2.0.0:
conf.nginx.foo.bar._value;

// 2.0.0+
conf.nginx.foo[0].bar[0]._value;

Usage

Pretend you have an nginx config file like this one.

Note that all public methods are prefixed with _ so that they (hopefully) don't clash with nginx's directives.

Note: *_content_by_lua_block directives are supported in >=v1.3.0.

// vanilla JS: const NginxConfFile = require('nginx-conf').NginxConfFile;
import {NginxConfFile} from '../../';

const filename = `${__dirname}/../files/readme.conf`;

NginxConfFile.create(filename, function (err, conf) {
    if (err || !conf) {
        console.log(err);
        return;
    }

    // reading values
    console.log('user: ' + conf.nginx.user?.[0]._value);
    console.log('http.server.listen: ' + conf.nginx.http?.[0].server?.[0].listen?.[0]._value);
    console.log('http.server.location.root:' + conf.nginx.http?.[0].server?.[0].location?.[3].root?.[0]._value);

    //writing values
    //NginxConfFile.create() automatically sets up a sync, so that whenever
    //a value is changed, or a node is removed/added, the file gets updated
    //immediately

    const onFlushed = () => {
        console.log('finished writing to disk');
    };

    conf.on('flushed', onFlushed);

    //listen to the flushed event to determine when the new file has been flushed to disk
    if (conf.nginx.events?.[0].connections) {
        conf.nginx.events[0].connections[0]._value = 1000;

        //don't write to disk when something changes
        conf.die(filename);
        conf.nginx.events[0].connections[0]._value = 2000; //change remains local, not in /etc/nginx.conf
    }

    //write to a different file
    conf.live(`${filename}.bak`);

    //force the synchronization
    conf.flush();

    //adding and removing directives
    if (conf.nginx.http) {
        conf.nginx.http[0]._add('add_header', 'Cache-Control max-age=315360000, public');
        console.log(conf.nginx.http[0].add_header?.[0]._value); //Cache-Control max-age=315360000, public

        conf.nginx.http[0]._add('add_header', 'X-Load-Balancer lb-01');
        conf.nginx.http[0]._add('add_header', 'X-Secure true');

        console.log(conf.nginx.http[0].add_header?.[0]._value); //Cache-Control max-age=315360000, public
        console.log(conf.nginx.http[0].add_header?.[1]._value); //X-Load-Balancer lb-01
        console.log(conf.nginx.http[0].add_header?.[2]._value); //X-Secure true

        conf.nginx.http[0]._remove('add_header'); //removes add_header[0]
        conf.nginx.http[0]._remove('add_header', 1); //removes add_header[1]
    }

    //adding a new block
    conf.nginx.http?.[0]._add('server');
    conf.nginx.http?.[0].server?.[0]._add('listen', '80');

    //that'll create something like this:
    /*
      server {
        listen 80;
      }
    */

    //multiple blocks
    conf.nginx.http?.[0]._add('server');
    conf.nginx.http?.[0].server?.[1]._add('listen', '443');

    /*
      server {
        listen 80;
      }
      server {
        listen 443;
      }
    */

    // blocks with values:
    conf.nginx.http?.[0].server?.[1]._add('location', '/');
    conf.nginx.http?.[0].server?.[1].location?.[0]._add('root', '/var/www/example.com');

    /*
      server {
        location / {
          root /var/www/example.com;
        }
      }
    */

    // you can also create empty blocks
    conf.nginx.http?.[0]._add('events', '', []); // events { }

    // lua blocks also work, but you can't put a mismatched "{" or "}" in a comment!
    conf.nginx.http?.[0].server?.[0].location?.[0]._addVerbatimBlock('rewrite_by_lua_block', '\n\
        ngx.say("this is a lua block!")\n\
        res = ngx.location.capture("/memc",\n\
          { args = { cmd = "incr", key = ngx.var.uri } }\n\
        )'
    );

    // remove old listener
    conf.off('flushed', onFlushed);

    // kill process when done writing to disk
    conf.on('flushed', () => {
        console.log('finished writing to disk, exiting');
        process.exit();
    });

    conf.flush();
});

Comments

Support for comments is supported-ish. Comments are attached to directives, and will always be rendered above the directive when using toString() (or _getString()).

Comments can be added, removed and updated via the _comments array on a node.

console.log(conf.nginx.events[0].use[0]._comments.length); // 1
console.log(conf.nginx.events[0].use[0]._comments[0]); // use [ kqueue | rtsig | epoll | /dev/poll | select | poll ];

//remove the comment
conf.nginx.events[0].use[0]._comments.splice(0, 1);

//add a new one
conf.nginx.events[0].use[0]._comments.push('my new comment');
console.log(conf.nginx.events[0].use[0]._comments.length); // 1
console.log(conf.nginx.events[0].use[0]._comments[0]); //my new comment

//update a comment's text
conf.nginx.events[0].use[0]._comments[0] = 'updated';
console.log(conf.nginx.events[0].use[0]._comments[0]); //updated

If the comment is in a weird place (like in the middle of a directive), it'll still be attached to the node. If it's after the directive (after the semicolon or closing brace), it will be attached to the next node, or ignored if it's at the end of the file.

Assuming this nginx configuration:

foo #comment
bar;

You will have this object structure:

console.log(conf.nginx.foo[0]._value); //bar
console.log(conf.nginx.foo[0]._comments[0]); //comment

But if the comment comes after:

foo bar;
#comment
console.log(conf.nginx.foo[0]._value); //bar
console.log(conf.nginx.foo[0]._comments.length); //0

Parser options

Support for go template syntax is provided via NginxParserOptions. By default, templating syntax is not supported.

To enable templating syntax, pass the following NginxParserOptions to the parser.parse or parser.parseFile function(s):

{
  templateSyntax: true
}

Development

git clone [email protected]:tmont/nginx-conf.git
cd nginx-conf
npm install
npm test

If you're making changes, you should run npm run watch in a separate terminal. tsc will output the JavaScript in the dist/ directory. The tests reference the JavaScript files in dist/, not the TypeScript files elsewhere.

Only the stuff in dist/ is included in the NPM package.

nginx-conf's People

Contributors

hackeryarn avatar jirutka avatar kevr2112 avatar mmontagna avatar tmont avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nginx-conf's Issues

Can I keep blank lines when formatting?

server {
    listen 9090;
    server_name localhost;

    location / {
        root /path/to/www;
    }
    
    location /exact/match.html {
        allow all;
    }
}

The above is what I expected, But expansion will produce the following results:

server {
    listen 9090;
    server_name localhost;
    location / {
        root /path/to/www;
    }
    location /exact/match.html {
        allow all;
    }
}

Variables get Removed during Parsing

Description:
Example Config:
/build${mobile_path}/
If it gets parsed and serialized again, the configuration looks like
/build$
For More Information see: raynigon/vscode-nginx-formatter#2

Expected Behaviour:
The expected bahviour would be to have the same variables in the configuration as before the config was parsed.

Testing:
Sample Code (TS) for testing:

const promise = new Promise<string>((resolve, reject)=>{
  nginx.parse(document, (error, tree)=>{
    if(error!=null){
      reject("Unable to parse Document: "+error);
      return;
    }
    const text = (new nginx.NginxConfFile(tree)).toString();
    resolve(text);
  });
});

_remove/update on a block not working.

Hi,

Config example :

rtmp{
  server{

    application A{
      live on;
      #..othercommands
    }

    application B{
      live on;
      #..othercommands
    }

    application C{
      live on;
      #..othercommands
    }

  }
}

Have added application blocks using _addVerbatimBlock function. Currently, there is no update function. So, for updating, I remove the block and add it again. But the following remove functions does not work :

 conf.nginx.rtmp.server._remove("application A")
 conf.nginx.rtmp.server._remove("application A",0)
 conf.nginx.rtmp.server._remove("application", "A")

Which is the correct way to remove or update the block ?

  • Cant use index of application ( application[1] ) to remove.

Reload nginx

Is it possible to reload nginx using this library?

Otherwise, exec should be used.

TypeError: conf.nginx.http.server._add is not a function

I got this error when I use nginx-conf. Could you pls help me to check? Thanks.

/home/lzw/go/src/github.com/cloud-pi/junos-ci-nginx/server.js:37
conf.nginx.http.server._add('listen', '80');
^

TypeError: conf.nginx.http.server._add is not a function
at /home/lzw/go/src/github.com/cloud-pi/junos-ci-nginx/server.js:37:26
at /home/lzw/go/src/github.com/cloud-pi/junos-ci-nginx/node_modules/nginx-conf/src/conf.js:295:15
at NginxParser.parse (/home/lzw/go/src/github.com/cloud-pi/junos-ci-nginx/node_modules/nginx-conf/src/parser.js:35:14)
at /home/lzw/go/src/github.com/cloud-pi/junos-ci-nginx/node_modules/nginx-conf/src/parser.js:232:10
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:380:3)

Comments are not properly formatted with config

After formatting, comments are not properly aligned.

Actual output:

http {
    include /etc/nginx/mime.types;
#gzip  on;
    include /etc/nginx/conf.d/*.conf;
    default_type application/octet-stream;
    log_format main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log  main;
    sendfile on;
#tcp_nopush     on;
    keepalive_timeout 65;
}

Expected output:

http {
    include /etc/nginx/mime.types;
    #gzip  on;
    include /etc/nginx/conf.d/*.conf;
    default_type application/octet-stream;
    log_format main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log  main;
    sendfile on;
    #tcp_nopush     on;
    keepalive_timeout 65;
}

Found a string but expected a directive with tricky log_format

Hi,
Before all, good job for this module!

During our first try to parse our complex nginx configuration, this exception has been resulted:

{ message: 'Found a string but expected a directive',
  index: 3252,
  line: 101 }

Here is what's happened around line 101:

86:   log_format logstash_json '{ '
87:     '"@timestamp": "$time_iso8601", '
88:     '"@message": "nginx - $remote_addr $request $status", ' 
89:     '"@fields": { '
90:       '"remote_addr": "$remote_addr", '
91:       '"remote_user": "$remote_user", '
92:       '"body_bytes_sent": "$body_bytes_sent", '
93:       '"request_time": "$request_time", '
94:       '"status": "$status", '
95:       '"request": "$request", '
96:       '"host": "$http_host", '
97:       '"request_method": "$request_method", '
98:       '"http_referrer": "$http_referer", '
99:       '"http_user_agent": "$http_user_agent", '
100:      '"http_x_forwarded_for": "$http_x_forwarded_for"'
101:    '}'
102:  '}';

I'll try to fix asap.

How to support Async

hello, How to support Async?
I want to perform subsequent operations after create is successful

Regexp parsing fails

Hi @tmont would be cool if you could fix this, since a user of the VSCode Formatting Plugin ran into this bug. The connected issue is raynigon/vscode-nginx-formatter#4

When parsing

location ~ ^/\d{3}/ {
    try_files $uri /index.html;
}

the dumped string looks like

location ~ ^/\d;

Proper way to add server?

Hi I want to dynamically add new servers to a node

I'm trying to do this:

conf.nginx.tcp._add('server', '{ listen 25565; server_name minecraft.gameserv.com; proxy_pass localhost:23456; }');

which gives me this output:

tcp {
    server { listen 25565; server_name minecraft.gameserv.com; proxy_pass localhost:23456; };
}

everything is cool except that it adds a semicolon after the closing bracket }; which is invalid nginx syntax. I'm assuming thats because it expects me to be adding individual directives

If statements are stripped when flushed.

If you load a config with an if statement inside it, and then call flush on it, the if statement brackets get stripped and it is not handle properly.

to reproduce:

const NginxConfFile = require('nginx-conf').NginxConfFile;

NginxConfFile.create('nginx.conf', (err, conf) => {
    conf.flush();
 );

ConfItem alias circularly references itself

node_modules/nginx-conf/src/conf.d.ts:44:21 - error TS2456: Type alias 'ConfItem' circularly references itself.
44 export declare type ConfItem = ConfItemContext & {

New to the world of TS, so not 100% sure if this is because of the way in which I'm using nginx-conf, but my gut tells me this is not the case. (Let me know if you'd like to see my implementation, please.)

For reference, I'm using this in an oclif app, and it works fine when I run it directly (using ./bin/run). However, I get the above when I try to publish my CLI app, which runs tsc -b before packing the tarball.

Thanks!

Location field

How to create something like this?

server {                                                 
    listen          80;                                  
    server_name     mydomain.com;                                 
    location /      { proxy_pass http://127.0.0.1:3000; }
}     

Tried the following:

conf.nginx.http._add('server');
conf.nginx.http.server._add('listen', '80');
conf.nginx.http.server._add('server_name', 'domain.com');
conf.nginx.http.server._add('location /', '{ proxy_pass http://127.0.0.1:3000; }');

But I'm getting:

conf.nginx.http.server._add('listen', '80');
                           ^
TypeError: Object server {
    listen 80;
    server_name ~.*;
    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}
,server;
 has no method '_add'

...because there is a server value already, I think.

Handle included files

How does this library handle included "sub-configs"? The files property is already an array files: [ '/etc/nginx/nginx.conf' ] but only contains the one file parsed. And I can't access the values in the included files so I assume includes are not treated specially?

_remove() method is mis-labeled in docs

conf.nginx.http.remove('add_header'); //removes add_header[0]
  conf.nginx.http.remove('add_header', 1); //removes add_header[1]

should be

conf.nginx.http._remove('add_header'); //removes add_header[0]
  conf.nginx.http._remove('add_header', 1); //removes add_header[1]

as there is no method remove().

License missing

@tmont

What license is nginx-conf? Can you add a LICENSE file + the proper package.json entry?

Config written incorrectly, when calling _remove twice()

For example, given something like the following config file:

http {
    test one {
        exist;
    }
    test2 two {
        exist;
    }
}

If I try and call *._remove on "test" and "test2" I can get strange results written to my nginx.conf file. Sometimes only one property is removed, sometimes the results get jumbled. It looks like writes are being intermingled.

Is this the expected behavior? I don't see this documented anywhere. It's possible to avoid this issue by calling flush() with a callback and chaining all nginx-conf calls that way, but this is cumbersome and the README seems to imply that this shouldn't be necessary.

Ability to _add given an index

NGINX is pretty picky in the ordering of locations.
given:

location ~ /user/.* {
   proxy_pass something1;
}
location ~ /user/abc {
  proxy_pass something2;
}

All traffic will go through something1 if my understanding is correct.
Because of wanting to dynamically edit locations, it would be beneficial to be able to _add locations at a specified index just like the _remove function.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.