Wandering Thoughts archives

2012-03-07

The hard part of custom environments on Fedora (or any Linux)

At one level, doing a custom X environment on top of Fedora is easy (as I alluded to in reply to a comment on this earlier entry). I do it in a perverse way with my desktop, and people who are sane enough to use the standard graphical login can do it by simply writing a script that starts everything (including their window manager) and putting an appropriately formatted file in /usr/share/xsessions (as of Fedora 16).

But all of that is the simple part. (As shown by the fact that I can look all of it up in about five minutes.)

The hard, complicated, and painful part of doing a custom environment on a modern Linux machine is figuring out all of the things that you need to run (and to do) to make all of the usual automatic things happen in your custom environment. Long gone are the days when a desktop environment was a window manager with a 'run some programs' menu; these days, a modern desktop environment has an ever growing number of moving parts, most of them mostly not documented and many of them needing other things as support. If you want things like automatic mounting and handling of removable disks, support for easy handling of wireless networks, and your laptop to suspend properly when you close the lid, you may be in for quite a bit of research and experimentation.

The other painful bit is due to where you usually have to get these programs from. There are independent implementations of some of what you need, but for most of it you generally have to selectively pick bits out of an existing desktop environment; you figure out what Gnome or KDE program is run to do a particular job, and then you start it in your desktop environment too. Of course these programs are not a stable, public interface that Gnome or KDE support as things that can be run outside the full Gnome or KDE environment. Instead they're internal implementation details, and such they keep changing. What program you run changes, how you run it changes, what it requires changes, and so on. Every time I upgrade Fedora, I can count on a couple of days of picking up the pieces of my custom environment again; I consider it a victory if only a few bits have to change.

(Increasingly you may also be up a creek if you are not running the standard environment. In Gnome 2, much of this functionality was provided by independent programs that you could run outside of the Gnome desktop environment. In Gnome 3 the Gnome Shell model is for 'applet' code to mostly run inside Gnome Shell itself, which means that you can't run it yourself in a different environment. So far the old 'applet' versions of various things are still being provided, but that probably won't last forever.)

linux/FedoraHardCustomEnvironments written at 23:16:54; Add Comment

How not to use Apache's ProxyPass directive

Periodically we need to set up reverse proxies with Apache's ProxyPass directive (to support our solution to the multiuser PHP problem). On the surface doing this fairly simple and straightforward; however, the important devil is in this spotlighted bit in the documentation:

If the first argument ends with a trailing /, the second argument should also end with a trailing / and vice versa. Otherwise the resulting requests to the backend may miss some needed slashes and do not deliver the expected results.

Since I have now stubbed my toe on this thoroughly, here are several ways to not use ProxyPass for this, all of which fall afoul of the above warning (some in less than obvious ways).

To start with, the basic template of ProxyPass is 'ProxyPass /a/path http://somewhere/else'. When Apache sees any URL that starts with /a/path, it removes /a/path from the front of the URL, puts whatever remains on the end of the second URL, and tries to fetch the resulting URL.

In all of the following examples, we want /url/ to be reverse proxied as a directory; the target has a page at the top level with a relative link to a.html.

First mistake:

ProxyPass /url/ http://localhost:8080

The top level page works and the link to a.html shows as link to /url/a.html, but attempts to follow the link fail with Apache being unable to fetch the URL http://localhost:8080a.html. This shows that Apache is effectively forming the URL by text substitution and then interpreting it later; because there is no / at the end of the second argument, it simply glued the raw text of everything past /url/ onto it and the result fails badly.

(This also doesn't do anything to handle a request for just '/url', but one can get around that with other tricks.)

Second mistake:

ProxyPass /url http://localhost:8080

If you request /url/ everything works. But if you request just /url you still get the page (instead of a redirection to the version with a version with a / on the end) and the relative link to a.html comes out as a link to /a.html (which doesn't exist and in any case is not reverse proxied) instead of /url/a.html, because your browser sees /url as a page in / instead of a directory.

This case is the tricky case because it's not obvious that we're breaking the rule from the documentation; after all, everything looks right since neither argument ends with a /. The problem is that when you make a bare request for http://localhost:8080, as you do when you ask for '/url', Apache implicitly adds a / on the end (because it has to; it must GET something from the server at localhost:8080). This implicit / means you have a / on the end of the second argument but not on the end of the first argument and have thus broken the rule.

My belief is that there is no simple way for whatever is behind the reverse proxy to fix this. Without peeking at special request headers that Apache reverse proxying supplies, it cannot tell whether a request for / is from someone who asked for '/url/' (and is okay) or someone who asked for '/url' (and should get redirected to /url/).

Third mistake:

ProxyPass /url http://localhost:8080/

If you ask for /url/ or anything under /url/, the reverse proxied web server receives a request for the (local) URL // or something that starts with that. Many web servers are unhappy about this. If you ask for just /url you get a page, but the relative links on the page are broken as before because it's still not redirected to /url/.

(However, now a suitably crazy web app can actually tell the difference between the two requests.)

As far as I can tell the only proper way to use ProxyPass in this situation is as follows:

ProxyPass /url/ http://localhost:8080/

This follows the rules and does not result in doubled /'s. It doesn't handle requests for /url at all, but I believe that you can arrange for /url to be redirected to /url/ by having a real /url directory in an appropriate place in your filesystem.

(In our environment most of these redirections are for user home pages, where /~user will already get redirected appropriately.)

web/ApacheProxyPass written at 02:24:29; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.