diff --git a/Changelog b/Changelog
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,10 @@
+iptadmin 1.3.0    22.10.2012:
+  * Add https support
+  * Add dialog for configuring ipv4 forwarding
+  * Fix js error related to inserting iptables rule
+  * Fix frontend markup for firefox 16
+  * Update dependenicy list: base-4, happstack-7, blaze-markup-0.5
+
 iptadmin 1.2.1    17.09.2011:
   * Add static files to iptadmin.cabal and source tarball.
 
diff --git a/doc/examples/config/iptadmin.conf b/doc/examples/config/iptadmin.conf
--- a/doc/examples/config/iptadmin.conf
+++ b/doc/examples/config/iptadmin.conf
@@ -1,3 +1,9 @@
 save command = /etc/init.d/iptables save
 port = 8000
 pam name = iptadmin
+ssl = enabled
+
+[SSL]
+create pair if does not exist = true
+crt path = /etc/iptadmin/iptadmin.crt
+key path = /etc/iptadmin/iptadmin.key
diff --git a/iptadmin.cabal b/iptadmin.cabal
--- a/iptadmin.cabal
+++ b/iptadmin.cabal
@@ -1,5 +1,5 @@
 Name:           iptadmin
-Version:        1.2.1
+Version:        1.3.0
 Cabal-Version:  >= 1.4
 Author:         Evgeny Tarasov
 Build-type:     Simple
@@ -11,7 +11,7 @@
 Stability:      Stable
 Synopsis:       web-interface for iptables
 Description:    web-interface for iptables with PAM authorization
-Category:       System, Tools, Web
+Category:       System, Tools, Web, Application
 Extra-source-files: html/htmlwrapper.html,
                     util/ptmpl/Setup.hs,
                     util/ptmpl/ptmpl.cabal,
@@ -44,19 +44,18 @@
 
 Executable iptadmin
     Build-Depends:  base >= 4 && < 5,
-                    haskell98,
                     utf8-string >= 0.3,
                     bytestring >= 0.9,
-                    happstack-server >= 6.2 && < 6.3,
-                    happstack-state >= 6.1 && < 6.2,
-                    happstack-util >= 6 && < 6.1,
+                    happstack-server >= 7.0 && < 7.1,
+                    happstack-server-tls >= 7.0 && < 7.1,
                     mtl >= 1.1,
                     safe >= 0.3,
                     iptables-helpers >= 0.4 && < 0.5,
                     process >= 1.0 && < 2,
-                    blaze-html >= 0.4,
+                    blaze-html >= 0.5,
+                    blaze-markup >= 0.5 && < 0.6,
                     parsec >= 2.1,
-                    containers >= 0.3,
+                    containers >= 0.4 && < 6,
                     time >= 1.1 && < 2,
                     random >= 1.0 && < 2,
                     pam >= 0.1 && < 1,
@@ -67,8 +66,9 @@
                     hsyslog >= 1.4 && < 2,
                     hdaemonize >= 0.4.4 && < 0.5,
                     file-embed >= 0.0.4 && < 0.1,
-                    old-time >= 1.0.0.3 && < 1.1,
-                    template-haskell >= 2.4
+                    old-time >= 1.0.0.3 && < 1.2,
+                    template-haskell >= 2.4,
+                    augeas >= 0.6 && < 0.7
     Main-Is:        Main.hs
     Other-modules:  IptAdmin.AccessControl
                     IptAdmin.AddChainPage
diff --git a/src/IptAdmin/Config.hs b/src/IptAdmin/Config.hs
--- a/src/IptAdmin/Config.hs
+++ b/src/IptAdmin/Config.hs
@@ -19,9 +19,22 @@
         saveCommand <- get cp "DEFAULT" "save command"
         port <- get cp "DEFAULT" "port"
         pamName <- get cp "DEFAULT" "pam name"
-        return $ IptAdminConfig saveCommand
-                               port
-                               pamName
+        sslEnabled <- get cp "DEFAULT" "ssl"
+        if sslEnabled then do
+            createPair <- get cp "SSL" "create pair if does not exist"
+            crtPath <- get cp "SSL" "crt path"
+            keyPath <- get cp "SSL" "key path"
+            return $ IptAdminConfig saveCommand
+                                    port
+                                    pamName
+                                    $ Just $ SSLConfig createPair
+                                                       crtPath
+                                                       keyPath
+            else
+            return $ IptAdminConfig saveCommand
+                                    port
+                                    pamName
+                                    Nothing
     case configE of
         Left (_, err) -> throwError ("Error on reading " ++ cONFpATHd </> cONFIGURATIONf ++ "\n" ++ err)
         Right config -> return config
