diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,11 +1,11 @@
 muon
 ====
 Muon is a static blog generator, meaning that it takes files written in
-convenient markup and converts it to HTML and CSS ready to deploy to a web
-server.
+convenient markup and converts it to HTML and CSS ready to deploy to a
+web server.
 
-Installing
-----------
+Installing from Darcs
+---------------------
 First, install the package by getting the darcs repo.
 
     $ darcs get http://repos.kaashif.co.uk/muon
@@ -15,9 +15,19 @@
     $ cd muon
     $ cabal install
 
-After that, assuming you have configured cabal and/or your PATH correctly, muon
-should be usable. Here are some things you may want to do:
+After that, assuming you have configured cabal and/or your PATH
+correctly, muon should be usable. Here are some things you may want to
+do:
 
+Installing from Hackage
+-----------------------
+Installing from Hackage using Cabal is as simple as:
+
+    $ cabal install muon
+
+Bear in mind this may not be the most up-to-date version, but it will be
+a stable version.
+
 Using Muon
 ----------
 Initialising a blog:
@@ -34,14 +44,78 @@
 
     $ muon generate
 
-Notes
------
+Previewng the site locally:
+
+    $ muon serve
+
+Uploading site to server:
+
+    $ muon upload
+
+Multiple commands in sequence:
+
+    $ muon init generate upload
+    $ muon generate serve
+
+Configuring Muon
+----------------
+After "muon init" is run, a file called "config.ini" is created. This is
+where you configure the blog. By default, it should look like this:
+
+    [site]
+    title=Default site
+    author=Your Name
+    tagline=Something descriptive
+    style=/style.css
+
+    [remote]
+    user=root
+    server=webserver
+    dir=/var/www/htdocs/
+
+The [site] section needs little explanation - you can preview the site
+yourself and see where those strings go. The "style" option denotes the
+location of a custom CSS file.
+
+The [remote] section is to configure the command run by Muon to upload
+the site. The command is "rsync -a --delete site/ user@server:dir", with
+the key words replaced with your SSH credentials on a server. If you're
+not sure if the configuration is correct, remember: the directory must
+end in a slash!
+
+Extra Pages
+-----------
+Aside from a homepage, archive, and posts, you might want some extra
+pages on your site, like "example.com/recipes" or "example.com/laptop".
+You can add such pages to your site simply by creating a file with the
+right name in the "pages/" directory of your blog.
+
+For example, if your blog is at "myblog.com" and you want a page at
+"myblog.com/mypage", edit the file "pages/mypage" and fill it with HTML.
+Bear in mind, this content will go in between the "header" and "footer"
+templates, so you don't need to include <body> or <html> tags. Here's
+how you might do that:
+
+    $ cat >> pages/mypage <<EOF
+    <h2>My Custom Page</h2>
+    <p>This is a page I made!</p>
+    EOF
+
+And that's that! Next time you "muon generate upload", the pages will be
+accessible at "myblog.com/mypage".
+
+Writing Posts
+-------------
+To add a new post, create a new file in the "posts/" directory with the
+suffix ".post".
+
 When writing posts, make sure you put the title on the first line, the date on
 the second, and a short description (for the archive) on the third line. The
-rest should be valid Markdown. See the posts/ directory after site
+rest should be valid Markdown. See the "posts/" directory after site
 initialisation for some examples.
 
-The posts are ordered lexicographically, _not_ by date. This means "aaa.post"
-will always come before "bbb.post", regardless of the date contained in the file.
-
-"muon upload" is currently hardcoded. Stay tuned for per-blog config files.
+In the archive, posts are ordered lexicographically, _not_ by date.
+This means "aaa.post" will always come above "bbb.post", regardless of
+the date contained in the file itself. This allows you to decide the
+order of your posts yourself, if you want to separate tutorials and
+rants, for example.
diff --git a/muon.cabal b/muon.cabal
--- a/muon.cabal
+++ b/muon.cabal
@@ -2,16 +2,18 @@
 -- see http://haskell.org/cabal/users-guide/
 
 name:                muon
-version:             0.1.0.3
+version:             0.1.0.4
 synopsis:            Static blog generator
 description:
     Program which takes blog posts and pages written in Markdown and
     compiles them into a tree of HTML pages which can then be served
     by any web server.
     .
-    Muon is similar in function to Hakyll <http://jaspervdj.be/hakyll/>
-    but has far fewer features (and dependencies) and is generally not
-    ready for use in production as of yet.
+    As of now, Muon supports:
+    .
+        * Generating a site from Markdown and HTML
+        * Previewing a site locally using happstack-server
+        * Uploading a site to a server using rsync
 homepage:            http://repos.kaashif.co.uk/darcs?r=muon;a=summary
 license:             BSD3
 license-file:        LICENSE
