2f373e683b
- Rewrite README with RetroBlog branding, config table, and two deploy paths (Docker Compose + bare-metal/systemd). - Enable Next.js standalone output for slim runtime images. - Add multi-stage Dockerfile (builds better-sqlite3 natively, runs as non-root, persists /app/data), docker-compose.yml, and .dockerignore. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
164 lines
4.2 KiB
Markdown
164 lines
4.2 KiB
Markdown
<div align="center">
|
|
|
|
# 🕹️ RetroBlog
|
|
|
|
**A self-hosted blog engine with swappable OS / game-console skins.**
|
|
|
|
Write Markdown posts, flip between retro themes (Windows, PS1, PS2, PS3, Wii,
|
|
NDS, Dreamcast, JV2002…), and run the whole thing from a single SQLite file.
|
|
|
|
</div>
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
- **Markdown posts** — create / edit / delete with slugs, tags, excerpts, dates.
|
|
- **Swappable skins** — pick the default theme; optionally let visitors switch.
|
|
- **Admin panel** — single-password login, signed session cookie.
|
|
- **Import / export** — JSON backup of settings and posts.
|
|
- **Zero external services** — data lives in one SQLite file (`data/blog.db`).
|
|
|
|
Stack: Next.js 16 (App Router) · React 19 · better-sqlite3 · marked.
|
|
|
|
---
|
|
|
|
## Quick start (development)
|
|
|
|
```bash
|
|
pnpm install
|
|
pnpm dev
|
|
```
|
|
|
|
Open <http://localhost:3000>. Admin panel at <http://localhost:3000/admin>
|
|
(default password `admin` in dev).
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
All config is environment variables. Copy `.env.example` to `.env` and edit.
|
|
|
|
| Variable | Required | Default | Purpose |
|
|
| ---------------------- | -------- | ---------------- | --------------------------------------------------------- |
|
|
| `ADMIN_PASSWORD` | **prod** | `admin` | Password for `/admin`. **Set this in production.** |
|
|
| `ADMIN_SESSION_SECRET` | **prod** | `ADMIN_PASSWORD` | Signs the admin session cookie. Use a long random string. |
|
|
| `PORT` | no | `3000` | Port the server listens on. |
|
|
|
|
Generate a secret:
|
|
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
**Data** is stored in `./data/blog.db` (created automatically). Back up that
|
|
directory to back up the whole site.
|
|
|
|
---
|
|
|
|
## Deploy — Docker (recommended)
|
|
|
|
Needs Docker + the Compose plugin.
|
|
|
|
```bash
|
|
# 1. Set production secrets
|
|
cp .env.example .env
|
|
$EDITOR .env # set ADMIN_PASSWORD and ADMIN_SESSION_SECRET
|
|
|
|
# 2. Build and run
|
|
docker compose up -d --build
|
|
```
|
|
|
|
Site is live on <http://localhost:3000>. The database persists in the
|
|
`retroblog-data` Docker volume across rebuilds.
|
|
|
|
Common operations:
|
|
|
|
```bash
|
|
docker compose logs -f # tail logs
|
|
docker compose down # stop (keeps the data volume)
|
|
docker compose up -d --build # update after pulling new code
|
|
```
|
|
|
|
**Back up the database:**
|
|
|
|
```bash
|
|
docker compose exec retroblog sh -c 'cat /app/data/blog.db' > backup-$(date +%F).db
|
|
```
|
|
|
|
> Put a TLS-terminating reverse proxy (Caddy, nginx, Traefik) in front for
|
|
> HTTPS in production. RetroBlog speaks plain HTTP on `PORT`.
|
|
|
|
---
|
|
|
|
## Deploy — bare metal
|
|
|
|
Needs Node.js 22+ and `pnpm` (`corepack enable`). A C toolchain
|
|
(`build-essential`, `python3`) is required once, to compile better-sqlite3.
|
|
|
|
```bash
|
|
# 1. Install deps and build
|
|
pnpm install --frozen-lockfile
|
|
pnpm build
|
|
|
|
# 2. Set production secrets
|
|
export ADMIN_PASSWORD='your-strong-password'
|
|
export ADMIN_SESSION_SECRET="$(openssl rand -hex 32)"
|
|
|
|
# 3. Start
|
|
pnpm start # serves on PORT (default 3000)
|
|
```
|
|
|
|
### Run it as a service (systemd)
|
|
|
|
`/etc/systemd/system/retroblog.service`:
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=RetroBlog
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
WorkingDirectory=/opt/retroblog
|
|
ExecStart=/usr/bin/pnpm start
|
|
Restart=on-failure
|
|
Environment=NODE_ENV=production
|
|
Environment=PORT=3000
|
|
Environment=ADMIN_PASSWORD=your-strong-password
|
|
Environment=ADMIN_SESSION_SECRET=your-long-random-secret
|
|
User=www-data
|
|
Group=www-data
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now retroblog
|
|
```
|
|
|
|
The SQLite database lives in `WorkingDirectory/data/blog.db` — make sure the
|
|
service `User` can write there, and back up that file.
|
|
|
|
---
|
|
|
|
## Admin panel
|
|
|
|
Sign in at `/admin` with `ADMIN_PASSWORD`. From there:
|
|
|
|
- **Posts** — full create / edit / delete with Markdown bodies, slugs, tags, dates.
|
|
- **Settings** — branding (title, subtitle, footer, version), default theme for
|
|
new visitors, whether the public theme switcher is shown, and which skins it offers.
|
|
- **Import / export** — download a JSON backup of settings and/or posts, and
|
|
import one back (posts can replace or append).
|
|
|
|
All `/admin/*` routes are gated by middleware behind the signed session cookie.
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
See repository.
|