diff --git a/src/IptAdmin/DelChainPage/Render.hs b/src/IptAdmin/DelChainPage/Render.hs
--- a/src/IptAdmin/DelChainPage/Render.hs
+++ b/src/IptAdmin/DelChainPage/Render.hs
@@ -7,7 +7,7 @@
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
 
-delChainForm :: String -> String -> Html
+delChainForm :: String -> String -> Markup
 delChainForm tableName chainName =
     H.div ! A.class_ "editForm" $
     H.form ! A.id "delChainform" ! A.method "post" $ do
diff --git a/src/IptAdmin/DelPage/Render.hs b/src/IptAdmin/DelPage/Render.hs
--- a/src/IptAdmin/DelPage/Render.hs
+++ b/src/IptAdmin/DelPage/Render.hs
@@ -7,7 +7,7 @@
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
 
-delPageForm :: (String, String, Int) -> String -> Html
+delPageForm :: (String, String, Int) -> String -> Markup
 delPageForm (tableName, chainName, rulePos) rule =
     H.div ! A.class_ "editForm" $
         H.form ! A.id "delform" ! A.method "post" $ do
diff --git a/src/IptAdmin/EditChainForm/Render.hs b/src/IptAdmin/EditChainForm/Render.hs
--- a/src/IptAdmin/EditChainForm/Render.hs
+++ b/src/IptAdmin/EditChainForm/Render.hs
@@ -8,7 +8,7 @@
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
 
-editChainForm :: (String, String) -> String -> Maybe String -> Html
+editChainForm :: (String, String) -> String -> Maybe String -> Markup
 editChainForm (tableName, chainName) newChainName mesMay =
     H.div ! A.class_ "editForm" $
         H.form ! A.id "editChainForm" ! A.method "post" $ do
@@ -19,6 +19,6 @@
                     H.td $
                         H.input ! A.type_ "text" ! A.name "newChainName" ! A.value (fromString newChainName) ! A.maxlength "20"
                     case mesMay of
-                        Nothing -> mempty :: Html
+                        Nothing -> mempty :: Markup
                         Just mes ->
                             H.td $ fromString mes
diff --git a/src/IptAdmin/EditForm/Render.hs b/src/IptAdmin/EditForm/Render.hs
--- a/src/IptAdmin/EditForm/Render.hs
+++ b/src/IptAdmin/EditForm/Render.hs
@@ -12,7 +12,7 @@
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
 
-checkBox :: String -> Bool -> Html
+checkBox :: String -> Bool -> Markup
 checkBox name on = do
     let chBox = H.input ! A.type_ "checkbox"
                         ! A.id (fromString name)
@@ -21,7 +21,7 @@
     if on then chBox ! A.checked "checked"
           else chBox
 
-printMesTd :: ResMessage -> Html
+printMesTd :: ResMessage -> Markup
 printMesTd rm = H.td $ fromString $ case rm of
                         RMError mes -> mes
                         RMSucc mes -> "ok " ++ mes
@@ -31,7 +31,7 @@
 maybeListToListMaybe (Just list) = map Just list
 maybeListToListMaybe Nothing = repeat Nothing
 
-editFormHtml :: EditForm a => (String,String,Int,[String]) -> a -> Maybe [ResMessage] -> Html
+editFormHtml :: EditForm a => (String,String,Int,[String]) -> a -> Maybe [ResMessage] -> Markup
 editFormHtml (tableName, chainName, rulePos, userChainNames) form errorListMay =
     let entryList = toEntryList form
         mesListMay = maybeListToListMaybe errorListMay
@@ -49,7 +49,7 @@
                         maybe mempty (\_-> H.th "Message") errorListMay
                     mapM_ (renderFormEntry userChainNames) $ zip entryList mesListMay
 