@@ -36,5 +38,5 @@
 
 executable muon
   main-is:             Main.hs
-  build-depends:       base ==4.6.*, text ==0.11.*, HStringTemplate ==0.7.*, directory ==1.2.*, Glob ==0.7.*, process ==1.2.*, blaze-html ==0.7.*, markdown ==0.1.*, ConfigFile==1.1.*, MissingH==1.2.*
+  build-depends:       base ==4.6.*, text ==0.11.*, HStringTemplate ==0.7.*, directory ==1.2.*, Glob ==0.7.*, process ==1.2.*, blaze-html ==0.7.*, markdown ==0.1.*, ConfigFile==1.1.*, MissingH==1.2.*, happstack-server==7.3.*
   hs-source-dirs:      src
diff --git a/src/Config.hs b/src/Config.hs
new file mode 100644
--- /dev/null
+++ b/src/Config.hs
@@ -0,0 +1,21 @@
+module Config (getSetting, rsyncCmd) where
+
+import System.Directory
+import Data.ConfigFile
+import Data.Either.Utils
+import qualified Data.Text as T
+
+blogCP ::  IO ConfigParser
+blogCP = fmap forceEither $ readfile emptyCP "config.ini"
+
+getSetting ::  String -> String -> IO String
+getSetting sect c = do
+    cp <- blogCP
+    return $ forceEither $ get cp sect c
+
+rsyncCmd ::  IO String
+rsyncCmd = do
+    user <- getSetting "remote" "user"
+    server <- getSetting "remote" "server"
+    dir <- getSetting "remote" "dir"
+    return $ "rsync -av --delete site/ " ++ user ++ "@" ++ server ++ ":" ++ dir
diff --git a/src/Constant.hs b/src/Constant.hs
--- a/src/Constant.hs
+++ b/src/Constant.hs
@@ -4,6 +4,5 @@
 import System.Directory
 
 sitePath = "site/"
-pageNames = ["about", "contact"]
 siteDirs = ["site", "style", "posts", "templates", "pages"]
-mkdir = createDirectoryIfMissing False
+mkdir = createDirectoryIfMissing True
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -7,12 +7,14 @@
 import System.Directory
 import System.FilePath.Glob
 import System.Environment
-import System.Process (runCommand)
+import System.Process (runInteractiveCommand)
 import Post (generatePosts)
 import Home (generateHome)
 import Archive (generateArchive)
 import Page (generatePages)
+import Server (startServer)
 import Constant
+import Config
 import Paths_muon
 
 ensureDirs = mkdir sitePath
@@ -35,7 +37,7 @@
 
 copyStatic = do
     copyFile "style/style.css" (sitePath ++ "style.css")
-    runCommand $ "cp -R static " ++ sitePath ++ "static"
+    runInteractiveCommand $ "cp -R static " ++ sitePath ++ "static"
 
 generateSite = copyStatic
             >> generatePosts
@@ -46,20 +48,24 @@
 showHelp = putStrLn "Usage: muon [commands]\n\n\
 \  help        show this help message\n\
 \  init        initialise a default blog in the current dir\n\
-\  generate    generate static blog in 'site' directory\n\n\
+\  generate    generate static blog in 'site' directory\n\
+\  serve       serve site at localhost:8000\n\
+\  upload      upload site to server\n\n\
 \Report bugs to <kaashif@kaashif.co.uk>"
 
 clearSite = mkdir sitePath
          >> removeDirectoryRecursive sitePath
          >> mkdir sitePath
 
-rsyncCmd = "rsync -a --delete site/ root@webserver:/var/www/htdocs/"
+printRun ::  String -> IO ()
+printRun cmd = putStrLn ("Running \'" ++ cmd ++ "\'") >> runInteractiveCommand cmd >> return ()
 
 proc ::  String -> IO ()
 proc cmd
     | cmd == "init" = createDefaults
     | cmd == "generate" = clearSite >> generateSite
-    | cmd == "upload" = void $ runCommand rsyncCmd
+    | cmd == "serve" = putStrLn "Serving site at http://127.0.0.1:8000/" >> startServer
+    | cmd == "upload" = rsyncCmd >>= printRun
     | otherwise = showHelp
 
 getArgsHelp = do
diff --git a/src/Page.hs b/src/Page.hs
--- a/src/Page.hs
+++ b/src/Page.hs
@@ -6,13 +6,25 @@
 import Site
 import Text.StringTemplate
 import Text.StringTemplate.GenericStandard
