location ~* \.(jpe?g|png|gif|ico)$ {
...
}
That would be pretty messy inside of JSON or YAML. You couldn't have the location line be a key for a map/hash, because you can have multiple blocks with the same "key".Besides, as bad as nginx configs are, just trying to understand which block "traps" a request is where you can spend most of your time; see ifIsEvil [1].
[1] https://www.nginx.com/resources/wiki/start/topics/depth/ifis...
However Apache just can't do some things that help you shooting in your foot. Maybe the C++ vs. Java comparison is not too far fetched.
I'm in the middle of a project built entirely in nginx and it's astoundingly performant. The restrictions on what I can do in (mainline) nginx force me to think through how I structure the blocks and directives with better logic representative of a web server and not an application server, which is what I'm used to.
DigitalOcean has a decent tutorial on now nginx decides on server and location block [1]. And, related to ifIsEvil, this blog post [2] goes a little into explaining how nginx "traps" a request. If someone has better resources, I would appreciate them.
[1] https://www.digitalocean.com/community/tutorials/understandi...
[2] http://agentzh.blogspot.com/2011/03/how-nginx-location-if-wo...
The tool interprets the nginx conf, rather than compiling any of it (as nginx does with the rewrite rules), makes it easy to log which lines are involved in the processing as it hits them.
YAML's initial release was 2001[0], likely not yet popular or stable enough for consideration.
JSON was likewise "released" in 2002[1] with a similar story.
In all likelihood, we're probably just lucky Igor didn't go with XML.
Okay I'll bite, what's wrong with writing nginx to go with XML?
XML is easily translatable to JSON, so... there's that.
Not really. XML is a document markup language, where order is important. JSON is a serialization format, and is a bit more bare-boned. For example, how would you transfer this XML to json, and back to XML?
<foo bar="baz"><bork>foo1</bork><bork>foo2</bork></foo> {
"#" = "foo",
"bar" = "baz",
"." = [
{ "#" = "bork", "." = "foo1" },
{ "#" = "bork", "." = "foo2" }
]
}
Or, for something more verbose (but maybe more intelligible), you could use "$element" as key for element names, and "$children" as key for child elements / text. (The point of choosing $ as a prefix, is it is not a valid character in attribute names, so cannot conflict with them.)I think it could be reasonably easy to come up with a config file standard in XML or JSON, but that the format will have to rely on the strengths of each. Translating between the two just becomes an unreadable mess. If anything, if I were to write an application that allowed for either format, I would come up with a separate standard for each. More code/upkeep, but when the config files are intended for humans and to be hand-written, the focus should be on the user.
First, a quick disclaimer: Apache conf format is not really XML. It leverages XML-like syntax but it's mostly not XML and avoids most of the serious problems that XML tends to bring, which I'll explain in more detail below.
XML was designed to provide structure to documents, it was not designed as a configuration syntax or a data serialization format. XML is meant for a document that already exists in its own right as a document, where the XML is added on as a layer to aid automated semantic understanding of that document's structure. It is not meant to directly represent programming data structures. As such, XML tags are designed to pop out and be visible from significant amounts of text that is not metadata. When there's more tags than text, as is usually the case when you try to use XML to write programming data structures, XML winds up being hopelessly verbose, and it's hard to avoid errors writing it (like misspelling end tags, forgetting a slash, putting end tags in the wrong order, etc.)
When not used for its intended purpose, XML winds up being hard for humans to write directly and hard(er than yaml and json) to write programs to parse it. In yaml and json, there's a standard, mostly direct mapping to common data structures in most high-level languages. With XML you have to make a lot of trivial decisions to make use of features that weren't designed for what you're trying to do. The most obvious examples are the distinction between attributes and tags: what does each one mean? What do tagnames represent? What do attribute values represent? What do attribute names represent? How do you handle CDATA that has more XML in it? XML is designed to elegantly handle something like this:
<A>first section <B>marked up section</B> second section</A>
But this kind of structure is horrible for a configuration file, unless the CDATA sections are a parsed language of their own and parsed externally, which is essentially what Apache does. If you're trying to use XML to specify data structures like lists and trees, it's messy. Consider this example: <VirtualHost>
<ServerName>my.server.domain.com</ServerName>
<DocumentRoot>/var/lib/www/my.server.domain.com</DocumentRoot>
</VirtualHost>
You might envision "VirtualHost" to be an item in a list, where the value of that item is a dictionary with subkeys specifying "ServerName" and "DocumentRoot." But in fact, there's more to it than that. An XML parser also gives you all the whitespace in between those two tags. You can discard it, you can write checks to ensure that nothing ever ends up in that unused CDATA area by mistake, you can write tools to generate the XML-- but no matter what method you choose it's something you have to think about that just doesn't come up if you are using a language designed for writing programming data structures instead of abusing one designed for marking up text documents.And that example highlights another problem with XML which is a flat out lack of support for common programming data types such as lists and integers. In the example above, how would you know that "<VirtualHost>" represents an item in a list, but "<ServerName>" should be a key in a dictionary? XML doesn't help you there, every parser decides for itself.
The fact that you have to pick a convention is the crux of the issue. "Easy" is a subjective term, but the fact is there isn't a direct mapping between XML And JSON.
It means that if you're using XML and converting it into a programming data structure, you have to make a bunch of decisions about how to handle the XML. It means that if you're converting a programming data structure to XML, you have to have a bunch of specific rules for how to generate that XML.
With JSON, you only have to make those decisions if you need to use data structures that aren't supported by JSON.
1. They created a paid version that has some additional basic features such as cache purging, dynamic upstream name resolution, and a few others. Charge for support, charge for some fancy management interface, monitoring, but for basic features (most of them available in Tengine [0]) - thanks, but no thanks. You lost me as an evangelist! In fact, in may aspects, they now are catching up with Tengine!
2. Instead of making LuaJIT integration standard and avoid the need to escape Lua in the configuration files, they invented some subpar JavaScript. People already use Lua widely, it's fast, it's great - don't you have anything better to do than invent yet another language!? I really can't believe pragmatic people would have done this, honestly! Speaks so badly about their thought process! I know can expect anything stupid from them!
3. The configuration language is not very intuitive. If they embedded Lua, the whole configuration could be a Lua script that initializes some internal state. This would have been a dream come true!
Web servers can have notoriously complex configs, up to the point where designing a mini-language might a worse idea than stripping down an embeddable language, such as Lua.
Lua, especially when sandboxed, seems like a fitting configuration language: http://stackoverflow.com/questions/1224708/how-can-i-create-...
I actually have some special corner case API endpoints that nginx just simply can not handle in the manner I would prefer. Further, the regex based location syntax, and even the prefix based ones, are not really what you want; you want a "Path" object that's aware of what / in a URL means, and does the right thing if you do/don't add it to the URL. (And it's not as easy as "/foo/bar/baz/?")
[1]. Conditionally streaming an upload to a backend (i.e., if auth fails, don't stream) is impossible; nginx will buffer the entire request body, either in memory or on disk, and there is no way to change this behavior.
(You're definitely not the only one to ask that question.)
I've been toying with getting a couple home servers going (replaced home service w/ business service, just installed two router based DMZ, looking at lightweight hardware -- probably will be Fit-PC products). I was going to run a separate reverse proxy and Lighttpd or similar but a quick glance makes it seem like Caddy could be used for both and more easily. Thanks for the link.
(Edit. BTW, you're not here: https://en.wikipedia.org/wiki/Comparison_of_web_server_softw...
You can do things like
{
"comment": ["blah blah comment message"],
"k1" : "v1", "k2" : "v2", ...
}
Or some silliness like that.https://groups.yahoo.com/neo/groups/sml-dev/conversations/to...
Well ok. But I'd still argue that Nginx was invented before the popularization of YAML. I think I didn't see YAML until I got in touch with Rails in 2007, which used the format extensively. And even then, almost everyone I met didn't take it seriously, saying that it is a joke until Microsoft, IBM, etc support it.
Note that it's not really fair to call Apache's configuration language "XML". Apache relies on XML for some structured data in its configuration file, but all the individual directives are parsed separately from the XML.
import json
import sys
sys.stdout.write("%s\n" % json.dumps(json.load(sys.stdin).get(sys.argv[1], None)))
This will accept JSON on standard input and will return the value of an object with the key name specified by the first command-line argument. $ echo '{ "value1" : { "sub-value": 5 }, "value2": 99 }' | python json-test.py value1
{"sub-value": 5}
$ echo '{ "value1" : { "sub-value": 5 }, "value2": 99 }' | python json-test.py value2
99
Such a program will look similar in any language with a json library that maps objects and arrays to native data structures. Granted, my simple tool will fail if the JSON isn't an object, but it's a very simple matter to extend it to handle lists and literals. For many applications this is a huge advantage over XML, especially if the point of the JSON isn't configuration but rather inter-application communication (aka data serialization).(1) https://www.nginx.com/blog/launching-nginscript-and-looking-...
(disclaimer: I work at NGINX)
content_by_lua_block {
ngx.say("hello, world")
}1. Nginx
2. IIS 6 (strange metabase thing)
3. Apache (XML, mostly)
4. IIS 7, 7.5 (XML, but with some of the files scattered through your Windows directory, and also some values aren't valid in some of the files).
5. Tomcat (XML plus madness).
I'd say the thing that makes all web-servers a pain is debugging which rules are passing/failing, and where are they sending their results to.
I think the thing which makes Nginx easier than the others is probably that it doesn't try to support the 'shared hosting' scenario, which adds a lot of mess.
I would prefer it if it were more like openssh or supervisor. Though I suspect those styles of configs are would make some of the more advanced configurations a pain.