-renderFormEntry :: [String] -> (FormEntry, Maybe ResMessage) -> Html
+renderFormEntry :: [String] -> (FormEntry, Maybe ResMessage) -> Markup
 renderFormEntry _ (FESrc en inv str, resMesMay) =
     H.tr $ do
         H.td $ do
@@ -351,7 +351,7 @@
         maybe mempty printMesTd resMesMay
 renderFormEntry _ a = H.tr $ fromString $ "Unknown form entry: " ++ show a
 
-renderDNat :: Bool -> String -> Bool -> Bool -> Html
+renderDNat :: Bool -> String -> Bool -> Bool -> Markup
 renderDNat checked dnatAddr dnatRand dnatPersist =
     H.tr $ do
         H.td ! A.class_ "target" $ do
@@ -371,7 +371,7 @@
                     $ "persistent:"
             checkBox "dnatpersistent" dnatPersist >> H.br
 
-renderRedirect :: Bool -> String -> Bool -> Html
+renderRedirect :: Bool -> String -> Bool -> Markup
 renderRedirect checked redirPort redirRand =
     H.tr $ do
         H.td ! A.class_ "target" $ do
@@ -388,7 +388,7 @@
                     $ "random:"
             checkBox "redirrandom" redirRand
 
-renderSNat :: Bool -> String -> Bool -> Bool -> Html
+renderSNat :: Bool -> String -> Bool -> Bool -> Markup
 renderSNat checked snatAddr snatRand snatPersist =
     H.tr $ do
         H.td ! A.class_ "target" $ do
@@ -407,7 +407,7 @@
             H.label ! A.for "snatpersistent"
                     $ "persistent:"
             checkBox "snatpersistent" snatPersist >> H.br
-renderMasq :: Bool -> String -> Bool -> Html
+renderMasq :: Bool -> String -> Bool -> Markup
 renderMasq checked masqPort masqRand =
     H.tr $ do
         H.td ! A.class_ "target" $ do
@@ -424,7 +424,7 @@
                     $ "random:"
             checkBox "masqrandom" masqRand
 
-renderUserChain :: Bool -> [String] -> String -> Html
+renderUserChain :: Bool -> [String] -> String -> Markup
 renderUserChain checked allChains chain =
     H.tr $ do
         H.td ! A.class_ "target" $ do
@@ -437,7 +437,7 @@
             H.select ! A.id "userChain" ! A.name "userChain" $
                 mapM_ (renderOption chain) allChains
     where
-    renderOption :: String -> String -> Html
+    renderOption :: String -> String -> Markup
     renderOption selName optName = do
         let opt = H.option ! A.value (fromString optName) $ fromString optName
         let optSel = if optName == selName then opt ! A.selected "selected"
diff --git a/src/IptAdmin/EditPolicyForm/Render.hs b/src/IptAdmin/EditPolicyForm/Render.hs
--- a/src/IptAdmin/EditPolicyForm/Render.hs
+++ b/src/IptAdmin/EditPolicyForm/Render.hs
@@ -9,11 +9,11 @@
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
 
-editPolicyForm :: (String, String) -> Policy -> Html
+editPolicyForm :: (String, String) -> Policy -> Markup
 editPolicyForm (tableName, chainName) policy = do
     case policy of
-        ACCEPT -> mempty :: Html
-        DROP -> mempty :: Html
+        ACCEPT -> mempty :: Markup
+        DROP -> mempty
         a -> fromString ("Unsupported policy type: " ++ show a)
     H.div ! A.class_ "editForm" $
         H.form ! A.id "editPolicyForm" ! A.method "post" $ do
diff --git a/src/IptAdmin/LoginPage.hs b/src/IptAdmin/LoginPage.hs
--- a/src/IptAdmin/LoginPage.hs
+++ b/src/IptAdmin/LoginPage.hs
@@ -68,7 +68,7 @@
             -- 4. Редиректим на /show
             redir "/show"
 
-loginForm :: String -> Maybe String -> Html
+loginForm :: String -> Maybe String -> Markup
 loginForm login mesMay =
     H.div ! A.class_ "loginForm" $ do
         H.div ! A.class_ "loginForm2" $
diff --git a/src/IptAdmin/Render.hs b/src/IptAdmin/Render.hs
--- a/src/IptAdmin/Render.hs
+++ b/src/IptAdmin/Render.hs
@@ -13,7 +13,7 @@
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
 
