diff --git a/go.mod b/go.mod
index 22f8f90..c906155 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,6 @@ go 1.24.0
 
 require (
 	github.com/cloudflare/circl v1.6.3
-	github.com/juju/ratelimit v1.0.2
 	github.com/pires/go-proxyproto v0.11.0
 	github.com/refraction-networking/utls v1.8.2
 	golang.org/x/crypto v0.48.0
@@ -14,5 +13,4 @@ require (
 require (
 	github.com/andybalholm/brotli v1.0.6 // indirect
 	github.com/klauspost/compress v1.17.4 // indirect
-	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 )
diff --git a/go.sum b/go.sum
index 72fddb4..d4f64e7 100644
--- a/go.sum
+++ b/go.sum
@@ -2,15 +2,8 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx
 github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
 github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
-github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
-github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
 github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
 github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
-github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/pires/go-proxyproto v0.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG68wXH4=
 github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
 github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=
@@ -19,5 +12,3 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
 golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
 golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
 golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/tls.go b/tls.go
index 4c8ef86..e85afd7 100644
--- a/tls.go
+++ b/tls.go
@@ -50,7 +50,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/juju/ratelimit"
 	"github.com/pires/go-proxyproto"
 	"golang.org/x/crypto/curve25519"
 	"golang.org/x/crypto/hkdf"
@@ -101,10 +100,52 @@ func (c *MirrorConn) SetWriteDeadline(t time.Time) error {
 	return nil
 }
 
+// tokenBucket is a license-clean replacement for the LGPL-3.0
+// github.com/juju/ratelimit dependency. It implements exactly the
+// NewBucketWithRate/Wait(count) semantics the fallback shaper below uses:
+// tokens refill continuously at rate per second up to capacity, Wait takes
+// count tokens immediately (going into debt if needed) and sleeps until the
+// debt would be repaid.
+type tokenBucket struct {
+	mu       sync.Mutex
+	rate     float64
+	capacity int64
+	tokens   float64
+	last     time.Time
+}
+
+func newTokenBucketWithRate(rate float64, capacity int64) *tokenBucket {
+	return &tokenBucket{
+		rate:     rate,
+		capacity: capacity,
+		tokens:   float64(capacity),
+		last:     time.Now(),
+	}
+}
+
+func (b *tokenBucket) Wait(count int64) {
+	b.mu.Lock()
+	now := time.Now()
+	b.tokens += now.Sub(b.last).Seconds() * b.rate
+	if b.tokens > float64(b.capacity) {
+		b.tokens = float64(b.capacity)
+	}
+	b.last = now
+	b.tokens -= float64(count)
+	var wait time.Duration
+	if b.tokens < 0 && b.rate > 0 {
+		wait = time.Duration(-b.tokens / b.rate * float64(time.Second))
+	}
+	b.mu.Unlock()
+	if wait > 0 {
+		time.Sleep(wait)
+	}
+}
+
 type RatelimitedConn struct {
 	net.Conn
 	After  int64
-	Bucket *ratelimit.Bucket
+	Bucket *tokenBucket
 }
 
 func (c *RatelimitedConn) Read(b []byte) (int, error) {
@@ -132,7 +173,7 @@ func NewRatelimitedConn(conn net.Conn, limit *LimitFallback) net.Conn {
 	return &RatelimitedConn{
 		Conn:   conn,
 		After:  int64(limit.AfterBytes),
-		Bucket: ratelimit.NewBucketWithRate(float64(limit.BytesPerSec), int64(burstBytesPerSec)),
+		Bucket: newTokenBucketWithRate(float64(limit.BytesPerSec), int64(burstBytesPerSec)),
 	}
 }
 
