Hacker News new | past | comments | ask | show | jobs | submit login
Gixy: Nginx Configuration Static Analyzer (github.com/dvershinin)
169 points by mmsc 3 days ago | hide | past | favorite | 28 comments





Using the nginx module on NixOS[1] and enabling services.nginx.validateConfigFil, which defaults to true, generated nginx configurations will be checked by Gixy[2]. The build will actually fail if Gixy finds any issues.

[1]: https://github.com/NixOS/nixpkgs/blob/nixos-24.11/nixos/modu... [2]: https://github.com/NixOS/nixpkgs/blob/nixos-24.11/pkgs/build...


Nice work, tons of extra stuff vs the original.

Had a thought: imagine if it were a subcommand of nginx (whichever fork will accept it) - that’d give it a much wider audience.

Even more impactful would be if analysis always ran at nginx startup. Wouldn’t have to be blocking but getting warned about risks would help more folks configure things more correctly more often.

Either way great to have tools to help with correctly configuring the parts of your infra that are exposed to the wild internet.


'nginx -t' exists as a general syntax checker, would be neat to expand it further to include these in depth checks.

What's annoying about the built-in checker is that it attempts to connect proxypass backends. So if you want to run this in CI you will get connection refused errors.

Put the proxy settings into variables and you can sidestep that. It also allows NgINX to start up when the backends may not be running.

e.g.

    set $upstream_app         backend;
    set $upstream_port        8888;
    set $upstream_proto       http;
    proxy_pass                $upstream_proto://$upstream_app:$upstream_port;

On the other hand, if it never checked those, you would run into problems, when you rely on those being available and somehow they are not.

On the other hand, I've grown to like these tools being separate, since it allows the check-tool to move faster. Updating the thing all of your production requests go through always has a bit of aprehension. Updating a config linter with no prod-impact? Meh, just do it.

However, this would be great if a distribution wanted to integrate it into their default nginx package (and maybe have a nginx-minimal package around to install nginx without it). Though e.g. debian has gotten hilarious amounts of flak in the past for attempting things like this.


I already learned one thing regarding add_header

Worth the read already. Initially I even thought the analyzer was 'wrong' but curl tests indeed shows that add_header replaces all, surprisingly to me.

Thanks!

But I dont really like the installation of a pip/python ecosystem but that is just my issue :) I now simply copy the configurations from a python free servers and analyze them.


uv makes the experience of installing dependencies in Python much better.

actually I just dont want any python on my servers :)

Pipx or pyenv

I have been building a platform [1] which makes it easy to deploy internal tools. Instead of taking the config file approach, it allows you to install each app at a unique location (domain name + url path). Within its location, the app owns all the URLs and can managing request routing without requiring a global config update.

The advantage is that new app installations cannot interfere with an existing app. I wrote more about this approach at https://clace.io/blog/webserver/

[1] https://github.com/claceio/clace


nice idea but i get that error when i try to use the docker image (on a nixos env)

NameError: name 'SRE_FLAG_TEMPLATE' is not defined. Did you mean: 'SRE_FLAG_VERBOSE'?

(using the mentioned docker command on README $ docker run --rm -v `pwd`/nginx.conf:/etc/nginx/conf/nginx.conf getpagespeed/gixy /etc/nginx/conf/nginx.conf)