-header :: String -> String -> Html
+header :: String -> String -> Markup
 header tableName pageHeader = do
     let filterB = tableName == "filter"
     let mangleB = tableName == "mangle"
@@ -24,7 +24,7 @@
     H.div ! A.class_ "pageHeader" $
         fromString pageHeader
 
-title :: Html
+title :: Markup
 title =
     H.div ! A.id "title" $ do
         H.a ! A.class_ "title" ! A.href "/" $ "IptAdmin"
@@ -32,7 +32,7 @@
             fromString $ intercalate "." $ map show $ versionBranch version
 
 -- Booleans says which link should be distinguished
-links :: Bool -> Bool -> Bool -> Html
+links :: Bool -> Bool -> Bool -> Markup
 links filt nat mangle =
     let
         filtA = H.a ! A.href "/show?table=filter" $ "Filter"
@@ -52,12 +52,12 @@
                 if mangle then mangleA ! A.class_ "activeTableLink"
                           else mangleA ! A.class_ "tableLink"
 
-logout :: Html
+logout :: Markup
 logout =
     H.div ! A.class_ "logout" $
         H.a ! A.href "/logout" $ "Logout"
 
-renderTarget :: RuleTarget -> (Html, Html)
+renderTarget :: RuleTarget -> (Markup, Markup)
 renderTarget target = case target of
             TAccept -> (H.span ! A.class_ "acceptTarget" $ "ACCEPT", mempty)
             TDrop -> (H.span ! A.class_ "dropTarget" $ "DROP", mempty)
@@ -81,10 +81,10 @@
                         fromString (printNatAddr natAddr)
                         " "
                         if rand then "random"
-                                else mempty :: Html
+                                else mempty :: Markup
                         " "
                         if persist then "persist"
