VYLK

VYLKDocs

Install and use Vylk.

VYLK is a single-user Markdown editor. Run it on your computer and open it in a browser.

First run

Install VYLK, then start it with your chosen password. Open localhost:8080 and sign in.

Markdown notes default to ./notes and the SQLite database to ./vylk.db, relative to VYLK's startup directory. Keep VYLK running while using the app.

Install VYLK

Ubuntu or Debian

Add the shared Toxdes repository once:

sudo apt update && sudo apt install -y ca-certificates curl gnupg && curl -fsSL https://packages.toxdes.com/apt/pubkey.gpg | sudo gpg --dearmor --yes -o /usr/share/keyrings/toxdes-archive-keyring.gpg && echo "deb [signed-by=/usr/share/keyrings/toxdes-archive-keyring.gpg] https://packages.toxdes.com/apt stable main" | sudo tee /etc/apt/sources.list.d/toxdes.list && sudo apt update
sudo apt install vylk
VYLK_PASSWORD='replace-with-your-password' vylk

Update: run sudo apt update && sudo apt upgrade vylk, then restart VYLK.

Fedora

Add the shared Toxdes repository once:

printf '%s\n' '[toxdes]' 'name=Toxdes' 'baseurl=https://packages.toxdes.com/rpm' 'enabled=1' 'gpgcheck=1' 'repo_gpgcheck=1' 'gpgkey=https://packages.toxdes.com/rpm/pubkey.gpg' | sudo tee /etc/yum.repos.d/toxdes.repo
sudo dnf install vylk
VYLK_PASSWORD='replace-with-your-password' vylk

Update: run sudo dnf upgrade vylk, then restart VYLK.

Arch Linux (AUR)

yay -S vylk-bin
VYLK_PASSWORD='replace-with-your-password' vylk

For current source: yay -S vylk-git.

Update: run yay -Syu vylk-bin, then restart VYLK.

Standalone binary

Download your processor’s archive and put the binary on your PATH.

curl -fsSL https://packages.toxdes.com/releases/vylk_3.1.1_amd64.tar.gz | sudo tar xzC /
VYLK_PASSWORD='replace-with-your-password' vylk

Update: download the newer archive, replace the binary, and restart VYLK. Your notes and database stay where they are.

Docker

Linux AMD64 and ARM64. Notes and database are stored in vylk-data.

docker run -d --name vylk -p 127.0.0.1:8080:8080 -e VYLK_PASSWORD='replace-with-your-password' -v vylk-data:/data toxdes/vylk:{version}

Open localhost:8080 after the container starts.

Update: pull the new image, remove the container, then run the same command again with the volume unchanged.

Build from source

Requires Git and the Go version declared in the application's go.mod.

git clone https://github.com/toxdes/vylk.git && cd vylk
go build -trimpath -ldflags="-s -w -X vylk/internal/server.version=$(cat VERSION)" -o vylk ./cmd/vylk
VYLK_PASSWORD='replace-with-your-password' ./vylk

Update: pull the latest source, rebuild the binary, and restart the process.

Windows binary

Download the executable and open PowerShell in its folder.

Download v3.1.1 - Windows AMD64

$env:VYLK_PASSWORD="replace-with-your-password"
.\vylk_windows_amd64_{version}.exe

Update: download the newer executable, replace the file in the same folder, and start it again. Keep the notes folder and vylk.db file.

Docker

Notes and database are stored in vylk-data.

docker run -d --name vylk -p 127.0.0.1:8080:8080 -e VYLK_PASSWORD='replace-with-your-password' -v vylk-data:/data toxdes/vylk:{version}

Update: pull the new image, remove the container, and run the same command again with vylk-data unchanged.

Homebrew

brew install toxdes/tap/vylk

Update: run brew update && brew upgrade vylk.

macOS binary

Download and extract the ZIP, then start VYLK from Terminal.

VYLK_PASSWORD='replace-with-your-password' ./vylk

Update: download the newer ZIP, replace the binary, and restart VYLK. Keep your notes folder and database.

Docker

Notes and database are stored in vylk-data.

docker run -d --name vylk -p 127.0.0.1:8080:8080 -e VYLK_PASSWORD='replace-with-your-password' -v vylk-data:/data toxdes/vylk:{version}

Update: pull the new image, remove the container, and run the same command again with vylk-data unchanged.

Build from source

Requires Git and the Go version in go.mod.

git clone https://github.com/toxdes/vylk.git && cd vylk
go build -trimpath -ldflags="-s -w -X vylk/internal/server.version=$(cat VERSION)" -o vylk ./cmd/vylk
VYLK_PASSWORD='replace-with-your-password' ./vylk

Update: pull the latest source, rebuild the binary, and restart it.

Write and customize

Markdown and live preview

Write Markdown or use the toolbar. Live preview shows the result beside your text; cursor-position highlighting connects the two.

Zen writing

Zen renders completed bold, italic, strikethrough, inline code, and Markdown links as you type. Unfinished syntax stays as typed. Select text for the compact toolbar; notes remain Markdown.

