diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go
index 144dcc80cd9810ffda8dc83f58b1d16d43b6e164..1c8da43aefeae301d63620b26f84d1fed90d1044 100644
--- a/cmd/swarm/main.go
+++ b/cmd/swarm/main.go
@@ -108,6 +108,10 @@ var (
 		Name:  "manifest",
 		Usage: "Automatic manifest upload",
 	}
+	SwarmUploadDefaultPath = cli.StringFlag{
+		Name:  "defaultpath",
+		Usage: "path to file served for empty url path (none)",
+	}
 )
 
 func init() {
@@ -179,6 +183,7 @@ Prints the swarm hash of file or directory.
 		SwarmApiFlag,
 		SwarmRecursiveUploadFlag,
 		SwarmWantManifestFlag,
+		SwarmUploadDefaultPath,
 	}
 	app.Flags = append(app.Flags, debug.Flags...)
 	app.Before = func(ctx *cli.Context) error {
diff --git a/cmd/swarm/upload.go b/cmd/swarm/upload.go
index 5393d4ef6ab4e8473848d909eb94441254585755..d048bbc4019fdec32db159cd1fe2fdb99ddf1969 100644
--- a/cmd/swarm/upload.go
+++ b/cmd/swarm/upload.go
@@ -27,6 +27,8 @@ import (
 	"mime"
 	"net/http"
 	"os"
+	"os/user"
+	"path"
 	"path/filepath"
 	"strings"
 
@@ -39,6 +41,7 @@ func upload(ctx *cli.Context) {
 		bzzapi       = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
 		recursive    = ctx.GlobalBool(SwarmRecursiveUploadFlag.Name)
 		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
+		defaultPath  = ctx.GlobalString(SwarmUploadDefaultPath.Name)
 	)
 	if len(args) != 1 {
 		log.Fatal("need filename as the first and only argument")
@@ -48,8 +51,9 @@ func upload(ctx *cli.Context) {
 		file   = args[0]
 		client = &client{api: bzzapi}
 		mroot  manifest
+		entry  manifestEntry
 	)
-	fi, err := os.Stat(file)
+	fi, err := os.Stat(expandPath(file))
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -57,28 +61,49 @@ func upload(ctx *cli.Context) {
 		if !recursive {
 			log.Fatal("argument is a directory and recursive upload is disabled")
 		}
-		mroot, err = client.uploadDirectory(file)
+		mroot, err = client.uploadDirectory(file, defaultPath)
 	} else {
-		mroot, err = client.uploadFile(file, fi)
-		if wantManifest {
-			// Wrap the raw file entry in a proper manifest so both hashes get printed.
-			mroot = manifest{Entries: []manifest{mroot}}
-		}
+		entry, err = client.uploadFile(file, fi)
+		mroot = manifest{[]manifestEntry{entry}}
 	}
 	if err != nil {
 		log.Fatalln("upload failed:", err)
 	}
-	if wantManifest {
-		hash, err := client.uploadManifest(mroot)
-		if err != nil {
-			log.Fatalln("manifest upload failed:", err)
+	if !wantManifest {
+		// Print the manifest. This is the only output to stdout.
+		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
+		fmt.Println(string(mrootJSON))
+		return
+	}
+	hash, err := client.uploadManifest(mroot)
+	if err != nil {
+		log.Fatalln("manifest upload failed:", err)
+	}
+	fmt.Println(hash)
+}
+
+// Expands a file path
+// 1. replace tilde with users home dir
+// 2. expands embedded environment variables
+// 3. cleans the path, e.g. /a/b/../c -> /a/c
+// Note, it has limitations, e.g. ~someuser/tmp will not be expanded
+func expandPath(p string) string {
+	if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
+		if home := homeDir(); home != "" {
+			p = home + p[1:]
 		}
-		mroot.Hash = hash
 	}
+	return path.Clean(os.ExpandEnv(p))
+}
 
-	// Print the manifest. This is the only output to stdout.
-	mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
-	fmt.Println(string(mrootJSON))
+func homeDir() string {
+	if home := os.Getenv("HOME"); home != "" {
+		return home
+	}
+	if usr, err := user.Current(); err == nil {
+		return usr.HomeDir
+	}
+	return ""
 }
 
 // client wraps interaction with the swarm HTTP gateway.
@@ -86,25 +111,41 @@ type client struct {
 	api string
 }
 
+// manifest is the JSON representation of a swarm manifest.
+type manifestEntry struct {
+	Hash        string `json:"hash,omitempty"`
+	ContentType string `json:"contentType,omitempty"`
+	Path        string `json:"path,omitempty"`
+}
+
 // manifest is the JSON representation of a swarm manifest.
 type manifest struct {
-	Hash        string     `json:"hash,omitempty"`
-	ContentType string     `json:"contentType,omitempty"`
-	Path        string     `json:"path,omitempty"`
-	Entries     []manifest `json:"entries,omitempty"`
+	Entries []manifestEntry `json:"entries,omitempty"`
 }
 
-func (c *client) uploadFile(file string, fi os.FileInfo) (manifest, error) {
+func (c *client) uploadFile(file string, fi os.FileInfo) (manifestEntry, error) {
 	hash, err := c.uploadFileContent(file, fi)
-	m := manifest{
+	m := manifestEntry{
 		Hash:        hash,
 		ContentType: mime.TypeByExtension(filepath.Ext(fi.Name())),
 	}
 	return m, err
 }
 
-func (c *client) uploadDirectory(dir string) (manifest, error) {
+func (c *client) uploadDirectory(dir string, defaultPath string) (manifest, error) {
 	dirm := manifest{}
+	if len(defaultPath) > 0 {
+		fi, err := os.Stat(defaultPath)
+		if err != nil {
+			log.Fatal(err)
+		}
+		entry, err := c.uploadFile(defaultPath, fi)
+		if err != nil {
+			log.Fatal(err)
+		}
+		entry.Path = ""
+		dirm.Entries = append(dirm.Entries, entry)
+	}
 	prefix := filepath.ToSlash(filepath.Clean(dir)) + "/"
 	err := filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
 		if err != nil || fi.IsDir() {