Hunchentoot is a Common Lisp webserver by Edi Weitz. It can be used to serve static pages, but most people use it to write web applications in Lisp. There are a few other Lisp webservers, but it's probably the most capable, most compatible and best-maintained one at the moment.
This isn't a general Common Lisp tutorial. If you want such a thing, I would recommend the excellent Practical Common Lisp, which is available in book form or free online.
Hunchentoot will work on most Lisp implementations, though not clisp. If you're using SBCL on Windows, you should still be able to use it, but it will be single-threaded; so you can't really use it for production websites. It's probably okay for development. SBCL on Linux is probably the ideal (free) production environment; it's fast, threaded, and supports Unicode.
Assuming you have asdf-install, you can install hunchentoot by just doing:
Hunchentoot has a list of functions associated with page names called *DISPATCH-TABLE*. It goes through this list one by one running the functions with the HTTP request; the function should return another function, which will be run with the request to produce a page as response. It comes with a few handy functions to match page names by prefix and by regular expression, but you can write your own if you like. A simple dispatch table looks like this:
`(,(create-prefix-dispatcher "/test" 'test-page) ,(create prefix-dispatcher "/about" 'about-page)))
You can set dispatch-tables per server, but setting the global one is probably the easiest way to start off.
When the server is running, now, going to http://localhost:myport/test will run the test-page function. It should return a HTML string, which will be returned to the user. You can generate the HTML any way you like. There are a few HTML generators by the same author as the webserver; html-template fills values into a template (it's based on an old PERL library) while cl-who converts s-expressions into HTML.
Obviously, that in itself isn't enough to write a webapp. You want to be able to take input in the form of HTTP parameters, for instance. (parameter "paramname") will return the value of the (GET or POST) parameter called "paramname", or nil if it doesn't exist.
There's a lot more to it than that, of course, but that's probably enough to get started. Hunchentoot has most features common to normal webservers, and the documentation is quite helpful. Here's a quick example:
(defpackage :testservTo run this, just compile it, and do (testserv:start-server :port 8080), and go to http://localhost:8080/test
`(,(create-prefix-dispatcher "/test" 'test-page)
,(create-prefix-dispatcher "/about" 'about-page)))
(defun test-page ()
(let ((name (parameter "name")))
(format nil "Hi, <b>~a</b>" name)
"Name: <form action='/test' method='get'><input type='text' name='name' /><input type='submit' name='submit' /></form>")))
(defun about-page ()
"<h1>Hunchentoot Demo</h1>This is a very simple demonstration of the Hunchentoot webserver.")
Update: There's a second, more interesting, article on the subject here.