Small, simple file server
  • Go 98.7%
  • Dockerfile 0.7%
  • templ 0.6%
Find a file
2026-07-30 15:45:14 +02:00
.forgejo/workflows added workflow 2026-07-17 13:11:23 +02:00
cmd IDFK 2026-07-30 15:45:14 +02:00
internal IDFK 2026-07-30 15:45:14 +02:00
tmp IDFK 2026-07-30 15:45:14 +02:00
web IDFK 2026-07-30 15:45:14 +02:00
.air.toml IDFK 2026-07-30 15:45:14 +02:00
.gitignore initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
auth.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
config.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
config.toml initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
docker-compose.yml initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
Dockerfile initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
ftp.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
go.mod initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
go.sum initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
http.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
LICENSE add GPL-2.0-or-later license 2026-07-17 13:14:20 +02:00
main.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
README.md initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
sftp.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
smb.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
vfs.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00
webdav.go initial commit: multi-protocol file server 2026-07-13 11:12:18 +02:00

fileserver

A multi-protocol file server written in Go. Serves files over HTTP/HTTPS, WebDAV (same port), FTP, SFTP, and SMB — all sharing a single root directory, authentication, and permission system.

Quickstart

go build -o fileserver . && ./fileserver

Open http://localhost:8080 in your browser to see the landing page.

Web interface

Path Description
/ Landing page with server info
/browse/ File browser (directory listings)
/webdav/ WebDAV endpoint

Protocols

Protocol Default Port Access URL
HTTP 8080 http://localhost:8080/browse/
HTTPS 8080 https://localhost:8080/browse/
WebDAV 8080 http://localhost:8080/webdav
FTP 2121 ftp://localhost:2121
SFTP 2222 sftp://localhost:2222
SMB 445 smb://localhost/files

HTTP and WebDAV share the same port — landing page at /, file browser at /browse/, WebDAV at /webdav/.

Permission system

The server uses a virtual filesystem (VFS) layer that enforces ACL rules on every file operation. Every protocol handler (HTTP, WebDAV, FTP, SFTP, SMB) routes through the same VFS, so permissions apply uniformly.

How it works

  1. Users are defined in config with password and group memberships.

  2. Groups collect users for shared access.

  3. ACL rules assign an owner, a group, and a permission mode to directory paths.

  4. When a user accesses a file, the VFS checks the most specific ACL that matches the path's prefix.

  5. Permission is determined by the ACL's mode bits and the user's relationship to the ACL:

    • Owner — user matches the ACL's owner field → uses owner permission bits
    • Group member — user belongs to the ACL's group → uses group permission bits
    • Other — everyone else → uses other permission bits

Permission bits

ACL modes use Unix-style 9-character strings: rwxrwxrwx

Bits Meaning
r Read (list directory, download files)
w Write (create, upload, delete, modify)
x Execute (traverse directory)

ACL matching

The most specific matching ACL wins. For a path like /projects/foo/bar.txt:

  1. Check for an ACL on /projects/foo
  2. If none, check /projects
  3. If none, check /
  4. If no ACL matches at all, full access is granted (backward compatible)

Home directories

Every user gets a private home directory. By default it's /home/<name> under the root, and it is created automatically on startup.

Home directories get an ACL with owner set to the user and mode = rwx------ (full access for the owner, nothing for anyone else). This ACL takes priority over broader rules because it is more specific.

To customize the path, set home_dir in the user config:

[[users]]
name = "alice"
password = "secret"
home_dir = "/users/alice"

Example

[[users]]
name = "alice"
password = "secret"
groups = ["editors"]

[[users]]
name = "bob"
password = "secret"
groups = ["viewers"]

[[groups]]
name = "editors"

[[groups]]
name = "viewers"

[[acl]]
path = "/"
owner = "alice"
group = "editors"
mode = "rwxr-x---"    # alice: rwx, editors: r-x, others: ---

[[acl]]
path = "/public"
owner = "alice"
group = "viewers"
mode = "rwxr-xr-x"    # alice: rwx, viewers: r-x, others: r-x
  • alice can read and write everywhere (/ and /public).
  • Editors group members can read everywhere (/ gives r-x), write only if / has write for group (it doesn't here).
  • bob (viewers) can read /public (r-x group bits), but --- for others on / means no access to other paths.
  • Anonymous users have --- on both, so they're denied everywhere.

Configuration

./fileserver -config config.toml

All options

root_dir = "./files"

[http]
enabled = true
address = ":8080"

[http.tls]
enabled = false

[ftp]
enabled = true
address = ":2121"
passive_min = 50000
passive_max = 50100

[sftp]
enabled = true
address = ":2222"
host_key = ""                      # auto-generated on first run

[webdav]
enabled = true
prefix = "/webdav"

[smb]
enabled = false
address = ":445"
netbios = "FILESERVER"
share_name = "files"

[[users]]
name = "admin"
password = "admin"
groups = ["admin"]
home_dir = "/home/admin"             # defaults to /home/<name>

[[groups]]
name = "admin"

[[acl]]
path = "/"
owner = "admin"
group = "admin"
mode = "rwxr-x---"

When no ACLs are defined, all authenticated users have full access.

Password hashing

[[users]]
name = "admin"
password = "$2a$10$..."
home_dir = "/home/admin"

Generate a hash:

htpasswd -nbB admin your-password   # requires apache2-utils

When no users are defined, authentication is disabled entirely (anonymous access).

Build

go build -o fileserver .

HTTP API

Method Path Action
GET /browse/dir/ List directory
GET /browse/file Download file
POST /browse/dir/ Upload files (multipart)
PUT /browse/dir/file Upload single file
DELETE /browse/path Delete file or directory
MKDIR /browse/dir/name/ Create directory

Legacy paths without the /browse/ prefix (e.g., /file) also work for backward compatibility.

Project

fileserver/
├── main.go       - entry point, wiring
├── config.go     - TOML config structs
├── auth.go       - authentication manager
├── vfs.go        - virtual filesystem with permission checks
├── http.go       - HTTP/HTTPS + WebDAV server
├── webdav.go     - WebDAV handler (VFS-backed)
├── ftp.go        - FTP server (VFS-backed)
├── sftp.go       - SFTP server
├── smb.go        - SMB server (skeleton)
├── config.toml   - default configuration
└── go.mod