Click a rendered link and choose Edit link to change its URL. Apply an empty URL to remove the link but keep its label; click away to cancel. Switch to Write or Split to inspect the source.

Writing and reading views

Choose editor-only, preview-only, resizable Split, or distraction-free Zen. Switching views focuses the visible pane. Cursor-following and selection scrolling stay gradual; Preferences sections switch instantly, and dialogs follow your motion setting.

Interactive preview

In the preview, check tasks, edit Markdown blocks, or drag them into order. On mobile, selected blocks show a fixed action tray.

Preferences

Set themes, fonts, page width, autosave, toolbar and Save button visibility, and your starting view. Appearance → Reduce motion can follow your system, always reduce motion, or never reduce it.

Keyboard shortcuts

In the editor: Ctrl+1 opens Write, Ctrl+2 Preview, Ctrl+3 Split, and Ctrl+4 Zen. On macOS, use Command. Customize keys in Preferences → Shortcuts; sequences default to the Ctrl+E prefix.

Encryption: setup and recovery.

First-run defaults

New accounts start in Write, with interactive preview, toolbar, and autosave on; manual Save button hidden. Zen: Inter at 125%, with title, word count, and view switcher visible. Upgrades keep saved preferences.

Offline use and sync

Sign in online once per device. Install VYLK as a PWA if supported. The installed app caches its shell and notes; offline edits and deletions wait in browser IndexedDB and sync when you reconnect.

Connection details

While open, an authenticated event stream watches for changes. A 25-second heartbeat updates Online/Offline status; 70 seconds without one means offline. On reconnect, VYLK reconciles the full cache before replaying local work.

When two devices edit one note, VYLK attempts a three-way merge. Separate line edits and one-sided title or tag changes merge automatically. Ambiguous overlaps open a conflict resolver that keeps both versions and lets you edit the result.

Sign-out retains cached notes and pending edits for your next sign-in. Without encryption, browser storage stays plaintext; signing out does not erase it. With encryption, notes and queued edits stay encrypted and the remembered key is forgotten. Offline Sign out locks this browser but cannot revoke its server session.

  • Saving: waiting for server acknowledgement.
  • Saved: changes reached the server.
  • Offline: edits remain on this device until reconnection.

Do not clear browser storage with pending work.

If the server database changes

Sync pauses. Choose:

  • Keep changes preserves local work. Restore the previous matching database and notes directory, then reload.
  • Switch permanently discards this browser’s cached notes and pending edits, loads the replacement, and requires sign-in.

An older backup of the same database keeps its identity; this check cannot detect rollback.

End-to-end encryption

Encryption is optional. Your browser encrypts titles, tags, bodies, and pending offline edits before sending or storing them. The server holds ciphertext and wrapped keys, never your passphrase or recovery words.

HTTPS first

Use HTTPS or http://localhost:8080 on the host. Browser cryptography requires a secure context. Plain HTTP on a LAN IP does not qualify, even on a trusted network.

Can't sign in to an encrypted instance?

If login says encryption requires HTTPS, use the HTTPS address with a trusted certificate, or localhost on the host. Already signed-in insecure pages return to login with this notice; bypassing it cannot enable browser cryptography.

Enable encryption

  1. Back up VYLK_DB and VYLK_DIR together. Sign in with the server password; open Preferences → Encryption.
  2. Choose a passphrase. Download or write down the numbered 24-word recovery key; store it safely, separate from the server.
  3. With the original list hidden, confirm all 24 words individually and acknowledge the access-loss warning. Bulk paste is disabled to encourage a separate recovery copy.
  4. Keep setup open while VYLK encrypts and verifies notes, converts local offline edits, and switches server storage. Note writes pause during conversion.
  5. Restart the server to release plaintext from the old process's memory. Update and unlock other devices to convert their local caches.

To resume an interrupted conversion, reopen setup with the original server password, vault passphrase, and recovery key. Unopened devices may still hold plaintext caches.

Passphrase and recovery key

After conversion, sign in and unlock with your passphrase or recovery key; VYLK_PASSWORD no longer unlocks notes. Recovery downloads use vylk-recovery-key-YYYYMMDDHHMM.txt. Anyone with the key can unlock your vault: protect it like a password.

In Preferences → Encryption, verify your current passphrase or recovery key to change either. Passphrase changes offer Sign out other devices, on by default. Replacing the recovery key revokes other sessions. This browser signs in again automatically.

Keep a separate recovery copy.

If you lose both the passphrase and recovery key, VYLK cannot recover your notes—even from a backup. Retaining VYLK_PASSWORD permits a destructive reset to an empty vault. Old ciphertext is archived for 30 days on the server; unlocking it still requires the original secret.

Remembered browsers and devices

Sign-in remembers a non-extractable browser key across tabs, refreshes, updates, and later visits while server access stays valid. Anyone using that browser profile can read cached notes. Sign out on shared devices: this forgets the key but keeps encrypted pending edits for your next unlock.

Preferences → Account → Devices treats each browser profile, including its tabs, as one device. Signing it out revokes its server sessions; offline devices learn this when reconnecting. Revocation cannot erase their cached notes or existing keys.

