diff --git a/cmd/cmd.go b/cmd/cmd.go
index efce7d0d96a7dfcd8b3b56d65b49daad06957c18..f694c52cdc0232f662195abb1fae32cc73c082fa 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -1,6 +1,7 @@
 package cmd
 
 import (
+	"errors"
 	"fmt"
 	"log"
 	"os"
@@ -10,7 +11,7 @@ import (
 
 	"github.com/dutchcoders/transfer.sh/server"
 	"github.com/fatih/color"
-	"github.com/urfave/cli"
+	"github.com/urfave/cli/v2"
 	"google.golang.org/api/googleapi"
 )
 
@@ -36,275 +37,275 @@ VERSION:
 	`{{ "\n"}}`
 
 var globalFlags = []cli.Flag{
-	cli.StringFlag{
-		Name:   "listener",
-		Usage:  "127.0.0.1:8080",
-		Value:  "127.0.0.1:8080",
-		EnvVar: "LISTENER",
+	&cli.StringFlag{
+		Name:    "listener",
+		Usage:   "127.0.0.1:8080",
+		Value:   "127.0.0.1:8080",
+		EnvVars: []string{"LISTENER"},
 	},
 	// redirect to https?
 	// hostnames
-	cli.StringFlag{
-		Name:   "profile-listener",
-		Usage:  "127.0.0.1:6060",
-		Value:  "",
-		EnvVar: "PROFILE_LISTENER",
-	},
-	cli.BoolFlag{
-		Name:   "force-https",
-		Usage:  "",
-		EnvVar: "FORCE_HTTPS",
-	},
-	cli.StringFlag{
-		Name:   "tls-listener",
-		Usage:  "127.0.0.1:8443",
-		Value:  "",
-		EnvVar: "TLS_LISTENER",
-	},
-	cli.BoolFlag{
-		Name:   "tls-listener-only",
-		Usage:  "",
-		EnvVar: "TLS_LISTENER_ONLY",
-	},
-	cli.StringFlag{
-		Name:   "tls-cert-file",
-		Value:  "",
-		EnvVar: "TLS_CERT_FILE",
-	},
-	cli.StringFlag{
-		Name:   "tls-private-key",
-		Value:  "",
-		EnvVar: "TLS_PRIVATE_KEY",
-	},
-	cli.StringFlag{
-		Name:   "temp-path",
-		Usage:  "path to temp files",
-		Value:  os.TempDir(),
-		EnvVar: "TEMP_PATH",
-	},
-	cli.StringFlag{
-		Name:   "web-path",
-		Usage:  "path to static web files",
-		Value:  "",
-		EnvVar: "WEB_PATH",
-	},
-	cli.StringFlag{
-		Name:   "proxy-path",
-		Usage:  "path prefix when service is run behind a proxy",
-		Value:  "",
-		EnvVar: "PROXY_PATH",
-	},
-	cli.StringFlag{
-		Name:   "proxy-port",
-		Usage:  "port of the proxy when the service is run behind a proxy",
-		Value:  "",
-		EnvVar: "PROXY_PORT",
-	},
-	cli.StringFlag{
-		Name:   "email-contact",
-		Usage:  "email address to link in Contact Us (front end)",
-		Value:  "",
-		EnvVar: "EMAIL_CONTACT",
-	},
-	cli.StringFlag{
-		Name:   "ga-key",
-		Usage:  "key for google analytics (front end)",
-		Value:  "",
-		EnvVar: "GA_KEY",
-	},
-	cli.StringFlag{
-		Name:   "uservoice-key",
-		Usage:  "key for user voice (front end)",
-		Value:  "",
-		EnvVar: "USERVOICE_KEY",
-	},
-	cli.StringFlag{
-		Name:   "provider",
-		Usage:  "s3|gdrive|local",
-		Value:  "",
-		EnvVar: "PROVIDER",
-	},
-	cli.StringFlag{
-		Name:   "s3-endpoint",
-		Usage:  "",
-		Value:  "",
-		EnvVar: "S3_ENDPOINT",
-	},
-	cli.StringFlag{
-		Name:   "s3-region",
-		Usage:  "",
-		Value:  "eu-west-1",
-		EnvVar: "S3_REGION",
-	},
-	cli.StringFlag{
-		Name:   "aws-access-key",
-		Usage:  "",
-		Value:  "",
-		EnvVar: "AWS_ACCESS_KEY",
-	},
-	cli.StringFlag{
-		Name:   "aws-secret-key",
-		Usage:  "",
-		Value:  "",
-		EnvVar: "AWS_SECRET_KEY",
-	},
-	cli.StringFlag{
-		Name:   "bucket",
-		Usage:  "",
-		Value:  "",
-		EnvVar: "BUCKET",
-	},
-	cli.BoolFlag{
-		Name:   "s3-no-multipart",
-		Usage:  "Disables S3 Multipart Puts",
-		EnvVar: "S3_NO_MULTIPART",
-	},
-	cli.BoolFlag{
-		Name:   "s3-path-style",
-		Usage:  "Forces path style URLs, required for Minio.",
-		EnvVar: "S3_PATH_STYLE",
-	},
-	cli.StringFlag{
-		Name:   "gdrive-client-json-filepath",
-		Usage:  "",
-		Value:  "",
-		EnvVar: "GDRIVE_CLIENT_JSON_FILEPATH",
-	},
-	cli.StringFlag{
-		Name:   "gdrive-local-config-path",
-		Usage:  "",
-		Value:  "",
-		EnvVar: "GDRIVE_LOCAL_CONFIG_PATH",
-	},
-	cli.IntFlag{
-		Name:   "gdrive-chunk-size",
-		Usage:  "",
-		Value:  googleapi.DefaultUploadChunkSize / 1024 / 1024,
-		EnvVar: "GDRIVE_CHUNK_SIZE",
-	},
-	cli.StringFlag{
-		Name:   "storj-access",
-		Usage:  "Access for the project",
-		Value:  "",
-		EnvVar: "STORJ_ACCESS",
-	},
-	cli.StringFlag{
-		Name:   "storj-bucket",
-		Usage:  "Bucket to use within the project",
-		Value:  "",
-		EnvVar: "STORJ_BUCKET",
-	},
-	cli.IntFlag{
-		Name:   "rate-limit",
-		Usage:  "requests per minute",
-		Value:  0,
-		EnvVar: "RATE_LIMIT",
-	},
-	cli.IntFlag{
-		Name:   "purge-days",
-		Usage:  "number of days after uploads are purged automatically",
-		Value:  0,
-		EnvVar: "PURGE_DAYS",
-	},
-	cli.IntFlag{
-		Name:   "purge-interval",
-		Usage:  "interval in hours to run the automatic purge for",
-		Value:  0,
-		EnvVar: "PURGE_INTERVAL",
-	},
-	cli.Int64Flag{
-		Name:   "max-upload-size",
-		Usage:  "max limit for upload, in kilobytes",
-		Value:  0,
-		EnvVar: "MAX_UPLOAD_SIZE",
-	},
-	cli.StringFlag{
-		Name:   "lets-encrypt-hosts",
-		Usage:  "host1, host2",
-		Value:  "",
-		EnvVar: "HOSTS",
-	},
-	cli.StringFlag{
-		Name:   "log",
-		Usage:  "/var/log/transfersh.log",
-		Value:  "",
-		EnvVar: "LOG",
-	},
-	cli.StringFlag{
-		Name:   "basedir",
-		Usage:  "path to storage",
-		Value:  "",
-		EnvVar: "BASEDIR",
-	},
-	cli.StringFlag{
-		Name:   "clamav-host",
-		Usage:  "clamav-host",
-		Value:  "",
-		EnvVar: "CLAMAV_HOST",
-	},
-	cli.BoolFlag{
-		Name:   "perform-clamav-prescan",
-		Usage:  "perform-clamav-prescan",
-		EnvVar: "PERFORM_CLAMAV_PRESCAN",
-	},
-	cli.StringFlag{
-		Name:   "virustotal-key",
-		Usage:  "virustotal-key",
-		Value:  "",
-		EnvVar: "VIRUSTOTAL_KEY",
-	},
-	cli.BoolFlag{
-		Name:   "profiler",
-		Usage:  "enable profiling",
-		EnvVar: "PROFILER",
-	},
-	cli.StringFlag{
-		Name:   "http-auth-user",
-		Usage:  "user for http basic auth",
-		Value:  "",
-		EnvVar: "HTTP_AUTH_USER",
-	},
-	cli.StringFlag{
-		Name:   "http-auth-pass",
-		Usage:  "pass for http basic auth",
-		Value:  "",
-		EnvVar: "HTTP_AUTH_PASS",
-	},
-	cli.StringFlag{
-		Name:   "http-auth-htpasswd",
-		Usage:  "htpasswd file http basic auth",
-		Value:  "",
-		EnvVar: "HTTP_AUTH_HTPASSWD",
-	},
-	cli.StringFlag{
-		Name:   "http-auth-ip-whitelist",
-		Usage:  "comma separated list of ips allowed to upload without being challenged an http auth",
-		Value:  "",
-		EnvVar: "HTTP_AUTH_IP_WHITELIST",
-	},
-	cli.StringFlag{
-		Name:   "ip-whitelist",
-		Usage:  "comma separated list of ips allowed to connect to the service",
-		Value:  "",
-		EnvVar: "IP_WHITELIST",
-	},
-	cli.StringFlag{
-		Name:   "ip-blacklist",
-		Usage:  "comma separated list of ips not allowed to connect to the service",
-		Value:  "",
-		EnvVar: "IP_BLACKLIST",
-	},
-	cli.StringFlag{
-		Name:   "cors-domains",
-		Usage:  "comma separated list of domains allowed for CORS requests",
-		Value:  "",
-		EnvVar: "CORS_DOMAINS",
-	},
-	cli.IntFlag{
-		Name:   "random-token-length",
-		Usage:  "",
-		Value:  10,
-		EnvVar: "RANDOM_TOKEN_LENGTH",
+	&cli.StringFlag{
+		Name:    "profile-listener",
+		Usage:   "127.0.0.1:6060",
+		Value:   "",
+		EnvVars: []string{"PROFILE_LISTENER"},
+	},
+	&cli.BoolFlag{
+		Name:    "force-https",
+		Usage:   "",
+		EnvVars: []string{"FORCE_HTTPS"},
+	},
+	&cli.StringFlag{
+		Name:    "tls-listener",
+		Usage:   "127.0.0.1:8443",
+		Value:   "",
+		EnvVars: []string{"TLS_LISTENER"},
+	},
+	&cli.BoolFlag{
+		Name:    "tls-listener-only",
+		Usage:   "",
+		EnvVars: []string{"TLS_LISTENER_ONLY"},
+	},
+	&cli.StringFlag{
+		Name:    "tls-cert-file",
+		Value:   "",
+		EnvVars: []string{"TLS_CERT_FILE"},
+	},
+	&cli.StringFlag{
+		Name:    "tls-private-key",
+		Value:   "",
+		EnvVars: []string{"TLS_PRIVATE_KEY"},
+	},
+	&cli.StringFlag{
+		Name:    "temp-path",
+		Usage:   "path to temp files",
+		Value:   os.TempDir(),
+		EnvVars: []string{"TEMP_PATH"},
+	},
+	&cli.StringFlag{
+		Name:    "web-path",
+		Usage:   "path to static web files",
+		Value:   "",
+		EnvVars: []string{"WEB_PATH"},
+	},
+	&cli.StringFlag{
+		Name:    "proxy-path",
+		Usage:   "path prefix when service is run behind a proxy",
+		Value:   "",
+		EnvVars: []string{"PROXY_PATH"},
+	},
+	&cli.StringFlag{
+		Name:    "proxy-port",
+		Usage:   "port of the proxy when the service is run behind a proxy",
+		Value:   "",
+		EnvVars: []string{"PROXY_PORT"},
+	},
+	&cli.StringFlag{
+		Name:    "email-contact",
+		Usage:   "email address to link in Contact Us (front end)",
+		Value:   "",
+		EnvVars: []string{"EMAIL_CONTACT"},
+	},
+	&cli.StringFlag{
+		Name:    "ga-key",
+		Usage:   "key for google analytics (front end)",
+		Value:   "",
+		EnvVars: []string{"GA_KEY"},
+	},
+	&cli.StringFlag{
+		Name:    "uservoice-key",
+		Usage:   "key for user voice (front end)",
+		Value:   "",
+		EnvVars: []string{"USERVOICE_KEY"},
+	},
+	&cli.StringFlag{
+		Name:    "provider",
+		Usage:   "s3|gdrive|local",
+		Value:   "",
+		EnvVars: []string{"PROVIDER"},
+	},
+	&cli.StringFlag{
+		Name:    "s3-endpoint",
+		Usage:   "",
+		Value:   "",
+		EnvVars: []string{"S3_ENDPOINT"},
+	},
+	&cli.StringFlag{
+		Name:    "s3-region",
+		Usage:   "",
+		Value:   "eu-west-1",
+		EnvVars: []string{"S3_REGION"},
+	},
+	&cli.StringFlag{
+		Name:    "aws-access-key",
+		Usage:   "",
+		Value:   "",
+		EnvVars: []string{"AWS_ACCESS_KEY"},
+	},
+	&cli.StringFlag{
+		Name:    "aws-secret-key",
+		Usage:   "",
+		Value:   "",
+		EnvVars: []string{"AWS_SECRET_KEY"},
+	},
+	&cli.StringFlag{
+		Name:    "bucket",
+		Usage:   "",
+		Value:   "",
+		EnvVars: []string{"BUCKET"},
+	},
+	&cli.BoolFlag{
+		Name:    "s3-no-multipart",
+		Usage:   "Disables S3 Multipart Puts",
+		EnvVars: []string{"S3_NO_MULTIPART"},
+	},
+	&cli.BoolFlag{
+		Name:    "s3-path-style",
+		Usage:   "Forces path style URLs, required for Minio.",
+		EnvVars: []string{"S3_PATH_STYLE"},
+	},
+	&cli.StringFlag{
+		Name:    "gdrive-client-json-filepath",
+		Usage:   "",
+		Value:   "",
+		EnvVars: []string{"GDRIVE_CLIENT_JSON_FILEPATH"},
+	},
+	&cli.StringFlag{
+		Name:    "gdrive-local-config-path",
+		Usage:   "",
+		Value:   "",
+		EnvVars: []string{"GDRIVE_LOCAL_CONFIG_PATH"},
+	},
+	&cli.IntFlag{
+		Name:    "gdrive-chunk-size",
+		Usage:   "",
+		Value:   googleapi.DefaultUploadChunkSize / 1024 / 1024,
+		EnvVars: []string{"GDRIVE_CHUNK_SIZE"},
+	},
+	&cli.StringFlag{
+		Name:    "storj-access",
+		Usage:   "Access for the project",
+		Value:   "",
+		EnvVars: []string{"STORJ_ACCESS"},
+	},
+	&cli.StringFlag{
+		Name:    "storj-bucket",
+		Usage:   "Bucket to use within the project",
+		Value:   "",
+		EnvVars: []string{"STORJ_BUCKET"},
+	},
+	&cli.IntFlag{
+		Name:    "rate-limit",
+		Usage:   "requests per minute",
+		Value:   0,
+		EnvVars: []string{"RATE_LIMIT"},
+	},
+	&cli.IntFlag{
+		Name:    "purge-days",
+		Usage:   "number of days after uploads are purged automatically",
+		Value:   0,
+		EnvVars: []string{"PURGE_DAYS"},
+	},
+	&cli.IntFlag{
+		Name:    "purge-interval",
+		Usage:   "interval in hours to run the automatic purge for",
+		Value:   0,
+		EnvVars: []string{"PURGE_INTERVAL"},
+	},
+	&cli.Int64Flag{
+		Name:    "max-upload-size",
+		Usage:   "max limit for upload, in kilobytes",
+		Value:   0,
+		EnvVars: []string{"MAX_UPLOAD_SIZE"},
+	},
+	&cli.StringFlag{
+		Name:    "lets-encrypt-hosts",
+		Usage:   "host1, host2",
+		Value:   "",
+		EnvVars: []string{"HOSTS"},
+	},
+	&cli.StringFlag{
+		Name:    "log",
+		Usage:   "/var/log/transfersh.log",
+		Value:   "",
+		EnvVars: []string{"LOG"},
+	},
+	&cli.StringFlag{
+		Name:    "basedir",
+		Usage:   "path to storage",
+		Value:   "",
+		EnvVars: []string{"BASEDIR"},
+	},
+	&cli.StringFlag{
+		Name:    "clamav-host",
+		Usage:   "clamav-host",
+		Value:   "",
+		EnvVars: []string{"CLAMAV_HOST"},
+	},
+	&cli.BoolFlag{
+		Name:    "perform-clamav-prescan",
+		Usage:   "perform-clamav-prescan",
+		EnvVars: []string{"PERFORM_CLAMAV_PRESCAN"},
+	},
+	&cli.StringFlag{
+		Name:    "virustotal-key",
+		Usage:   "virustotal-key",
+		Value:   "",
+		EnvVars: []string{"VIRUSTOTAL_KEY"},
+	},
+	&cli.BoolFlag{
+		Name:    "profiler",
+		Usage:   "enable profiling",
+		EnvVars: []string{"PROFILER"},
+	},
+	&cli.StringFlag{
+		Name:    "http-auth-user",
+		Usage:   "user for http basic auth",
+		Value:   "",
+		EnvVars: []string{"HTTP_AUTH_USER"},
+	},
+	&cli.StringFlag{
+		Name:    "http-auth-pass",
+		Usage:   "pass for http basic auth",
+		Value:   "",
+		EnvVars: []string{"HTTP_AUTH_PASS"},
+	},
+	&cli.StringFlag{
+		Name:    "http-auth-htpasswd",
+		Usage:   "htpasswd file http basic auth",
+		Value:   "",
+		EnvVars: []string{"HTTP_AUTH_HTPASSWD"},
+	},
+	&cli.StringFlag{
+		Name:    "http-auth-ip-whitelist",
+		Usage:   "comma separated list of ips allowed to upload without being challenged an http auth",
+		Value:   "",
+		EnvVars: []string{"HTTP_AUTH_IP_WHITELIST"},
+	},
+	&cli.StringFlag{
+		Name:    "ip-whitelist",
+		Usage:   "comma separated list of ips allowed to connect to the service",
+		Value:   "",
+		EnvVars: []string{"IP_WHITELIST"},
+	},
+	&cli.StringFlag{
+		Name:    "ip-blacklist",
+		Usage:   "comma separated list of ips not allowed to connect to the service",
+		Value:   "",
+		EnvVars: []string{"IP_BLACKLIST"},
+	},
+	&cli.StringFlag{
+		Name:    "cors-domains",
+		Usage:   "comma separated list of domains allowed for CORS requests",
+		Value:   "",
+		EnvVars: []string{"CORS_DOMAINS"},
+	},
+	&cli.IntFlag{
+		Name:    "random-token-length",
+		Usage:   "",
+		Value:   10,
+		EnvVars: []string{"RANDOM_TOKEN_LENGTH"},
 	},
 }
 
@@ -313,8 +314,9 @@ type Cmd struct {
 	*cli.App
 }
 
-func versionCommand(_ *cli.Context) {
+func versionCommand(_ *cli.Context) error {
 	fmt.Println(color.YellowString("transfer.sh %s: Easy file sharing from the command line", Version))
+	return nil
 }
 
 // New is the factory for transfer.sh
@@ -323,13 +325,13 @@ func New() *Cmd {
 
 	app := cli.NewApp()
 	app.Name = "transfer.sh"
-	app.Author = ""
+	app.Authors = []*cli.Author{}
 	app.Usage = "transfer.sh"
 	app.Description = `Easy file sharing from the command line`
 	app.Version = Version
 	app.Flags = globalFlags
 	app.CustomAppHelpTemplate = helpTemplate
-	app.Commands = []cli.Command{
+	app.Commands = []*cli.Command{
 		{
 			Name:   "version",
 			Action: versionCommand,
@@ -340,7 +342,7 @@ func New() *Cmd {
 		return nil
 	}
 
-	app.Action = func(c *cli.Context) {
+	app.Action = func(c *cli.Context) error {
 		var options []server.OptionFn
 		if v := c.String("listener"); v != "" {
 			options = append(options, server.Listener(v))
@@ -409,7 +411,7 @@ func New() *Cmd {
 
 		if v := c.Bool("perform-clamav-prescan"); v {
 			if c.String("clamav-host") == "" {
-				panic("clamav-host not set")
+				return errors.New("clamav-host not set")
 			}
 
 			options = append(options, server.PerformClamavPrescan(v))
@@ -483,13 +485,13 @@ func New() *Cmd {
 		switch provider := c.String("provider"); provider {
 		case "s3":
 			if accessKey := c.String("aws-access-key"); accessKey == "" {
-				panic("access-key not set.")
+				return errors.New("access-key not set.")
 			} else if secretKey := c.String("aws-secret-key"); secretKey == "" {
-				panic("secret-key not set.")
+				return errors.New("secret-key not set.")
 			} else if bucket := c.String("bucket"); bucket == "" {
-				panic("bucket not set.")
+				return errors.New("bucket not set.")
 			} else if store, err := storage.NewS3Storage(accessKey, secretKey, bucket, purgeDays, c.String("s3-region"), c.String("s3-endpoint"), c.Bool("s3-no-multipart"), c.Bool("s3-path-style"), logger); err != nil {
-				panic(err)
+				return err
 			} else {
 				options = append(options, server.UseStorage(store))
 			}
@@ -497,36 +499,36 @@ func New() *Cmd {
 			chunkSize := c.Int("gdrive-chunk-size") * 1024 * 1024
 
 			if clientJSONFilepath := c.String("gdrive-client-json-filepath"); clientJSONFilepath == "" {
-				panic("gdrive-client-json-filepath not set.")
+				return errors.New("gdrive-client-json-filepath not set.")
 			} else if localConfigPath := c.String("gdrive-local-config-path"); localConfigPath == "" {
-				panic("gdrive-local-config-path not set.")
+				return errors.New("gdrive-local-config-path not set.")
 			} else if basedir := c.String("basedir"); basedir == "" {
-				panic("basedir not set.")
-			} else if store, err := storage.NewGDriveStorage(clientJSONFilepath, localConfigPath, basedir, chunkSize, logger); err != nil {
-				panic(err)
+				return errors.New("basedir not set.")
+			} else if store, err := storage.NewGDriveStorage(c.Context, clientJSONFilepath, localConfigPath, basedir, chunkSize, logger); err != nil {
+				return err
 			} else {
 				options = append(options, server.UseStorage(store))
 			}
 		case "storj":
 			if access := c.String("storj-access"); access == "" {
-				panic("storj-access not set.")
+				return errors.New("storj-access not set.")
 			} else if bucket := c.String("storj-bucket"); bucket == "" {
-				panic("storj-bucket not set.")
-			} else if store, err := storage.NewStorjStorage(access, bucket, purgeDays, logger); err != nil {
-				panic(err)
+				return errors.New("storj-bucket not set.")
+			} else if store, err := storage.NewStorjStorage(c.Context, access, bucket, purgeDays, logger); err != nil {
+				return err
 			} else {
 				options = append(options, server.UseStorage(store))
 			}
 		case "local":
 			if v := c.String("basedir"); v == "" {
-				panic("basedir not set.")
+				return errors.New("basedir not set.")
 			} else if store, err := storage.NewLocalStorage(v, logger); err != nil {
-				panic(err)
+				return err
 			} else {
 				options = append(options, server.UseStorage(store))
 			}
 		default:
-			panic("Provider not set or invalid.")
+			return errors.New("Provider not set or invalid.")
 		}
 
 		srvr, err := server.New(
@@ -535,10 +537,11 @@ func New() *Cmd {
 
 		if err != nil {
 			logger.Println(color.RedString("Error starting server: %s", err.Error()))
-			return
+			return err
 		}
 
 		srvr.Run()
+		return nil
 	}
 
 	return &Cmd{
diff --git a/go.mod b/go.mod
index c31dd4421219d82354d862b5c6098a3916d37e0a..ca4cede426b4d52aed5efcd57d59ca93a69d9db7 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/tg123/go-htpasswd v1.2.1
 	github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
-	github.com/urfave/cli v1.22.12
+	github.com/urfave/cli/v2 v2.25.3
 	golang.org/x/crypto v0.6.0
 	golang.org/x/net v0.8.0
 	golang.org/x/oauth2 v0.5.0
@@ -62,6 +62,7 @@ require (
 	github.com/rogpeppe/go-internal v1.9.0 // indirect
 	github.com/spacemonkeygo/monkit/v3 v3.0.19 // indirect
 	github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 // indirect
+	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
 	github.com/zeebo/blake3 v0.2.3 // indirect
 	github.com/zeebo/errs v1.3.0 // indirect
 	go.opencensus.io v0.24.0 // indirect
@@ -72,6 +73,7 @@ require (
 	google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514 // indirect
 	google.golang.org/grpc v1.53.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
 	storj.io/drpc v0.0.33-0.20230204035225-c9649dee8f2a // indirect
 	storj.io/picobuf v0.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index d72fbe759c4358d721bd879d843d5aad54a5e3b9..feaab09cc58f405f4bb70acd231355729ec77396 100644
--- a/go.sum
+++ b/go.sum
@@ -7,7 +7,6 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
 cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw=
 github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo=
@@ -186,10 +185,12 @@ github.com/tg123/go-htpasswd v1.2.1 h1:i4wfsX1KvvkyoMiHZzjS0VzbAPWfxzI8INcZAKtut
 github.com/tg123/go-htpasswd v1.2.1/go.mod h1:erHp1B86KXdwQf1X5ZrLb7erXZnWueEQezb2dql4q58=
 github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
 github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
-github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8=
-github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
+github.com/urfave/cli/v2 v2.25.3 h1:VJkt6wvEBOoSjPFQvOkv6iWIrsJyCrKGtCtxXWwmGeY=
+github.com/urfave/cli/v2 v2.25.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
 github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 h1:zMsHhfK9+Wdl1F7sIKLyx3wrOFofpb3rWFbA4HgcK5k=
 github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3/go.mod h1:R0Gbuw7ElaGSLOZUSwBm/GgVwMd30jWxBDdAyMOeTuc=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
diff --git a/server/storage/gdrive.go b/server/storage/gdrive.go
index a761a6461203300426b901fec7956c6cdb462b0a..b59df27a4c5b38fbce6793f0d315bcc30286ae69 100644
--- a/server/storage/gdrive.go
+++ b/server/storage/gdrive.go
@@ -35,9 +35,7 @@ const gDriveTokenJSONFile = "token.json"
 const gDriveDirectoryMimeType = "application/vnd.google-apps.folder"
 
 // NewGDriveStorage is the factory for GDrive
-func NewGDriveStorage(clientJSONFilepath string, localConfigPath string, basedir string, chunkSize int, logger *log.Logger) (*GDrive, error) {
-
-	ctx := context.TODO()
+func NewGDriveStorage(ctx context.Context, clientJSONFilepath string, localConfigPath string, basedir string, chunkSize int, logger *log.Logger) (*GDrive, error) {
 
 	b, err := ioutil.ReadFile(clientJSONFilepath)
 	if err != nil {
diff --git a/server/storage/storj.go b/server/storage/storj.go
index 76f74a9a76c99ed673f969554d831d901ee6b4fa..fd695921c7c7c3da58bbb5322eb0e4fd36f423dd 100644
--- a/server/storage/storj.go
+++ b/server/storage/storj.go
@@ -22,13 +22,11 @@ type StorjStorage struct {
 }
 
 // NewStorjStorage is the factory for StorjStorage
-func NewStorjStorage(access, bucket string, purgeDays int, logger *log.Logger) (*StorjStorage, error) {
+func NewStorjStorage(ctx context.Context, access, bucket string, purgeDays int, logger *log.Logger) (*StorjStorage, error) {
 	var instance StorjStorage
 	var err error
 
-	pCtx := context.TODO()
-
-	ctx := fpath.WithTempData(pCtx, "", true)
+	ctx = fpath.WithTempData(ctx, "", true)
 
 	uplConf := &uplink.Config{
 		UserAgent: "transfer-sh",