Using Racket to Configure Apache

I have a confession to make: I really hate writing boilerplate code.

I use Apache to serve lots of websites, have many lines of configuration code and have often longed for a way to capture all the patterns and reduce code duplication. I thought about using a macro language like m4 or the C preprocessor or even Ruby but neither alternative was particulary attractive. Then it hit me that I could describe the Apache configuration with plain S-expressions and use the full power of Racket to manipulate these and output normal configuration files. What makes this a compelling alternative is of course that S-expressions allow one to express tree-structured data very succinctly, like here:

( group ( VirtualHost * ) ( ServerName www . defsoftware . se ) ( RedirectPermanent / http://defsoftware . se/ ))

Racket—being a Lisp equipped with many powerful built-in functions—makes a full translator for these kind of trees simple to write.

Update: I got an e-mail from Eli Barzilay (of Racket fame) with some valuable feedback on how to improve my code by using functions in the scribble/text and racket/list libraries that are included with Racket. I’ve updated my code and put the old code at the bottom1 for reference. Eli also wrote about using the cool at-exp reader to mix text and code.

( require scribble/text ) ( define ( apache-config . complete-config ) ( define ( format-apache-config config ) ( match config (( list 'group ( list group ... ) directives ... ) ( list "<" ( add-between group " " ) ">" "

" " " ( add-newlines ( map format-apache-config directives )) "

" "</" ( first group ) ">" )) (( list ( list _ ... ) ... ) ( add-newlines ( map format-apache-config config ))) (( list _ ... ) ( add-between config " " )))) ( output ( format-apache-config complete-config )) ( newline ))

The output function takes care of the indentation in a pretty clever way.

Now—equipped with apache-config —we can start building functions that work with Apache S-expressions:

( define ( host-redirect from-hostname to-hostname ) ` ( group ( VirtualHost * ) ( ServerName , from-hostname ) ( RedirectPermanent / , ( string-append "http://" to-hostname "/" )))) ( apache-config ( host-redirect "defsoftware.com" "defsoftware.se" ) ( host-redirect "defsoftware.net" "defsoftware.se" ))

Output:

<VirtualHost * > ServerName defsoftware.com RedirectPermanent / http://defsoftware.se/ </VirtualHost> <VirtualHost * > ServerName defsoftware.net RedirectPermanent / http://defsoftware.se/ </VirtualHost>

Now I’m happy.

1 Click here to see the old code.