-                                   else mempty :: Html
+                                   else mempty :: Markup
                 in
                     (target', param)
             TDNat natAddr rand persist ->
@@ -93,34 +93,34 @@
                         fromString (printNatAddr natAddr)
                         " "
                         if rand then "random"
-                                else mempty :: Html
+                                else mempty :: Markup
                         " "
                         if persist then "persist"
-                                   else mempty :: Html
+                                   else mempty :: Markup
                 in
                     (target', param)
             TMasquerade natPort rand ->
                 let target' = H.span ! A.class_ "masqueradeTarget" $ "MASQUERADE"
                     param = do
                         case natPort of
-                            NatPortDefault -> mempty :: Html
+                            NatPortDefault -> mempty :: Markup
                             _ -> fromString (printNatPort natPort)
                         if rand then do
                                     " "
                                     "random"
-                                else mempty :: Html
+                                else mempty :: Markup
                 in
                     (target', param)
             TRedirect natPort rand ->
                 let target' = H.span ! A.class_ "redirectTarget" $ "REDIRECT"
                     param = do
                         case natPort of
-                            NatPortDefault -> mempty :: Html
+                            NatPortDefault -> mempty :: Markup
                             _ -> fromString (printNatPort natPort)
                         if rand then do
                                     " "
                                     "random"
-                                else mempty :: Html
+                                else mempty :: Markup
                 in
                     (target', param)
             TUChain chainName ->
diff --git a/src/IptAdmin/ShowPage.hs b/src/IptAdmin/ShowPage.hs
--- a/src/IptAdmin/ShowPage.hs
+++ b/src/IptAdmin/ShowPage.hs
@@ -159,9 +159,11 @@
                           refreshString
                           (sortNatTable $ tNat iptables)
                           (sortNatTable $ tNat iptables')
+    forwState <- getForwardingState
     return $ buildResponse $ Template.htmlWrapper $ renderHtml $ do
         includeJs
         header "nat" "Iptables Nat table"
+        renderIpForwarding forwState
         showPageHtml nat
 
 showMangle :: CountersType -> Iptables -> Iptables -> IptAdmin Response
@@ -178,13 +180,13 @@
         header "mangle" "Iptables Mangle table. Rule editing is not supported for Mangle yet."
         showPageHtml mangle
 
-includeJs :: Html
+includeJs :: Markup
 includeJs =
     H.script H.! A.type_ "text/javascript"
              H.! A.src "/static/js/showpage.js"
              $ ""
 
-showPageHtml :: Html -> Html
+showPageHtml :: Markup -> Markup
 showPageHtml table =
     H.div H.! A.id "rules" $
         table
diff --git a/src/IptAdmin/ShowPage/Render.hs b/src/IptAdmin/ShowPage/Render.hs
--- a/src/IptAdmin/ShowPage/Render.hs
+++ b/src/IptAdmin/ShowPage/Render.hs
@@ -11,6 +11,7 @@
 import Iptables.Print
 import Iptables.Types
 import Text.Blaze
+import Text.Blaze.Internal
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
 
@@ -27,7 +28,7 @@
             -> String                 -- ^ random string for 'refresh' link
             -> [Chain]                -- ^ table's chains
             -> [Chain]                -- ^ chains with relative start counters state
-            -> Html
+            -> Markup
 renderTable (tableName, _) countType maxCounter refreshString chains chains' = do
     mapM_ (renderChain tableName countType maxCounter refreshString) $ zip chains chains'
     -- H.a ! A.href (fromString $ "/addchain?table="++tableName) $ "Add chain"
@@ -37,8 +38,8 @@
              ! A.id "addChainButton"
              $ "Add chain"
 
--- | Table name -> counters type -> max counter -> refresh string ->  Chain -> Html
-renderChain :: String -> CountersType -> Integer -> String -> (Chain,Chain) -> Html
+-- | Table name -> counters type -> max counter -> refresh string ->  Chain -> Markup
+renderChain :: String -> CountersType -> Integer -> String -> (Chain,Chain) -> Markup
 renderChain tableName countType maxCounterDiff refreshString (Chain n p counters rs, Chain _ _ counters' rs') =
     H.table ! A.class_ "rules" ! A.id (fromString $ "chain-table-" ++ tableName ++ "-" ++ n) $ do
         H.tr $ do
@@ -149,7 +150,7 @@
                          $ "Add rule"
 
 -- | (Table name, Chain name) -> Counters type -> max counter -> Rule -> Html
-renderRule :: (String, String) -> CountersType -> Integer -> (Int, (Rule, Rule)) -> Html
+renderRule :: (String, String) -> CountersType -> Integer -> (Int, (Rule, Rule)) -> Markup
 renderRule (tableName, chainName) countType maxCounterDiff (ruleNum, (Rule counters opts tar, Rule counters2 _ _)) =
     let mainTr = if even ruleNum then H.tr ! A.class_ "even"
                                            ! A.id (fromString $ "rule-tr-" ++ tableName ++ "-" ++ chainName ++ "-" ++ show ruleNum)
@@ -241,3 +242,17 @@
                 show b ++ x
             else
                 bytesToPrefix' xs nextLevel
+
+renderIpForwarding :: Bool -> Markup
+renderIpForwarding forwState = do
+    H.button ! A.id "forwStateButton"
+             ! A.class_ "bigActionButton editIpForwButton"
+             $ "IPv4 Forwarding:"
+    H.span ! A.id (case forwState of
+                    True -> "ipForwardOn"
+                    False -> "ipForwardOff"
+                    )
+           $ do
+        toMarkup $ case forwState of
+            True -> "On" :: String
+            False -> "Off"
diff --git a/src/IptAdmin/Types.hs b/src/IptAdmin/Types.hs
--- a/src/IptAdmin/Types.hs
+++ b/src/IptAdmin/Types.hs
@@ -30,7 +30,13 @@
 data IptAdminConfig = IptAdminConfig { cSaveCommand :: String
                                      , cPort :: Int
                                      , cPamName :: String
+                                     , cSSL :: Maybe SSLConfig
                                      }
+
+data SSLConfig = SSLConfig { scCreatePair :: Bool
+                           , scCrtPath :: String
+                           , scKeyPath :: String
+                           }
 
 -- | Display bytes or packets on show page
 data CountersType = CTBytes
diff --git a/src/IptAdmin/Utils.hs b/src/IptAdmin/Utils.hs
--- a/src/IptAdmin/Utils.hs
+++ b/src/IptAdmin/Utils.hs
@@ -3,13 +3,17 @@
 import Control.Concurrent
 import Control.Monad.Error
 import Control.Monad.State
+import Data.ByteString(empty)
+import Data.ByteString.UTF8(fromString)
 import Data.IORef
-import Data.Map
+import Data.Map hiding (empty)
+import Foreign.ForeignPtr.Safe
 import Happstack.Server
 import Iptables.Types
 import IptAdmin.System
 import IptAdmin.Types
 import Safe
+import System.Augeas
 import Text.ParserCombinators.Parsec.Prim hiding (State (..))
 import Text.ParserCombinators.Parsec.Char
 import Text.ParserCombinators.Parsec.Combinator
@@ -120,3 +124,34 @@
                     "#" ++ chainName ++ "_" ++ show (ruleNum - 15)
                 else
                     "#chain_" ++ chainName
+
+getForwardingState :: MonadIO m => ServerPartT (ErrorT String m) Bool
+getForwardingState = do
+    forwStateStr <- liftIO $ readFile "/proc/sys/net/ipv4/ip_forward"
+    let forwState = read forwStateStr :: Integer
+    case forwState of
+        0 -> return False
+        1 -> return True
+        a -> throwError $ "get " ++ show a ++ " from /proc/sys/net/ipv4/ip_foward"
+
+setForwardingState :: MonadIO m => Bool -> ServerPartT (ErrorT String m) ()
+setForwardingState forwState = do
+    -- 1. /proc/...
+    let forwState' = case forwState of
+            True -> "1"
+            False -> "0"
+    liftIO $ writeFile "/proc/sys/net/ipv4/ip_forward" forwState'
+
+    -- 2. /etc/sysctl.conf @ augeas
+    augMay <- liftIO $ aug_init empty empty []
+    aug <- case augMay of
+        Just a -> return a
+        Nothing -> throwError "Error on augeas init"
+
+    res <- liftIO $ withForeignPtr aug (\a -> aug_set a (fromString "files/etc/sysctl.conf/net.ipv4.ip_forward") (fromString forwState'))
+    when (res /= success) $
+        throwError $ "Error on augeas run: " ++ show res
+
+    res <- liftIO $ withForeignPtr aug aug_save
+    when (res /= success) $
+        throwError $ "Error on augeas run: " ++ show res
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -12,7 +12,7 @@
 import Data.Version
 import Happstack.Server.Internal.Monads
 import Happstack.Server.SimpleHTTP
-import Happstack.State.Control
+import Happstack.Server.SimpleHTTPS
 import IptAdmin.AccessControl
 import IptAdmin.AddChainPage as AddChainPage
 import IptAdmin.AddPage as AddPage
@@ -20,6 +20,7 @@
 import IptAdmin.DelChainPage as DelChainPage
 import IptAdmin.DelPage as DelPage
 import IptAdmin.EditChainPage as EditChainPage
+import IptAdmin.EditIpForwPage as EditIpForwPage
 import IptAdmin.EditPage as EditPage
 import IptAdmin.EditPolicyPage as EditPolicyPage
 import IptAdmin.InsertPage as InsertPage
@@ -32,7 +33,10 @@
 import Prelude hiding (catch)
 import System.Exit
 import System.Environment
+import System.IO
+import System.Process
 import System.Posix.Daemonize
+import System.Posix.Files
 import System.Posix.User
 import System.Posix.Syslog
 
@@ -63,26 +67,38 @@
 startDaemon :: IptAdminConfig -> a -> IO ()
 startDaemon config _ = do
     sessions <- newIORef empty
-    let httpConf = Conf (cPort config) Nothing Nothing 60
 
-    -- create socket manually because we must listen only on 127.0.0.1
-    sock <- socket AF_INET Stream defaultProtocol
-    setSocketOption sock ReuseAddr 1
-    loopbackIp <- inet_addr "127.0.0.1"
-    bindSocket sock $
-        SockAddrInet (fromInteger $ toInteger $ cPort config) loopbackIp
-    listen sock (max 1024 maxListenQueue)
+    case cSSL config of
+        Nothing -> do
+            let httpConf = Conf (cPort config) Nothing Nothing 60 Nothing
 
-    httpTid <- forkIO $ simpleHTTPWithSocket' unpackErrorT
-                                              sock
-                                              httpConf
-                                              $ decodeBody (defaultBodyPolicy "/tmp/" 4096 20000 40000 )
-                                              >> authorize sessions config control
-    waitForTermination
-    syslog Notice "Shutting down..."
-    killThread httpTid
-    syslog Notice "Shutdown complete"
+            -- create socket manually because we must listen only on 127.0.0.1
+            sock <- socket AF_INET Stream defaultProtocol
+            setSocketOption sock ReuseAddr 1
+            loopbackIp <- inet_addr "127.0.0.1"
+            bindSocket sock $
+                SockAddrInet (fromInteger $ toInteger $ cPort config) loopbackIp
+            listen sock (max 1024 maxListenQueue)
 
+            httpTid <- forkIO $ simpleHTTPWithSocket' unpackErrorT
+                                                      sock
+                                                      httpConf
+                                                      $ decodeBody (defaultBodyPolicy "/tmp/" 4096 20000 40000 )
+                                                      >> authorize sessions config control
+            waitForTermination
+            syslog Notice "Shutting down..."
+            killThread httpTid
+            syslog Notice "Shutdown complete"
+        Just sslConfig -> do
+            checkAndCreatePair sslConfig
+            let tlsConf = nullTLSConf { tlsPort = cPort config
+                                      , tlsCert = scCrtPath sslConfig
+                                      , tlsKey  = scKeyPath sslConfig
+                                      }
+            simpleHTTPS' unpackErrorT
+                         tlsConf
+                         $ decodeBody (defaultBodyPolicy "/tmp/" 4096 20000 40000 ) >> authorize sessions config control
+
 unpackErrorT :: (Monad m) => UnWebT (ErrorT String m) a -> UnWebT m a
 unpackErrorT handler = do
     resE <- runErrorT handler
@@ -103,6 +119,7 @@
                , dir "editchain" EditChainPage.pageHandlers
                , dir "delchain" DelChainPage.pageHandlers
                , dir "editpolicy" EditPolicyPage.pageHandlers
+               , dir "editipforw" EditIpForwPage.pageHandlers
                ]
 
 {- | Save changes if user have changed something
@@ -130,3 +147,49 @@
     when (userID_ /= 0) $ do
         putStrLn "the program have to be run under root privileges"
         exitFailure
+
+checkAndCreatePair :: SSLConfig -> IO ()
+checkAndCreatePair sslConfig = do
+    crtExist <- fileExist $ scCrtPath sslConfig
+    keyExist <- fileExist $ scKeyPath sslConfig
+
+    let checkRegFile filePath = do
+            st <- getFileStatus $ filePath
+            if isRegularFile st  then return False
+                                 else return True
+
+    crtWrongType <- if crtExist
+                        then checkRegFile $ scCrtPath sslConfig
+                        else return False
+    when crtWrongType $ do
+        syslog Critical $ "crt path already exists and it's not a regular file: " ++ scCrtPath sslConfig
+        exitFailure
+
+    keyWrongType <- if keyExist
+                        then checkRegFile $ scKeyPath sslConfig
+                        else return False
+
+    when keyWrongType $ do
+        syslog Critical $ "key path already exists and it's not a regular file: " ++ scKeyPath sslConfig
+        exitFailure
+
+    when (not crtExist || not keyExist) $
+        do
+            if scCreatePair sslConfig
+                then do
+                -- TODO: check for parent directory
+                syslog Notice $ "Creating selfsigned key pair: " ++ scCrtPath sslConfig ++ ", " ++ scKeyPath sslConfig
+                (_, _, _, h) <- liftIO $ runInteractiveCommand $ "openssl req -new -x509 -nodes -out "
+                                                               ++ scCrtPath sslConfig
+                                                               ++ " -keyout "
+                                                               ++ scKeyPath sslConfig
+                                                               ++ " -batch"
+                ec <- liftIO $ waitForProcess h
+                case ec of
+                    ExitSuccess -> return () -- hGetContents o
+                    ExitFailure a -> do
+                        syslog Critical $ "error while running openssl: " ++ show a
+                        exitFailure
+                else do
+                syslog Critical $ "key and crt pair doesn't exist"
+                exitFailure
diff --git a/static/css/iptadmin.css b/static/css/iptadmin.css
--- a/static/css/iptadmin.css
+++ b/static/css/iptadmin.css
@@ -183,7 +183,7 @@
     width : 60px;
 }
 th.col6 {
-    width : 64px;
+    width : 69px;
 }
 /*
 Цвета для различных targets
@@ -341,3 +341,14 @@
     padding: 5px;
 }
 
+/* Цвета флага ip forwarding
+ */
+span#ipForwardOn{
+    padding-left: 4px;
+    color: green;
+}
+
+span#ipForwardOff{
+    padding-left: 4px;
+    color: red;
+}
diff --git a/static/js/showpage.js b/static/js/showpage.js
--- a/static/js/showpage.js
+++ b/static/js/showpage.js
@@ -31,6 +31,7 @@
         $(".addChainButton").click(addChainButtonHandler);
         $(".delChainButton").click(delChainButtonHandler);
         $(".editPolicyButton").click(editPolicyButtonHandler);
+        $(".editIpForwButton").click(editIpForwButtonHandler);
     };
 
     var ajaxError = function (x, t, m) {
@@ -246,7 +247,7 @@
                                         });
                                     }
                                     else {
-                                        dialog1.html(ans2);
+                                        dialog1.html(ans9);
                                         dialog1.dialog("option","width",'auto');
                                         dialog1.dialog("option","height",'auto');
                                         dialog1.dialog("option","position","center");
@@ -624,6 +625,71 @@
                 $('#dialog1').html("");
                 dialog1 = $('#dialog1').dialog({
                     title: 'Select policy',
+                    modal: true,
+                    resizable: false,
+                    buttons: dialogButtons,
+                });
+                dialog1.html(ans);
+                dialog1.dialog("option","width",'auto');
+                dialog1.dialog("option","height",'auto');
+                dialog1.dialog("option","position","center");
+            },
+        });
+    };
+    var editIpForwButtonHandler = function () {
+        $.ajax({
+            url: '/editipforw',
+            dataType: 'html',
+            error: ajaxError,
+            success: function (ans) {
+                var dialogButtons = [
+                    {
+                        text: "Submit",
+                        click: function () {
+                            dialog1.dialog("option","buttons",[]);
+                            var str = $("#editIpForwForm").serialize();
+                            $.ajax({
+                                type: "POST",
+                                url: "/editipforw",
+                                data: str,
+                                error: ajaxError,
+                                success: function (ans) {
+                                    dialog1.dialog("option", "buttons", dialogButtons);
+                                    if (ans.split(':')[0] == "ok") {
+                                        dialog1.dialog("destroy");
+                                        newSpan = "";
+                                        switch(ans.split(':')[1]){
+                                            case "on":
+                                                newSpan = '<span id="ipForwardOn">On</span>';
+                                                $('#ipForwardOff').replaceWith(newSpan);
+                                                break;
+                                            case "off":
+                                                newSpan = '<span id="ipForwardOff">Off</span>';
+                                                $('#ipForwardOn').replaceWith(newSpan);
+                                                break;
+                                            default: alert("wrong value: " + ans.split(':')[1]);
+                                        };
+                                    }
+                                    else {
+                                        dialog1.html(ans);
+                                        dialog1.dialog("option","width",'auto');
+                                        dialog1.dialog("option","height",'auto');
+                                        dialog1.dialog("option","position","center");
+                                    }
+                                },
+                            });
+                        },
+                    },
+                    {
+                        text: "Cancel",
+                        click: function() {
+                            dialog1.dialog("destroy");
+                        },
+                    },
+                ];
+                $('#dialog1').html("");
+                dialog1 = $('#dialog1').dialog({
+                    title: 'Select forwarding state',
                     modal: true,
                     resizable: false,
                     buttons: dialogButtons,
diff --git a/util/ptmpl/ptmpl.cabal b/util/ptmpl/ptmpl.cabal
--- a/util/ptmpl/ptmpl.cabal
+++ b/util/ptmpl/ptmpl.cabal
@@ -13,7 +13,6 @@
 
 Executable ptmpl
     Build-Depends:  base >= 3 && < 5,
-                    haskell98,
                     parsec >= 2.1
     Main-Is:        Main.hs
     Hs-Source-Dirs: src
diff --git a/util/ptmpl/src/Main.hs b/util/ptmpl/src/Main.hs
--- a/util/ptmpl/src/Main.hs
+++ b/util/ptmpl/src/Main.hs
@@ -1,7 +1,7 @@
 
 module Main where
 
-import System
+import System.Environment
 import Text.ParserCombinators.Parsec
 
 main :: IO ()
