diff --git a/go.mod b/go.mod
index 3dd738719c38170aee1621993d3bd5d191b5d075..abbeb91688b3bfb0488eebacf82d7c7e0f94a2dc 100644
--- a/go.mod
+++ b/go.mod
@@ -16,6 +16,7 @@ require (
 	github.com/dutchcoders/go-virustotal v0.0.0-20140923143438-24cc8e6fa329
 	github.com/dutchcoders/transfer.sh-web v0.0.0-20221119114740-ca3a2621d2a6
 	github.com/elazarl/go-bindata-assetfs v1.0.1
+	github.com/emicklei/go-restful v2.16.0+incompatible
 	github.com/fatih/color v1.14.1
 	github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f
 	github.com/gorilla/handlers v1.5.1
@@ -29,6 +30,7 @@ require (
 	golang.org/x/crypto v0.17.0
 	golang.org/x/net v0.17.0
 	golang.org/x/oauth2 v0.7.0
+	golang.org/x/text v0.14.0
 	google.golang.org/api v0.114.0
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
 	storj.io/common v0.0.0-20230301105927-7f966760c100
@@ -86,7 +88,6 @@ require (
 	go.opencensus.io v0.24.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
 	golang.org/x/sys v0.15.0 // indirect
-	golang.org/x/text v0.14.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	google.golang.org/grpc v1.56.3 // indirect
diff --git a/go.sum b/go.sum
index bfcacf8fe403d3ef4d7d5edac7c0b723dcd7c698..401fe988ad83742f3a2081bde846cc51f86d4808 100644
--- a/go.sum
+++ b/go.sum
@@ -85,6 +85,8 @@ github.com/dutchcoders/transfer.sh-web v0.0.0-20221119114740-ca3a2621d2a6 h1:7uT
 github.com/dutchcoders/transfer.sh-web v0.0.0-20221119114740-ca3a2621d2a6/go.mod h1:F6Q37CxDh2MHr5KXkcZmNB3tdkK7v+bgE+OpBY+9ilI=
 github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
 github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/emicklei/go-restful v2.16.0+incompatible h1:rgqiKNjTnFQA6kkhFe16D8epTksy9HQ1MyrbDXSdYhM=
+github.com/emicklei/go-restful v2.16.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
diff --git a/server/handlers.go b/server/handlers.go
index 265aab42022a4487a98fc5cec48db35bcc307574..4f1b16acac130c197f3cb95627c7f8ea50785878 100644
--- a/server/handlers.go
+++ b/server/handlers.go
@@ -51,6 +51,7 @@ import (
 	"sync"
 	textTemplate "text/template"
 	"time"
+	"unicode"
 
 	"github.com/ProtonMail/go-crypto/openpgp"
 	"github.com/ProtonMail/go-crypto/openpgp/armor"
@@ -66,6 +67,9 @@ import (
 	blackfriday "github.com/russross/blackfriday/v2"
 	qrcode "github.com/skip2/go-qrcode"
 	"golang.org/x/net/idna"
+	"golang.org/x/text/runes"
+	"golang.org/x/text/transform"
+	"golang.org/x/text/unicode/norm"
 )
 
 const getPathPart = "get"
@@ -418,7 +422,24 @@ func (s *Server) notFoundHandler(w http.ResponseWriter, _ *http.Request) {
 }
 
 func sanitize(fileName string) string {
-	return path.Base(fileName)
+	t := transform.Chain(
+		norm.NFD,
+		runes.Remove(runes.In(unicode.Cc)),
+		runes.Remove(runes.In(unicode.Cf)),
+		runes.Remove(runes.In(unicode.Co)),
+		runes.Remove(runes.In(unicode.Cs)),
+		runes.Remove(runes.In(unicode.Other)),
+		runes.Remove(runes.In(unicode.Zl)),
+		runes.Remove(runes.In(unicode.Zp)),
+		norm.NFC)
+	newName, _, err := transform.String(t, fileName)
+	if err != nil {
+		return path.Base(fileName)
+	}
+	if len(newName) == 0 {
+		newName = "_"
+	}
+	return path.Base(newName)
 }
 
 func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {