- Svelte 44.8%
- Go 42.6%
- CSS 4.7%
- Python 3.9%
- TypeScript 3.1%
- Other 0.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| app | ||
| scripts | ||
| server | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| compose.yaml | ||
| Dockerfile | ||
| README.md | ||
Fileapp
A Docker Compose application with one authenticated SMB share and a simple web file manager. The Svelte 5 interface uses components and styling copied from ../client-kit/app; that project is not needed to build or run Fileapp.
Deploy on Linux
Requires Docker Engine, Docker Compose v2 with bind.selinux support, and a dedicated existing data directory. Supported architectures: amd64 and arm64.
cp .env.example .env
Edit .env:
- Compose mounts the existing host directory
/mnt/mediaat/data. To change it, edit the bind mount'ssourceincompose.yaml. ADMIN_PASSWORD: a unique administrator password, at least 12 characters. Protect.envwithchmod 600 .env.PUID/PGID: UID/GID that should own files created through the UI and SMB. Find these withid -uandid -g.SELINUX_LABEL:Zby default; see below.
Create the directory if needed, assigning the chosen UID/GID. For example, with UID/GID 1000:
sudo install -d -m 0775 -o 1000 -g 1000 /mnt/media
chmod 600 .env
docker compose up --build -d
Open http://YOUR_SERVER:8080, sign in with your administrator credentials, and open Settings. Choose the mounted root or an existing subfolder, set an SMB username and password, enable the share, and save. SMB is disabled until configured. Existing files retain their ownership; the application does not recursively chown the host directory.
The web administrator and SMB account are separate. Settings and Samba's account database survive container recreation in the fileapp_state named volume. Admin credentials come from .env; changing them and recreating the container also invalidates web sessions.
SELinux enforcing hosts
The bind mount uses bind.selinux: Z, giving the mounted directory a private container label. Docker relabels its contents, including existing files. Use a dedicated data directory whose labels may be changed; avoid mounting /, /etc, /home, or other system directories.
Use SELINUX_LABEL=z only when this directory is intentionally shared with other containers. Private Z labels are unsuitable for two separate containers mounting the same directory, because the later container can relabel it away from the first. A host service may also lose access after relabeling; coordinate its policy separately.
Fileapp keeps SELinux enabled and does not use privileged mode, the Docker socket, or label=disable. Filesystem access still requires ordinary UID/GID permissions. Container processes use the host's container SELinux policy; host smbd_t permissions do not describe this containerized Samba deployment.
To investigate an access denial:
getenforce
ls -Zd /mnt/media
ls -ldn /mnt/media
docker compose logs --tail=100 fileapp
sudo ausearch -m AVC,USER_AVC -ts recent
Check both the directory's SELinux label and its numeric owner/permissions. SELinux failures appear in AVC audit records; ordinary filesystem permission failures may not. Fix the mount label or UID/GID access rather than disabling enforcement. Z/z relabeling must be supported by the underlying filesystem; NFS/CIFS-mounted data may need filesystem-specific policy and is outside the default deployment.
Connect over SMB
Use the configured SMB username and password:
- Windows File Explorer:
\\YOUR_SERVER\Files - macOS Finder → Go → Connect to Server:
smb://YOUR_SERVER/Files - Linux file manager:
smb://YOUR_SERVER/Files
Replace Files with your share name. Direct SMB2/3 access uses TCP port 445; automatic network discovery and SMB1 are not included. Port 445 must be free on the host. If another Samba service is already using it, stop that service or bind Fileapp to another host IP using SMB_BIND_ADDRESS.
The UI supports listing, filtering, downloading, uploading multiple files, creating folders, renaming, and deleting files or empty directories. Upload/rename collisions are rejected. The per-file upload limit defaults to 1 GiB and is configurable with MAX_UPLOAD_BYTES. Failed uploads are removed; files already uploaded in a multi-file batch remain. The filesystem must support hard links and Linux renameat2 for atomic publication and collision handling.
Read-only mode blocks edits through both SMB and the browser. Disabling SMB leaves the browser available. Saving settings restarts Samba and briefly disconnects clients. Windows may cache SMB credentials; disconnect the old session before reconnecting after a username/password change. Symlink following is disabled in Samba; browser file APIs are confined to the selected directory and reject escapes.
HTTPS reverse proxy
Set PUBLIC_ORIGIN=https://files.example.com and recreate the container. Proxy all HTTP paths to port 8080. This enables Secure session cookies and restricts mutation requests to that origin. Configure the proxy's upload size and timeout for your expected files. When accessing the UI directly over HTTP, leave PUBLIC_ORIGIN empty.
Use an actual server IP/hostname in the UI's connection card when the web hostname points to a reverse proxy. That field affects copied instructions only. Keep SMB on your trusted LAN or VPN. The application does not terminate TLS itself.
Operation
docker compose ps
docker compose logs -f fileapp
docker compose down
down keeps persistent state; down -v removes stored settings and SMB credentials. Neither command removes the bind-mounted host files. Back up both your data and the state volume. Health checks verify that the controller responds and that enabled Samba has a live process. Unexpected child-process failure exits the container for Compose to restart.
A root supervisor manages Samba and its account database. The HTTP server runs under PUID/PGID and talks to the supervisor over a filesystem-protected Unix socket. Read/write requests follow host filesystem permissions. API mutation requests require both an allowed Origin and a session CSRF token. Sessions expire after 12 hours and are held in memory. Ten failed logins from an IP block further attempts for 15 minutes; a reverse proxy shares this limit across its clients because forwarded IP headers are not trusted.
Development and validation
cd app
npm ci
npm run check
npm run build
cd ../server
go test -race ./...
go vet ./...
go build .
Go 1.25+ and Node.js 24+ are required. To work on the frontend, npm run dev proxies /api to localhost:8080. The web binary mode can connect to an existing supervisor socket; production startup is the default supervisor mode.
Validate Compose without starting containers:
docker compose config --quiet
On an SELinux-enforcing Docker host, use a fresh deployment with a disposable mounted directory and run:
python3 scripts/smoke.py
The smoke test prompts for your admin password, creates a test folder, configures generated SMB credentials, exercises browser and SMB transfers and read-only enforcement, restarts the container, checks persisted settings/credentials, and then removes its files and disables SMB. It refuses an already configured deployment. The test initializes the SMB account database; remove the disposable state volume when finished. Use FILEAPP_URL if the web UI is not at http://127.0.0.1:8080.
Also inspect ls -Zd and recent AVC records before/after testing to verify the mount label and absence of application-related denials. Live Docker/SMB/SELinux tests could not be run in the implementation workspace because Docker daemon and local listening-socket access are unavailable. Chromium also cannot launch under the workspace restrictions, so browser interaction checks remain unverified. Frontend builds and in-process backend tests can run without that access.