+import System.Directory
+import Control.Monad
 import Constant
 
+
 pageTemplate = do
     templates <- directoryGroup "templates" :: IO (STGroup T.Text)
     let Just t = getStringTemplate "generic" templates
     return t
 
+onlyFiles ::  [FilePath] -> IO [FilePath]
+onlyFiles fs = filterM doesFileExist fs
+
+pageNames ::  IO [String]
+pageNames = do
+    cs <- getDirectoryContents "pages"
+    let fs = map (\x -> "pages/" ++ x) cs
+    fmap ( map (drop 6) ) (onlyFiles fs)
+
 renderPage ::  Site -> StringTemplate T.Text -> T.Text -> T.Text
 renderPage s t c = render
                $ setAttribute "site" s
@@ -35,4 +47,4 @@
     writePage p c
     putStrLn $ "Generated " ++ p
 
-generatePages = mapM_ generatePage pageNames
+generatePages = pageNames >>= mapM_ generatePage
diff --git a/src/Post.hs b/src/Post.hs
--- a/src/Post.hs
+++ b/src/Post.hs
@@ -13,12 +13,16 @@
 import Data.Typeable
 import Data.Data
 import Data.List
+import Data.Char
+import qualified Data.String.Utils as S
 import Site
 import Control.Monad
 import Constant
 
 postPath = "posts/" :: String
 
