### lichen.page lichen.page is a cms for static site generators built on atproto. you can see [screenshots](https://lichen.page/screenshots) of it, read about its [background](https://lichen.page/green-paper.html), or try it out in one the following ways: - use the hosted version — [login with atproto](https://dash.lichen.page) - run it locally — see the [quickstart](#quickstart) - use the [malleable software version](#agent-entrypoint) lichen.page is a piece of software fan-fiction (aka a fork) of [lichen-markdown](https://lichen.commoninternet.net) which was itself a fork of [lichen-gemini](https://codeberg.org/stringbone/lichen/src/branch/master), which is composed of a few forth scripts. In the third edition, the CMS was rewritten in Rust to enable realtime collaboration using yrs and work with any static site generator. This is an independent and experimental project and welcomes contributions, feedback, bug reports, and conversation. ![artwork created by frsw of a geometric frame](docs/frame.png) *artwork created by [frsw](https://www.instagram.com/frsw_franz/)* ### Quickstart ```bash git clone https://tangled.org/notplants.net/lichen.page.git cd lichen.page cargo run -- server run # then visit http://127.0.0.1:9000/ ``` This starts the lichen server on your computer, without requiring a login. Use the dashboard to create or open a site. Sites live in `~/.lichen/`. To serve a single site from a directory instead, use `cargo run -- server run --site ./site`. For all features, see [README-extended.md](README-extended.md). ### Commands `cargo run --` runs the `lichen` executable. - `lichen server run` — run locally; add `--site ` for a standalone site. - `lichen server init/build/export` — prepare, build, or export a standalone site (default: `./site`). - `lichen remote …` — log in to a remote server, manage sites, and synchronize local clones. - `lichen update` — update the executable. Use `lichen --help` to explore commands. The [extended command reference](README-extended.md#command-line-interface) covers all options. ### Configuration The default lichen stores data in `~/.lichen/` (or `LM_ROOT_DIR`) and uses port 9000 (overridden by `--port` or `LM_SERVER_PORT`). The server configuration is in `~/.lichen/lichen.toml`, and each site configuration is in `~/.lichen//settings.toml` For site settings, lichen reads its settings from layered sources: 1. optional CLI args: `--site ` establishes the project root (defaults to `./site`). `--settings ` sets the path to the settings file (defaults to `/settings.toml`). 2. optional environment variables prefixed with `LM_` (including `LM_SITE_DIR` and `LM_SETTINGS_PATH`, for example `LM_AUTO_SAVE=true`). 3. optional values in `settings.toml`. 4. default values. CLI args override environment variables which override file values which override the defaults. standalone `server` commands use this configuration scheme. Multi-site hosting uses `lichen.toml` instead; see [README-extended.md](README-extended.md#configuration). the standard usage is: `./lichen server run --site path/to/your/site` (with other configurations stored in `path/to/your/site/settings.toml`). All possible configurations are shown in `settings.toml.example` along with explanations. `auto_save` automatically saves edits made in the CMS, but can be disabled within settings. Clients without JavaScript cannot use autosave. ### Authentication & User Management For standalone or multi-site hosting, if `use_auth` is not explicitly set to true in configuration, authentication will not be required and anyone can access the CMS. If `use_auth` is set to true, then authentication is required, via one of the configured `auth_providers` set in `lichen.toml`, which can have a values of `file`, `atproto` or `oidc` or a list of these. Users are stored as individual TOML files in the `users/` directory within your site folder: ``` site/ └── users/ ├── alice.toml └── bob.toml ``` In file auth mode, user files contain an Argon2 password hash: ```toml password_hash = "$argon2id$v=19$m=19456,t=2,p=1$..." ``` And you can use the built-in CLI commands to manage users (passwords are hashed automatically): ```bash # create a new user (prompts for password) cargo run -- server users --site ./site add yourusername # update an existing user's password cargo run -- server users --site ./site set-password yourusername ``` To start an authenticated session, visit `/login/`. After logging in, the browser receives a session cookie (managed by tower-sessions) which allows access to protected CMS routes. ### Static Site Generators lichen uses a simple built-in static site generator by default, but it can also be configured to use other static site generators. these are the possible values for the `ssg` setting in `settings.toml`. each also requires being enabled as a compilation feature. - `lichen` – the default, implements a markdown + Tera pipeline entirely inside this crate. - `hugo` – enable the `hugo` Cargo feature and install the `hugo` CLI somewhere on `$PATH`. - `mdbook` – enable the `mdbook` Cargo feature. This routes all builds through the `mdbook_driver` crate so no external binary is required. additional static site generators can be added by implementing the `StaticSiteGenerator` trait in ssg_trait.rs. ### Multi-Site Mode lichen can also be run in multi-site mode, which allows hosting multiple sites from a single server instance with a management dashboard. Each site is served based on its domain name via the HTTP Host header. ```bash cargo run -- server run --multi ``` For full documentation of multisite mode, see [README-extended.md](README-extended.md). ### Deploy as a Nix service This repo's flake ships everything needed to run lichen as a systemd service on NixOS: - **`packages.lichen`** (also `packages.default`) — the unified client/server binary, built with client support, Git, ATProto, the optional terminal, and iroh. Other features can be selected when building. `git` and `ssh` are wrapped onto its `PATH` for git-backed sites and deploy keys. ```bash nix build .#lichen # -> ./result/bin/lichen nix run .#lichen -- server run --multi # run it directly ``` - **`nixosModules.lichen`** — a NixOS module exposing `services.lichen`. Import it in a configuration and pass your deployment vars; it defines a hardened `systemd.services.lichen` (`Restart=always`, `StateDirectory`, `EnvironmentFile`, `DynamicUser` by default). ```nix { inputs.lichen.url = "git+https://tangled.org/notplants.net/lichen.page"; outputs = { self, nixpkgs, lichen }: { nixosConfigurations.myhost = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ lichen.nixosModules.lichen { services.lichen = { enable = true; port = 8080; bindAddress = "100.84.190.30"; # e.g. a Tailscale IP; "0.0.0.0" = all baseUrl = "https://staging.lichen.page"; dataDir = "/var/lib/lichen"; # sites + users/ + lichen.toml live here environmentFile = "/run/secrets/lichen.env"; # atproto/OAuth/PDS secrets — NEVER in the store openFirewall = true; }; } ]; }; }; } ``` **Options** (`services.lichen.*`): `enable`, `package`, `bindAddress`, `port`, `dataDir`, `user` / `group` / `dynamicUser`, `environmentFile`, `baseUrl`, `extraArgs`, `openFirewall`. The typed options are passed through as `LM_*` env vars (`LM_SERVER_PORT`, `LM_BIND_ADDRESS`, `LM_PUBLIC_URL`, `LM_ROOT_DIR`); any other server setting can go in `environmentFile` or a `lichen.toml` in `dataDir`. Keep **secrets only in `environmentFile`** — it is read by systemd at start and never copied into the nix store. See [nix/lichen-service.nix](nix/lichen-service.nix). ### Agent Entrypoint For the malleable software version, paste this prompt into your AI agent of choice: ``` Please read https://tangled.org/notplants.net/lichen.page/blob/main/.agents/skills/lichen/SKILL.md, and explain the project. what is the malleable software framing? how can we install this and use this? ```