A self-hosted, file-based Markdown editor

Test coverage

Markoun is a lightweight, self-hosted, and entirely file-based Markdown editor designed for users who prioritize privacy and simplicity. > The UI layout of Markoun is inspired by [Haptic](https://github.com/chroxify/haptic) and [Obsidian](https://github.com/obsidianmd) — both excellent Markdown editing tools. ## Features - **Clean UI**: Minimal interface with smooth animations and complete core editing features - **File-Based Architecture**: Works directly on local files — no database, no indexing, fully portable - **LaTeX support**: Live Markdown preview with built-in LaTeX support - **Keyboard Shortcuts**: Paste clipboard images and save the current document without leaving the editor - **Rich Configuration**: Flexible config.yaml options for logging, authentication, and file control ## Quick Start You can deploy Markoun using `docker`, `docker compose`, or `Nix`:
🐳 Docker Setup - Click to expand
**Setup** ```bash export MARKOUN_PORT=10000 export MARKOUN_ROOT=./ docker run -itd --name markoun \ --restart unless-stopped \ -p ${MARKOUN_PORT:-10000}:80 \ -e DEFAULT_ADMIN_NAME=admin \ -e DEFAULT_ADMIN_EMAIL=admin@example.com \ -e DEFAULT_ADMIN_PASSWORD=change-this-password \ -v ${MARKOUN_ROOT:-$(pwd)}:/markoun \ tropicalalgae/markoun:latest ``` > The `DEFAULT_ADMIN_*` environment variables are optional. > > If no administrator credentials are provided, Markoun will automatically create a default administrator account with a randomly generated password on the first startup. > > To view the generated credentials, run: `docker logs -f markoun` **Volume Explanation** After the container starts for the first time, Markoun will automatically create the following files and directories under `MARKOUN_ROOT`: | Path | Description | | ------------- | ------------------------------------------------- | | `config.yaml` | Application configuration file. | | `welcome.md` | Default welcome page displayed to new users. | | `data/` | Stores all Markdown documents and workspace data. | | `log/` | Application log files. | If you are upgrading from `v0.2.2` or earlier, or would like to learn more about the changes to the Docker mounting layout, please refer to the [Docker Migration Guide](./docs/en/docker_migration.md).
📦 Docker Compose Setup - Click to expand
**Setup** Copy [docker-compose.yaml](./docker-compose.yaml) to your local machine, then create a `.env` file in the same directory: ```.env MARKOUN_PORT=10000 # Port exposed by Markoun MARKOUN_ROOT=. # Directory for persistent data DEFAULT_ADMIN_NAME=admin # Default administrator username DEFAULT_ADMIN_EMAIL=admin@example.com # Default administrator email DEFAULT_ADMIN_PASSWORD=change-this-password # Default administrator password ``` Then start Markoun by: ``` docker compose up -d ``` **Volume Explanation** After the container starts for the first time, Markoun will automatically create the following files and directories under `MARKOUN_ROOT`: | Path | Description | | ------------- | ------------------------------------------------- | | `config.yaml` | Application configuration file. | | `welcome.md` | Default welcome page displayed to new users. | | `data/` | Stores all Markdown documents and workspace data. | | `log/` | Application log files. |
❄️ Nix Setup - Click to expand
**Setup** With [Nix](https://nixos.org/download/) installed and flakes enabled, run Markoun directly from the repository's default branch: ```bash export PORT=10000 export DEFAULT_ADMIN_NAME=admin export DEFAULT_ADMIN_EMAIL=admin@example.com export DEFAULT_ADMIN_PASSWORD=change-this-password nix run github:tropical-algae/markoun ``` To run the source currently checked out in this repository instead: ```bash nix run . ``` Alternatively, install Markoun into your user profile and run it as a regular command: ```bash nix profile install github:tropical-algae/markoun#markoun markoun ``` Markoun serves the complete web application at [`http://localhost:10000`](http://localhost:10000). The process runs in the foreground; use your preferred process or service manager for a persistent server. > The `DEFAULT_ADMIN_*` environment variables are optional. > > If they are omitted, the first startup creates an administrator with a random password and prints the credentials in the terminal output. **Runtime Path Explanation** Markoun keeps editable files in the standard XDG user directories: | Path | Description | | ------------------------------------------------------------------------------------- | -------------------------------------------------------------- | | `$XDG_CONFIG_HOME/markoun/config.yaml`
default: `~/.config/markoun/config.yaml` | Application configuration file. | | `$XDG_DATA_HOME/markoun/welcome.md`
default: `~/.local/share/markoun/welcome.md` | Editable welcome page, initialized from the packaged template. | | `$XDG_DATA_HOME/markoun/data/`
default: `~/.local/share/markoun/data/` | Stores all Markdown documents and workspace data. | | `$XDG_STATE_HOME/markoun/log/`
default: `~/.local/state/markoun/log/` | Application log files. | The runtime paths can be overridden before starting Markoun: ```bash export MARKOUN_CONFIG_FILE=/path/to/config.yaml export DOCUMENT_ROOT=/path/to/documents export WELCOME_NOTE_PATH=/path/to/welcome.md export LOG_ROOT=/path/to/log nix run github:tropical-algae/markoun ```
## Configuration Markoun is configured via a `config.yaml` file. Restart the service after modifying this file for changes to take effect. Below are some important options: | **Key** | **Description** | **Default** | **Since** | | -------------------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------ | --------- | | `USER_WORKSPACE_ISOLATION` | Uses `/` as each authenticated user's workspace when authentication is enabled. | false | `v0.2.2` | | `MEDIA_DELIVERY_MODE` | Sends protected images through FastAPI (`application`) or an Nginx internal redirect (`nginx`). | `nginx` | `v0.2.2` | | `AUTH_REQUIRED` | Requires users to sign in before accessing and editing workspace files. | true | `v0.2.1` | | `DEBUG` | Enables/disable debug-level logging for the backend service. | false | `v0.0.1` | | `ACCESS_TOKEN_DEFAULT_EXPIRE_MINUTES` | **Standard Session Lifetime**: Duration (in minutes) a user remains logged in before the session expires. | 1440 | `v0.0.1` | | `ACCESS_TOKEN_EXTENDED_EXPIRE_MINUTES` | **Persistent Session Lifetime**: Duration (in minutes) for users who select "Remember Me" during login. | 43200 | `v0.0.1` | | `ACCESS_TOKEN_COOKIE_SECURE` | Sends the auth cookie only over HTTPS. Enable this when the public site is served through HTTPS. | false | `v0.1.4` | | `DISPLAYED_FILE_TYPES` | **File Filter**: A list of file extensions that the editor is permitted to display. | ["md", "png", "jpg", "jpeg", "bmp", "svg"] | `v0.0.1` | | `WELCOME_NOTE_PATH` | Path to the Markdown file used as the default welcome page when no document is open. | `./welcome.md` | `v0.1.0` | All configuration options can be initialized via environment variables at startup, and then modified at runtime through `config.yaml`. For more configurable options, see [config.py](src/markoun/common/config.py) > [!WARNING] > Setting `AUTH_REQUIRED` to `false` gives every visitor full access to read, create, edit, upload, move, and delete workspace files. > Only disable authentication on a trusted network or behind another access-control layer. ## Editor Details **Keyboard Shortcuts**: | **Action** | **Windows / Linux** | **macOS** | | --------------------- | ------------------- | ------------- | | Paste clipboard image | `Ctrl + V` | `Command + V` | | Save current document | `Ctrl + S` | `Command + S` | **Relative Image Paths**: When inserting images into a Markdown file, image paths are generated relative to the Markdown file’s location — not the project root. The renderer resolves them through the protected media API, preserving portability without exposing the physical workspace path. **Rename by Long Press**: Long-press on a file or folder name in the sidebar to rename it. **Drag-and-Drop Upload**: Drag a local file onto a folder in the sidebar to upload it directly into that folder. **File Visibility Rules**: By default, the sidebar displays only Markdown files and common image formats. To show additional file types, modify `DISPLAYED_FILE_TYPES` in `config.yaml`. **System configuration**: Administrators can manage these options from the sidebar settings: - Enable or disable user registration. - Group pasted images by note, storing them in a folder named after the Markdown file. ## Limitations & Roadmap - [x] **Image security**: static image routes currently lack authentication checks - [x] **File system architecture**: design can be further optimized - [x] **UI polish**: incomplete animation feedback and styling inconsistencies - [ ] **Settings expansion**: add more configurable options for personalization and workflow control - [x] **Quick actions & interaction enhancements**: support more intuitive and efficient operations - [x] **Improved usability**: provide a smoother and more comfortable operation experience - [x] **Enhanced previews**: support richer previews, including image preview and ~~Gantt chart rendering~~ in Markdown files - [x] **Frontend refactoring**: codebase requires further optimization - [ ] **File synchronization**: support syncing files with a remote source - [ ] **Version management**: introduce file versioning with history tracking and restore capability - [ ] **Deployment options**: support more installation and deployment methods across different environments ## License This project is licensed under the [MIT License](https://github.com/tropical-algae/markoun/blob/main/LICENSE).