-
-
Notifications
You must be signed in to change notification settings - Fork 43
Data Storage and Persistence
All durable WebSSH state belongs under DATA_DIR. Mount that directory on persistent storage and back it up as one coordinated unit.
Typical content includes:
DATA_DIR/
|-- app.db
|-- secret_key
|-- logs/
| `-- security_audit.log
|-- users/
| `-- user_<id>/
| |-- profiles.json
| |-- commands.json
| |-- command_sets.json
| |-- jump_hosts.json
| |-- settings.json
| |-- notes.json
| |-- keys.json
| `-- known_hosts
`-- deleted_users/
Exact auxiliary files can evolve. Do not selectively copy only the database and assume the installation is recoverable.
app.db stores relational security and runtime metadata, including:
- local users and administrator state;
- active/revoked socket session metadata;
- persistent SSH session metadata;
- Passkey credentials and challenges;
- recovery-code hashes;
- OIDC identities and one-use login state;
- LDAP identity links and authorization metadata.
SQLite is part of the one-process architecture. Do not run multiple independent WebSSH workers or containers against the same database and data directory.
Profiles, commands, command sets, jump hosts, application settings, notes, encrypted SSH keys, and known-host trust are isolated below users/user_<id>/. Every application access must also enforce authenticated user ownership; path separation alone is not the authorization control.
JSON-backed state follows a full load-modify-save cycle while holding the shared storage lock. Writes use an atomic temporary-file replacement and filesystem synchronization. Corrupt JSON is not silently replaced with an empty default because doing so could turn a recoverable incident into permanent data loss.
Do not edit these files while WebSSH is running. Use the UI or supported APIs, or stop every process before a controlled offline repair.
Persisted JSON schemas are migrated additively. Current schema version 2 covers profiles, command sets, jump hosts, keys, settings, and application settings. Before changing a file, migration creates a private backup and writes the upgraded representation atomically.
Database changes likewise preserve existing installations. Always take a verified native backup before upgrading across versions.
Private keys are encrypted with user-specific Fernet material derived from SECRET_KEY:user_id using PBKDF2-HMAC-SHA256 and 600,000 iterations. The key record, application secret, and user ID are therefore part of one recovery boundary.
Copying user files without app.db and the matching SECRET_KEY is not a valid migration. Replacing SECRET_KEY manually can make stored keys unreadable.
User deletion first moves the user's directory to a quarantine area under deleted_users. If the database transaction fails, WebSSH attempts to restore the directory. Quarantine is an integrity mechanism, not an indefinite retention or backup strategy; apply an explicit policy to this sensitive residual data.
Run the container or process under a dedicated identity and restrict DATA_DIR to it. Secret files should be read-only wherever possible. Avoid network filesystems with weak locking or atomic-rename semantics unless their behavior has been tested with SQLite and WebSSH's write pattern.
Use WebSSH's native backup workflow for a live instance. For an offline filesystem backup, stop every WebSSH process first and capture the complete directory consistently. See Backup, Restore, and Secret Rotation.
WebSSH documentation - Project - Issues - Discussions - Security
WebSSH Wiki
Install and operate
- Installation from Source
- Docker and Docker Compose
- Production Deployment
- Reverse Proxy and Subfolder Deployment
- Upgrading, Rollback, and FAQ
Identity and access
- Users and Account Management
- Authentication Overview
- LDAP and Active Directory
- OpenID Connect
- Passkeys and Recovery Codes
SSH and files
- SSH Connections and Host Keys
- Profiles, Jump Hosts, and Commands
- Terminal and Persistent tmux Sessions
- SFTP File Workspace and Transfers
- Tailscale SSH
Reference and administration