diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## Modern URI 0.3.4.3
+
+* Percent encode delimiter characters and `@` that appear in a path
+  component. [PR 47](https://github.com/mrkkrp/modern-uri/pull/47).
+
+* Sub-domains that look like IPv4 can now be parsed. [Issue
+  46](https://github.com/mrkkrp/modern-uri/issues/46).
+
 ## Modern URI 0.3.4.2
 
 * Improved handling of percent-encoded sequences of bytes that cannot be
diff --git a/Text/URI/Parser/Text/Utils.hs b/Text/URI/Parser/Text/Utils.hs
--- a/Text/URI/Parser/Text/Utils.hs
+++ b/Text/URI/Parser/Text/Utils.hs
@@ -33,7 +33,6 @@
 import qualified Data.Text as T
 import Text.Megaparsec
 import Text.Megaparsec.Char
-import qualified Text.Megaparsec.Char.Lexer as L
 
 -- | Parser that can parse host names.
 pHost ::
@@ -44,7 +43,6 @@
 pHost pe =
   choice
     [ try (asConsumed ipLiteral),
-      try (asConsumed ipv4Address),
       regName
     ]
   where
@@ -53,16 +51,6 @@
     ipLiteral =
       between (char '[') (char ']') $
         try ipv6Address <|> ipvFuture
-    octet = do
-      o <- getOffset
-      (toks, x) <- match L.decimal
-      when (x >= (256 :: Integer)) $ do
-        setOffset o
-        failure
-          (fmap Tokens . NE.nonEmpty . T.unpack $ toks)
-          (E.singleton . Label . NE.fromList $ "decimal number from 0 to 255")
-    ipv4Address =
-      count 3 (octet <* char '.') *> octet
     ipv6Address = do
       pos <- getOffset
       (toks, xs) <- match $ do
diff --git a/Text/URI/Render.hs b/Text/URI/Render.hs
--- a/Text/URI/Render.hs
+++ b/Text/URI/Render.hs
@@ -248,8 +248,8 @@
                 | sap && w == 32 -> ('+', (bs'', []))
                 | nne w -> (chr (fromIntegral w), (bs'', []))
                 | otherwise ->
-                  let c :| cs = encodeByte w
-                   in (c, (bs'', cs))
+                    let c :| cs = encodeByte w
+                     in (c, (bs'', cs))
     f (bs', x : xs) = Just (x, (bs', xs))
     encodeByte x = '%' :| [intToDigit h, intToDigit l]
       where
@@ -289,7 +289,7 @@
 
 instance RLabel 'PathPiece where
   needsNoEscaping Proxy x =
-    isUnreserved x || isDelim x || x == 64
+    isUnreserved x
 
 instance RLabel 'QueryKey where
   needsNoEscaping Proxy x =
diff --git a/modern-uri.cabal b/modern-uri.cabal
--- a/modern-uri.cabal
+++ b/modern-uri.cabal
@@ -1,11 +1,11 @@
-cabal-version:   1.18
+cabal-version:   2.4
 name:            modern-uri
-version:         0.3.4.2
-license:         BSD3
+version:         0.3.4.3
+license:         BSD-3-Clause
 license-file:    LICENSE.md
 maintainer:      Mark Karpov <markkarpov92@gmail.com>
 author:          Mark Karpov <markkarpov92@gmail.com>
-tested-with:     ghc ==8.8.4 ghc ==8.10.5 ghc ==9.0.1
+tested-with:     ghc ==8.10.7 ghc ==9.0.1 ghc ==9.2.1
 homepage:        https://github.com/mrkkrp/modern-uri
 bug-reports:     https://github.com/mrkkrp/modern-uri/issues
 synopsis:        Modern library for working with URIs
@@ -52,7 +52,7 @@
         profunctors >=5.2.1 && <6.0,
         reflection >=2.0 && <3.0,
         tagged >=0.8 && <0.9,
-        template-haskell >=2.10 && <2.18,
+        template-haskell >=2.10 && <2.19,
         text >=0.2 && <1.3
 
     if flag(dev)
@@ -67,15 +67,15 @@
             -Wnoncanonical-monad-instances
 
 test-suite tests
-    type:             exitcode-stdio-1.0
-    main-is:          Spec.hs
-    build-tools:      hspec-discover >=2.0 && <3.0
-    hs-source-dirs:   tests
+    type:               exitcode-stdio-1.0
+    main-is:            Spec.hs
+    build-tool-depends: hspec-discover:hspec-discover >=2.0 && <3.0
+    hs-source-dirs:     tests
     other-modules:
         Text.QQSpec
         Text.URISpec
 
-    default-language: Haskell2010
+    default-language:   Haskell2010
     build-depends:
         QuickCheck >=2.4 && <3.0,
         base >=4.13 && <5.0,
diff --git a/tests/Text/URISpec.hs b/tests/Text/URISpec.hs
--- a/tests/Text/URISpec.hs
+++ b/tests/Text/URISpec.hs
@@ -119,6 +119,7 @@
       URI.mkHost "LOCALHOST" `shouldRText` "localhost"
       URI.mkHost "github.com" `shouldRText` "github.com"
       URI.mkHost "foo.example.com" `shouldRText` "foo.example.com"
+      URI.mkHost "104.155.144.4.sslip.io" `shouldRText` "104.155.144.4.sslip.io"
       URI.mkHost "юникод.рф" `shouldRText` "юникод.рф"
       URI.mkHost "" `shouldRText` ""
     it "rejects invalid hosts" $ do
@@ -204,7 +205,6 @@
                 etok '?',
                 etok '[',
                 elabel "ASCII alpha-numeric character",
-                elabel "integer",
                 elabel "username",
                 elabel "path piece",
                 eeof
@@ -224,6 +224,24 @@
                 eeof
               ]
           )
+    it "parses URIs with sub-domains that look like IPv4" $ do
+      scheme <- URI.mkScheme "https"
+      host <- URI.mkHost "104.155.144.4.sslip.io"
+      let s = "https://104.155.144.4.sslip.io:443/"
+      parse urip "" s
+        `shouldParse` URI
+          { uriScheme = Just scheme,
+            uriAuthority =
+              Right
+                URI.Authority
+                  { URI.authUserInfo = Nothing,
+                    URI.authHost = host,
+                    URI.authPort = Just 443
+                  },
+            uriPath = Nothing,
+            uriQuery = [],
+            uriFragment = Nothing
+          }
     it "parses URIs with empty authority" $ do
       scheme <- URI.mkScheme "file"
       ppetc <- URI.mkPathPiece "etc"
@@ -359,7 +377,7 @@
 
 -- | Polymorphic textual rendering of the 'URI' generated by 'mkTestURI'.
 testURI :: IsString a => a
-testURI = "https://mark%3a%40:secret:%40@github.com:443/mrkkrp/modern-uri+%3a@?foo:@=bar+:@#fragment:@"
+testURI = "https://mark%3a%40:secret:%40@github.com:443/mrkkrp/modern-uri%2b%3a%40?foo:@=bar+:@#fragment:@"
 
 -- | A utility wrapper around 'URI.parser'.
 urip :: Parsec Void Text URI