What encryption does and does not cover

Argon2id derives a passphrase wrapping key; a random vault key encrypts notes with AES-256-GCM. The server still sees IDs, revisions, timestamps, pins, preferences, and sync activity. Search, tag filtering, and conflict resolution run on unlocked devices.

Use HTTPS and a trusted deployment. A compromised server can replace the app to steal secrets at unlock or use a remembered key on your next visit. Encryption cannot detect replayed older valid ciphertext. Changing a passphrase or recovery key rewraps the same vault key; it does not revoke a key or old wrapped-key copy already stolen.

Backups and safety

Without encryption, notes are Markdown files; SQLite holds their metadata. With encryption, the server stores encrypted note bodies, titles, and tags. Stop VYLK and copy VYLK_DB and VYLK_DIR together, or use a consistent backup method that captures both. Neither alone is a complete backup. Keep encrypted notes’ passphrase or recovery key separately. Restart with matching data and valid credentials to resume the instance.

Enabling encryption removes active plaintext storage and the temporary conversion backup. It cannot erase old external backups, SQLite migration snapshots, unopened browser caches, filesystem snapshots, or freed disk blocks. Review those copies under your backup policy.

Upgrading from server-side file encryption

Legacy server-side encryption and its settings have been removed. Before upgrading, export those notes as plaintext with the previous VYLK version; then optionally enable E2EE in the app. Removed settings or recognized encrypted files stop startup safely. The oldest ciphertext has no identifying header: removing settings does not decrypt it.

Migration backups

Before a pending database migration, VYLK saves a consistent SQLite snapshot beside the database. It retains the three newest *.pre-migration-*.db snapshots. Allow roughly one extra database-sized block of free space.

Connect another device

Use a desktop or mobile browser, or install the PWA.

VYLK listens on port 8080 by default. For an unencrypted instance, open the host's local IP address on a trusted network and allow the connection through its firewall. Plain HTTP exposes passwords and notes in transit.

Encrypted notes require HTTPS, even on a local network. A LAN address such as http://192.168.1.10:8080 is not a secure browser context and cannot unlock notes. HTTP on localhost or loopback works on the host. Encryption requirements.

Use an HTTPS reverse proxy with a certificate trusted by every device. VYLK neither serves HTTPS nor issues certificates. Service workers and PWA installation require HTTPS; localhost is exempt. The Docker examples bind to localhost: use your proxy to reach them from other devices.

Sign in online once per device before relying on offline access. Keep password protection enabled. Set VYLK_TRUST_PROXY=1 only when a trusted proxy supplies forwarding headers.

Configuration

Set environment variables before starting VYLK. For Docker or secret managers, VYLK_PASSWORD_FILE=/run/secrets/vylk_password reads the server password from a file. Enable encryption in the app; its passphrase and recovery key are not server settings.

VYLK configuration variables
VariableDefaultPurpose
VYLK_PASSWORDnoneRequired before encryption. Afterward, sign in with the vault passphrase or recovery key. Retaining this password permits a destructive reset to an empty vault; it cannot recover old notes.
VYLK_PASSWORD_FILEunsetRead the initial server password from a secret file instead of an environment variable.
PORT8080HTTP listen port.
VYLK_DIR./notesDirectory for Markdown notes or encrypted note files.
VYLK_DB./vylk.dbSQLite database: metadata, sync state, and wrapped vault keys. Back up with the notes directory.
VYLK_APP_NAMEVYLKApp and PWA name for this server. Restart to apply.
VYLK_TRUST_PROXYunsetSet to 1 only behind a trusted TLS-terminating proxy.
VYLK_REQUIRE_STRONG_PASSWORDSfalseUse true or 1 to require strong server passwords and have browsers enforce strong vault passphrases.
VYLK_DISABLE_VAULT_CHANGESfalseUse true or 1 for shared demos: block encryption setup, passphrase/recovery-key changes, vault reset, and device revocation at the API. Notes, sign-in, and existing encryption still work.
VYLK_NO_BROWSERunsetUse 1 or --no-browser to skip the startup browser-opening attempt.
ARTIFICIAL_RTT_DELAY_MS0Request delay for development only; keep disabled in production.

With VYLK_DISABLE_VAULT_CHANGES=true, encryption settings remain viewable. Startup refuses this setting during an unfinished encryption migration.

Local setup example

VYLK_PASSWORD=change-this PORT=8080 VYLK_DIR=./notes VYLK_DB=./vylk.db ./vylk

Build and test

Local binary, with version from VERSION:

go build -trimpath -ldflags="-s -w -X vylk/internal/server.version=$(cat VERSION)" -o vylk ./cmd/vylk

All supported binaries and platform archives:

./build.py

Linux packages and archives (Yesb):

./yesb/build_all.py

Tests require the Go version in go.mod and Bun. Browser tests require Chrome or CHROME_PATH pointing to a compatible browser. Install dependencies and run:

bun ci
go test ./...
go tool staticcheck ./...
bun run test:frontend
bun run test:browser