+replace a b c = S.replace a b (T.unpack c)
+
 data Post = Post { title :: T.Text
                  , link :: T.Text
                  , date :: T.Text
@@ -36,8 +40,11 @@
                $ setAttribute "site" s
                $ setAttribute "post" p t
 
-renderName ::  Site -> StringTemplate T.Text -> String -> IO T.Text
-renderName s t n = liftM (renderPost s t) (getPost (0, n))
+renderPostT ::  Post -> IO T.Text
+renderPostT p = do
+    t <- postTemplate
+    s <- readSite
+    return $ renderPost s t p
 
 makeExtract ::  Post -> T.Text
 makeExtract p = T.pack
@@ -48,55 +55,54 @@
                  ++ "<br/><a href=\'" ++ T.unpack (link p) ++ "\'>Read more...</a>"
                  ++ "<br/><br/><hr/>"
 
-makePost ::  (Int, [String]) -> Post
-makePost l = Post { title  = T.pack $ head (snd l)
-                  , link = T.pack $ "/post/" ++ show (fst l)
-                  , date = T.pack $ snd l !! 1
-                  , comment = T.pack $ snd l !! 2
-                  , content = T.pack $ extractContent (snd l) }
+makePost ::  [String] -> Post
+makePost l = Post { title  = T.pack $ head l
+                  , link = T.pack $ "/" ++ S.replace "-" "/" (l !! 1) ++ "/" ++ linkify (head l)
+                  , date = T.pack $ l !! 1
+                  , comment = T.pack $ l !! 2
+                  , content = T.pack $ extractContent l
+                  }
 
 extractContent ::  [String] -> String
 extractContent l = TL.unpack
+                 $ TL.replace "<pre>" "<pre class=\'prettyprint\'>"
                  $ renderHtml
                  $ markdown def
                  $ TL.pack
                  $ unlines
                  $ drop 3 l
 
-getPost ::  (Int, FilePath) -> IO Post
+getPost ::  FilePath -> IO Post
 getPost n = do
-    c <- readFile (snd n)
-    return $ makePost (fst n, lines c)
+    c <- readFile n
+    return $ makePost $ lines c
 
-getNames ::  IO [(Int, FilePath)]
+getNames ::  IO [FilePath]
 getNames = do
     d <- globDir [compile "*.post"] postPath
-    let l = (sort . head . fst) d
-    return $ zip [1..(length l)] l
+    return $ (sort . head . fst) d
 
-renderPosts ::  IO [T.Text]
-renderPosts = do
-    templates <- directoryGroup "templates" :: IO (STGroup T.Text)
-    let Just t = getStringTemplate "post" templates
-    ns <- getNames
-    s <- readSite
-    mapM (renderName s t . snd) ns
+linkify ::  [Char] -> [Char]
+linkify s = filter isLetter $ map toLower $ S.replace " " "-" s
 
-writePosts ::  [T.Text] -> IO ()
-writePosts ps = mapM_ writePost (zip [1..(length ps)] ps)
+writePosts ::  [Post] -> IO ()
+writePosts ps = mapM_ writePost ps
 
-writePost ::  (Int, T.Text) -> IO ()
+writePost ::  Post -> IO ()
 writePost p = do
-    mkdir $ sitePath ++ "post"
-    mkdir $ sitePath ++ "post/" ++ show (fst p)
-    writeFile (sitePath ++ "post/" ++ show (fst p) ++ "/index.html") (T.unpack $ T.append "\n" $ snd p)
+    let d = S.replace "-" "/" (T.unpack $ date p) ++ "/" ++ (linkify $ T.unpack $ title p)
+    mkdir $ sitePath ++ d
+    c <- renderPostT p
+    writeFile (sitePath ++ d ++ "/index.html") (T.unpack $ T.append "\n" c)
 
+getAllPosts ::  IO [Post]
 getAllPosts = do
     ns <- getNames
     mapM getPost ns
 
+getAllExtracts ::  IO [T.Text]
 getAllExtracts = do
     ps <- getAllPosts
     return $ map makeExtract ps
 
-generatePosts = renderPosts >>= writePosts >> putStrLn "Generated posts"
+generatePosts = getAllPosts >>= writePosts >> putStrLn "Generated posts"
diff --git a/src/Server.hs b/src/Server.hs
new file mode 100644
--- /dev/null
+++ b/src/Server.hs
@@ -0,0 +1,7 @@
+module Server where
+
+import Happstack.Server ( Browsing(EnableBrowsing), nullConf
+                        , serveDirectory, simpleHTTP
+                        )
+startServer ::  IO ()
+startServer = simpleHTTP nullConf $ serveDirectory EnableBrowsing ["index.html"] "site/"
diff --git a/src/Site.hs b/src/Site.hs
--- a/src/Site.hs
+++ b/src/Site.hs
@@ -7,6 +7,7 @@
 import Data.Data
 import Data.ConfigFile
 import Data.Either.Utils
+import Config
 
 data Site = Site { title :: T.Text
                  , style :: T.Text
@@ -20,15 +21,14 @@
                    , tagline = "Description of this blog"
                    }
 
-getSetting ::  ConfigParser -> String -> T.Text
-getSetting cp s = T.pack $ forceEither $ get cp "site" s
-
 readSite ::  IO Site
 readSite = do
-    r <- readfile emptyCP "config.ini"
-    let cp = forceEither r
-    return $ Site { title = getSetting cp "title"
-                  , style = getSetting cp "style"
-                  , author = getSetting cp "author"
-                  , tagline = getSetting cp "tagline"
+    t <- getSetting "site" "title"
+    s <- getSetting "site" "style"
+    a <- getSetting "site" "author"
+    g <- getSetting "site" "tagline"
+    return $ Site { title = T.pack t
+                  , style = T.pack s
+                  , author = T.pack a
+                  , tagline = T.pack g
                   }
diff --git a/src/def/config.ini b/src/def/config.ini
--- a/src/def/config.ini
+++ b/src/def/config.ini
@@ -3,3 +3,8 @@
 author=Your Name
 tagline=Something descriptive
 style=/style.css
+
+[remote]
+user=root
+server=webserver
+dir=/var/www/htdocs/
diff --git a/src/def/posts/first.post b/src/def/posts/first.post
--- a/src/def/posts/first.post
+++ b/src/def/posts/first.post
@@ -2,4 +2,13 @@
 2014-04-05
 A comment
 
-Some content
+Something interesting. Here is some highlighted code:
+
+    #include <stdio.h>
+    
+    int main()
+    {
+        printf("Hello, world!\n");
+        return 0;
+    }
+
diff --git a/src/def/style/style.css b/src/def/style/style.css
--- a/src/def/style/style.css
+++ b/src/def/style/style.css
@@ -129,7 +129,7 @@
 	padding: 20px;
 	background: #DDDDDD;
 	color: #333333;
-	margin: 0 -20px 20px;
+	margin: 0;
 	overflow-x:auto;
 }
 li pre {
diff --git a/src/def/templates/header.st b/src/def/templates/header.st
--- a/src/def/templates/header.st
+++ b/src/def/templates/header.st
@@ -3,6 +3,12 @@
 <head>
 <title>$site.title$</title>
 <link rel="stylesheet" type="text/css" href="$site.style$">
+<script type="text/javascript"
+  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
+</script>
+<script 
+  src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js?skin=sunburst">
+</script>
 </head>
 <body>
 <div class="wrapper">
@@ -18,8 +24,6 @@
             <li> <a href="/contact">Contact</a></li>
             <li>//</li>
             <li> <a href="/archive">Archive</a></li>
-            <li>//</li>
-            <li> <a href="http://git.kaashif.co.uk/">Code</a></li>
         </ul>
 </header>
 <hr id="header" />