NGINX config language grates on me. Whyyy did they have to come up with their own config format? It is so much nicer to configure Caddy with JSON file for example. Probably would also be much easier to statically check things about the config, than having to create a parser for NGINX config (or somehow integrate NGINX' own parser maybe). Probably the best one can do is either have NGINX at some point offer alternative config that uses JSON, or have some converter from JSON to NGINX config.

As a counterpoint, I find custom formats to often be nicer than reusing generic ones: atomic values (individual lexemes, primitive types: strings, numbers, etc) tend to have custom formats or semantic restrictions anyway (say, dates, length-limited strings, range-limited numbers, though in some cases numbers are also just restricted strings), so that part is mostly handled from scratch either way. And then there is composition, with JSON--apparently the most popular format now--not having a standard way to encode sum types, so you basically have to hammer those on top. At which point it feels like building on top of a JSON structure instead of building on top of a sequence of characters, but not in a very different way: sometimes it is more helpful in some parts, sometimes adds more clutter than needed. Likewise with XML: it is not uncommon to see something like <my-custom-format>a string in a custom format here, or even a base64-encoded blob</my-custom-format>.

In practice it is easier to use JSON for interfaces, since for someone unfamiliar with parsing it is less work to sort out on the other end, and then you have at least a partially specified structure, the rest can be easier to specify (with JSON schema, for instance), there are readily available libraries and tools to work with it, to do at least some of the parsing without writing a parser. But I think cleaner interfaces can be achieved with custom formats.


Nginx's configuration is the most flexible I've ever seen. When writing an nginx module, you have a handle to the config file being read, and you can do whatever you want. Conventions of syntax really are just conventions. There's no grammar.

I'd prefer a formal language with a parse tree and all that, but I think the spirit of the nginx code is "just what you need and nothing more."


crossplane is an nginx<-->json converter: https://github.com/nginxinc/crossplane

It works well, but probably doesn't solve your actual problem, because it still uses nginx _format_ -- just in json:)


nginx unit[1] has JSON configuration. Although it's not terrible to write a hand-rolled recursive descent parser.

[1] https://unit.nginx.org/configuration/


Would it be useful or easier to plug in if these were rules developed for platforms such as Semgrep? It looks like they already have an existing nginx ruleset: https://semgrep.dev/p/nginx.

They can always use some extra contributions, and would slot into existing tooling within a pipeline.


Great tool! Also, what about apache2, any similar tool suggestions?

uh, I'm hitting this one https://github.com/dvershinin/gixy/blob/master/docs/en/plugi...

how serious is header injection? it sounds pretty serious, is it?


[flagged]


Please submit a PR

The need for a configuration file analyzer is a good sign your software is overly complex and poorly architected.

Configuration files should be self-documenting.

Instead nginx taught us that if != if.


I'm using nginx for many years (used mostly apache before that) and would say as web servers configurations go nginx is one of the easiest to work with. I've seen complex and hard to understand nginx configs but they abused rewrite and logic which they implement was complex itself.

add_header inheritance is counterintuitive bot once you know how it works it should not be a problem. Another problematic directive is "if" - AFAIK Igor (nginx creator) designed config to be declarative but had to add "if" (imperative directive) after numerous feature requests and "if" didn't fit existing architecture well.


Try Caddy once; it’s a revelation. I have committed fairly atrocious crimes with nginx over the years, only to figure out just how much better I could have had it.

I've tried to try - yet still on Nginx as my primary web server and Apache somewhat secondary (with may be 5% for Apache and 95% for Nginx) web server of choice.

No doubts I'm not an expert in Caddy and there are some chances it has unique selling proposition, but I'm yet to find it.

My take on Caddy was - something to let your quickly-crafted-something-newshiny-loneley-dev-docker-container-to-be-available-to-the-world - sort of the same case if I do some tests (we call it MVP here) on my great-idea Flask app and I need plain reverse proxy in front of it with SSL termination, as noone except me and may be couple of Shodan bots won't see.

Yet not mentioned unclear stable releases policy for Caddy.


I tried. I failed to configure it to work as a proxy that proxypasses to php-fpm.

I'd call it's configuration way less intuitive than the one of ngnix (and I wouldn't call myself a great enjoyer of ngnix configuration).


It's absolutely true that the nginx config has some really obtuse features, "if" probably being the best example. But just because they're there doesn't mean you have to use them, and the documentation for "if" includes ample warning about its pitfalls and openly advises against using it.

In fact, I'd argue that learning not to use them unless they're absolutely necessary is a good lesson on the importance of keeping things simple. When I was a beginner to web servers, I spent quite a few hours wrangling nginx configs trying to do things like fancy conditional redirects, removing .php extensions from pages, etc.. But over the years I've slowly learned that most of this logic belongs in application code, not in nginx, and nowadays I can set up a new nginx server in minutes because the configuration format is actually quite simple and intuitive once you understand what you really need, and what you should leave out or implement elsewhere.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: