A self-hosted webcomic server built with Gleam. Stores panels and volunteer data in Mnesia (Erlang's built-in database) for reliability and serves them with simplicity.
- Webcomic hosting - Serve comics with markdown content
- Rich media support - Add images, videos, and audio to panels
- Hall of Fame - Track contributors and volunteers
- Custom styling - Per-panel CSS and JavaScript support
- Admin interface - Web-based management for panels and volunteers
- Type-safe - Built with Gleam's type system for reliability
- Gleam (latest version)
- Erlang/OTP (for Mnesia database and runtime)
git clone <repo-url>
cd homeservecp homeserve.example.toml homeserve.toml
# Edit homeserve.toml with your settings# Verify Mnesia is ready (persistent storage mode)
ERL_FLAGS="-sname homeserve" gleam run -m setup verify
# Generate a secure admin token for production
gleam run -m setup tokenProduction mode (data persists between restarts):
# Using just (recommended)
just run
# Or manually
ERL_FLAGS="-sname homeserve" gleam runDevelopment mode (data in memory only, lost on restart):
just run-dev
# or
gleam runVisit http://localhost:8000 to see your comic!
Panels are stored in Mnesia with this structure:
{
"meta": {
"index": 1,
"title": "My Awesome Comic",
"media": {
"kind": "image",
"url": "/assets/panel1.jpg",
"alt": "First panel!",
"track": null
},
"credits": {
"artists": ["Artist Name"],
"writers": ["Writer Name"],
"musicians": [],
"misc": []
},
"css": [],
"js": [],
"date": 1704067200,
"draft": false
},
"content": "Your name is..."
}Access at: /admin?token=YOUR_TOKEN
Panel management:
- Create, edit, and delete panels
- View all panels and their draft status
Volunteer management at /admin/volunteers?token=YOUR_TOKEN:
- Create volunteer profiles (name, bio, social links)
- Edit and delete volunteers
- View all volunteers
Volunteer profiles appear on /hoc/<name> pages when names match.
Key options in homeserve.toml:
| Section | Key | Description | Default |
|---|---|---|---|
[server] |
port |
HTTP port | 8000 |
[server] |
host |
Bind address | 0.0.0.0 |
[mnesia] |
data_dir |
Database location | Mnesia default |
[admin] |
token |
Admin auth token | changeme |
[contact] |
email |
Contact address | admin@example.com |
[logging] |
level |
Log level | info |
See homeserve.example.toml for all options.
Caddy provides HTTPS, static file serving, and security headers:
# Install Caddy (https://caddyserver.com/docs/install)
# Setup configuration
cp Caddyfile.example Caddyfile
# Edit Caddyfile with your domain
# Start Caddy
caddy run --config CaddyfileWhat Caddy handles:
- Automatic HTTPS (Let's Encrypt certificates)
- Static asset serving (bypasses the app)
- Compression (gzip/brotli)
- Security headers
For production, generate a SHA-256 hashed token:
gleam run -m setup token
# Copy output to homeserve.toml:
# token = "sha256:salt:hash"Users enter the plaintext token; only the hash is stored.
Mnesia requires an Erlang node name for persistent disk storage:
# Use this for production (data survives restarts)
ERL_FLAGS="-sname homeserve" gleam runWithout the node name, data is stored in RAM only (development mode).
Custom data directory:
[mnesia]
data_dir = "/var/lib/homeserve/mnesia"Ensure the directory exists and is writable.
Homeserve is built with modern, type-safe technologies:
| Component | Technology |
|---|---|
| Language | Gleam (compiles to Erlang/BEAM) |
| Database | Mnesia (built into Erlang) |
| Web Framework | Wisp |
| HTML/CSS | Lustre + Sketch |
| Markdown | Mork |
| Auth | SHA-256 token hashing |
| Rate Limiting | Application-layer (in-memory) |
- DEPLOYMENT.md - Detailed deployment guide with Docker
- Caddyfile.example - Example reverse proxy configuration
- AGENTS.md - Development guide for contributors
See LICENSE file.