A homepage, blog, and single-user ActivityPub instance written in Lua https://raphaelkabo.com
  • Lua 72.4%
  • CSS 16%
  • HTML 6.4%
  • JavaScript 3.4%
  • Dockerfile 1.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-08 19:29:36 +01:00
content New post 2026-09-08 17:27:12 +01:00
src Fix line breaks on Mastodon 2026-09-08 19:29:36 +01:00
.dockerignore First commit! 2026-09-03 23:15:26 +01:00
.gitignore First commit! 2026-09-03 23:15:26 +01:00
docker-compose.yml Only listen on local 2026-09-08 13:47:04 +01:00
Dockerfile Fix lua-http bug 2026-09-08 13:44:51 +01:00
README.md Add summary, post images, move AP data out of env 2026-09-04 01:34:16 +01:00
stylua.toml Update linter rules, tweak content 2026-09-04 10:24:23 +01:00

🌙 Lunette 🪟

A lunette is a moon-shaped window.

Lunette is a single-user ActivityPub instance written in Lua - a tiny moon-shaped window on the Fediverse.

More specifically it is my instance, available on the web and at @[email protected] on the Fediverse. It is very adaptable to become someone else's blog, but you'll have to fork it and change some of the source code! This is because Lunette uses a lot of magical Lua DSL to build and output HTML, and that lives in the source code.

How to run Lunette

There are two ways to run Lunette: in Docker (which is easiest - you don't need to install Lua at all), or natively.

Either way, start by creating a .env file in the Lunette directory. This is read by Docker Compose and native Lua. You can add more to this file (see below) but this is the bare minimum:

AP_DOMAIN=localhost:8181
AP_SCHEME=http
AP_PORT=8181

Next, generate your ActivityPub keypair. Lunette signs everything it sends to other Fediverse servers with this key, and refuses to start without it. Never commit it to Git!

mkdir -p keys
openssl genrsa -out keys/private_key.pem 2048
openssl rsa -in keys/private_key.pem -pubout -out keys/public_key.pem

openssl is preinstalled on macOS and most Linux distributions.

Docker

You need Docker (or OrbStack on macOS). Then, from the Lunette directory:

docker compose up --build

Once it starts up, Lunette should be running at http://localhost:8181.

Native Lua on macOS

Lunette needs Lua 5.4, not the current default 5.5 (some of its dependencies don't support 5.5 yet).

# Lua 5.4, the LuaRocks package manager, and C libraries we build against
brew install [email protected] luarocks sqlite cmark openssl@3

# chroma does build-time syntax highlighting (optional)
brew install chroma

# Make `lua` mean 5.4, and point LuaRocks at it permanently
brew link [email protected]
luarocks config lua_version 5.4
luarocks config variables.LUA_DIR "$(brew --prefix [email protected])"

# Install Lunette's Lua dependencies
luarocks install http
luarocks install cmark
luarocks install luafilesystem
luarocks install lsqlite3 SQLITE_DIR="$(brew --prefix sqlite)"

Then run the server. The eval puts the LuaRocks tree on Lua's module path (add it to your ~/.zshrc/~/.bashrc to make it permanent).

eval "$(luarocks path)"
lua src/main.lua

Visit http://localhost:8181.

Native Lua on Debian/Ubuntu

This basically mirrors what the Dockerfile does:

sudo apt install lua5.4 liblua5.4-dev luarocks build-essential \
    libssl-dev libsqlite3-dev libcmark-dev m4 curl

# chroma has no Debian package so grab the release binary
ARCH=$(dpkg --print-architecture)
curl -sfL "https://github.com/alecthomas/chroma/releases/download/v2.27.0/chroma-2.27.0-linux-${ARCH}.tar.gz" \
    | sudo tar xz -C /usr/local/bin chroma

# The Lua dependencies, into your user tree (no sudo required)
luarocks --local --lua-version=5.4 install http
luarocks --local --lua-version=5.4 install cmark
luarocks --local --lua-version=5.4 install luafilesystem
luarocks --local --lua-version=5.4 install lsqlite3

Then:

eval "$(luarocks --lua-version=5.4 path)"
lua5.4 src/main.lua

Configuration

Some things can be configured in the .env file:

Variable Default Description
AP_DOMAIN localhost:8181 Your public domain
AP_SCHEME https http for local development
AP_PORT 8181 Port the server listens on
AP_KEYS_DIR keys Where the RSA keypair lives
DATABASE_FILE data/database.sqlite3 The SQLite database

Others, like the ActivityPub identity and the RSS feed metadata, can only be configured in the source code.