Skip navigation

Here’s an Apache one-liner I often find myself using. It will list all of the server names and alises that are contained in the active Apache config files on a machine. I’ll go into the parts of the command and how to modify it to suit your needs. This assumes a bash-like shell (with grep, sed, sort, tr and a for loop), root (or permission to run the httpd binary directly) and if you wish to modify the examples, a little command-fu.

First, let’s get the one-liner itself out of the way. This one-liner is actually a chain of commands on a single line.

THECONFS="`httpd -S 2>&1 | grep -oE '\/[^\:]+' | grep -vE '^\s*#'`"; for ACONF in ${THECONFS}; do cat ${ACONF} | tr '\t' ' ' | grep -E '^ *(ServerName|ServerAlias)' | sed -r 's/^( |ServerName|ServerAlias)+//g' | tr ' ' '\n'; done | sort -fu

Yeah, all of that gunk is on one line. If you ran it straight, it should turn out something like this:[12:53:28][root@igoo:~]$ THECONFS="`httpd -S 2>&1 | grep -oE '\/[^\:]+' | grep -vE '^\s*#'`"; for ACONF in ${THECONFS}; do cat ${ACONF} | tr '\t' ' ' | grep -E '^ *(ServerName|ServerAlias)' | sed -r 's/^( |ServerName|ServerAlias)+//g' | tr ' ' '\n'; done | sort -fu
admin.foo.com
admin.foo.dev
foodev
*.foodev
*.foo.com
*.foo.dev
www.foo.com
www.foo.dev
[13:06:50][root@igoo:~]$
A handy list in your terminal to copy and paste. It’s complete (vanilla `httpd -S` will not give aliases). It’s sorted and the duplicates have been removed. That list of active domains on the hellish WPMU server that Dick in Marketing needed? Now you have it easily.

In the above format, we have a set of network names that we can put into a spreadsheet, hand to QA or use in whatever ways we want. Once we understand what the one-liner does and how to change it, we can also use it for geeky goodness too. At that point, we can search for any Apache directive we wish.

If you understand what’s in the one-liner and already see what the trick is, you can skip the rest of this tutorial. You have your one-liner and may go in peace. Be well. :)

For those that went “But what does it MEAN?!?!”, the first thing we do here is set a variable named THECONFS to the output of some chained commands to get a list of configuration files.

THECONFS="`httpd -S 2>&1 | grep -oE '\/[^\:]+' | grep -vE '^\s*#'`";

The backtick (` or “grave“) denotes where our “command” begins and ends. This is known formally as shell expansion. Inside the backticks, we first run the command `httpd -S`. Then we filter the output using grep until all we have are file names. If you’re curious what the normal output is like, run `httpd -S` yourself. It is completely harmless. This portion of our one-liner is good to go as-is, so I’m going to skip the detail so we can get to the stuff you can play with. We tell the bash-like shell we are using that we are done setting the variable by using the end-of-line terminator: The character “;”, not some odd Galactica-Schwarzenegger hybrid like you Sci-Fi fans hoped.

Next, we start up a `for` loop. The usual bash-style syntax of `for` is as follows.

for NEWVARIABLE in thing1 thing2 thing3; do
  #run commands using the variable ${NEWVARIABLE} in place of each "thing"
done

In our case, each “thing” is the name of an Apache configuration file and the NEWVARIABLE is called “ACONF” accordingly. We get the file names from our variable THECONFS instead of “thing1 thing2 thing3”.

for ACONF in ${THECONFS}; do
  #run commands using the variable ${ACONF} in place of each "thing"
done

Let’s look at what we’re doing inside of our real `for` loop.

cat ${ACONF} | tr '\t' ' ' | grep -E '^ *(ServerName|ServerAlias)' | sed -r 's/^( |ServerName|ServerAlias)+//g' | tr ' ' '\n'

We `cat` the configuration file to convert the contents to STDOUT. Since we want a one-liner, we take advantage of command piping so we can pass the resulting STDOUT to our next command without missing a beat.

After the `cat`, we use `grep` to pull only the lines containing the words “ServerName” or “ServerAlias”. The pipe symbol (“|”) between these two words means OR. If we wanted to, we could substitute different things here such as replacing the text “ServerName|ServerAlias” with “DocumentRoot”, but we have more than one spot to do so in, so hang on a sec.

We take the STDOUT, no converted to

Finally, we sort everything ignoring case and cleaning out duplicates using `sort -fu`. Those of you that immediately jumped to saying something like “FU `sort`! FU in the eye!” when you first saw that part should be ashamed.

Like the domain names from the first example above, but this time show the DocumentRoots for each.
We just changed the regex portions to match “DocumentRoot” instead of “ServerName|ServerAlias”. For example you may try it with “ErrorLog” or “ReqriteRule”.

THECONFS=`httpd -S 2>&1 | grep -oE '\/[^\:]+' | grep -vE '^\s*#'`; for ACONF in ${THECONFS}; do cat ${ACONF} | tr '\t' ' ' | grep -E '^ *(DocumentRoot)' | sed -r 's/^( |DocumentRoot)+//g' | tr ' ' '\n'; done | sort -fu

Some Notes

  • I skipped on the detail, but in the first step when I set the variable “THECONFS”, I also remove the commented out lines from the config file.
  • I said that running `httpd -S` is harmless, but that is not exactly the absolute truth. If you have a god-awful mess in your Apache configuration and/or hundreds of config files, just parsing those configs and validating them could take a while on a very active or stressed server… perhaps even bog it down. If you are running commands on a production machine without knowing what you are doing or what kind of configuration is on that machine, then that is your major issue – not the command that you decided to run.
  • You may have noticed the "2>&1" after my `httpd` command. This pipes STDERR (error messages) to STDOUT (normal messages). Unfortunately, most of `httpd`’s output is sent to STDERR. I don’t know why it does that. For more info on STDOUT and STDERR redirections, see this.
  • I left braces in where I could for simplicity. Yes, I know that they are extraneous in regex when there is only one option to match. If this bothers you to the point of wanting to comment about it, please go troll against the n00b someplace else. I left the braces in there for them. If you’re a n00b and want to learn about regex, look here.
  • There’s a lot that can be done with the regex used for matching directives. If you’re a master of regex and not shell scripting, I forced regex extended syntax in `grep` and `sed` so you can hack away.

Leave a comment