A self-hosted personal portfolio built for makers, welders, and fabricators. Post your projects with photos, YouTube embeds, and full markdown writeups. Everything is managed through a private admin dashboard — no external CMS, no cloud accounts, no subscriptions.
- Home page — Editable hero, bio, and skills section. All content is changed from the dashboard with no code edits required.
- Projects — Full project list with tag-based filtering. Each project supports a thumbnail, photo gallery, YouTube embed, and a complete markdown writeup.
- Hub — A private bookmarks page for self-hosted services (Jellyfin, Nextcloud, Plex, Portainer, etc.) with auto-fetched favicons. Visible to any logged-in user. Each link has a green or red dot for whether it answers right now.
- Your apps — SkyBit, ComicOrbit, AstroFit and NitroLog sit at the top of the Hub with their own icons, at
localhoston their usual ports (7070, 7080, 7090, 7100).localhostonly opens on the server itself, so for phones change each address under Dashboard → Hub to the server's IP or domain, or hide the ones you don't run. - Sign in with Amethyst — turn on shared login under Dashboard → System and paste its secret into the other apps' admin pages. Their login pages then get a Sign in with Amethyst button that signs in the account with the same username. Apps on your Hub go straight through; any other address asks first.
- Animated cyberpunk UI — Circuit board background, neon glows, scan effects, and a glitch animation on the hero title.
- Fully responsive — Works on desktop and mobile. The admin dashboard has a slide-out drawer on small screens.
- System — update notice (checks Docker Hub once a day, sends nothing about you), shared login, backups, and your recent sign-ins with Sign out everywhere else.
- Backups — a copy of the database every night (the last 7, in
/data/backups), plus Download backup (database and uploaded pictures in one.tar) and restore from a file or a saved copy. A copy is saved before every restore, so it can be undone. - Projects — Create, edit, and delete projects. Upload thumbnail and gallery photos directly (no external hosting needed). YouTube URL auto-parses into an embed.
- Home Page Editor — Change your name, badge text, hero lines, bio, skills list, email, and GitHub link. Updates the live site instantly.
- Hub Manager — Add, edit, and reorder links to self-hosted services. Favicon is auto-fetched from the service URL.
- Users — Create additional accounts (admin or regular user). Only admins can access the dashboard; regular users can only access the Hub.
| Page | Public | Logged-in User | Admin |
|---|---|---|---|
| Home, Projects | ✓ | ✓ | ✓ |
| Hub | — | ✓ | ✓ |
| Dashboard | — | — | ✓ |
The recommended way to run Amethyst. No environment variables required.
docker run -d \
--name amethyst \
--restart always \
-p 3000:3000 \
-v amethyst-data:/data \
-v amethyst-uploads:/app/public/uploads \
rayderc/amethyst:latestThen open http://your-server:3000/setup to create your admin account.
services:
amethyst:
image: rayderc/amethyst:latest
container_name: amethyst
restart: always
ports:
- 3000:3000
volumes:
- ./data:/data
- ./uploads:/app/public/uploadsdocker compose up -dAll variables are optional. The app runs out of the box with no configuration.
| Variable | Default | Description |
|---|---|---|
SESSION_SECRET |
auto-generated | Cookie encryption key (min 32 chars). Recommended in production — keeps sessions alive across container restarts. |
DATABASE_PATH |
/data/amethyst.db |
Path to the SQLite database inside the container. |
SESSION_COOKIE_SECURE |
false |
Set to true when running behind a TLS-terminating reverse proxy (HTTPS). |
services:
amethyst:
image: rayderc/amethyst:latest
container_name: amethyst
restart: always
ports:
- 3000:3000
environment:
- SESSION_SECRET=your_random_secret_string_at_least_32_chars
- SESSION_COOKIE_SECURE=true
volumes:
- ./data:/data
- ./uploads:/app/public/uploads| Path | Contains |
|---|---|
/data |
SQLite database (amethyst.db) |
/app/public/uploads |
Uploaded images, served at /uploads/* |
Mount both as volumes so data survives container updates.
server {
listen 443 ssl;
server_name portfolio.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Set SESSION_COOKIE_SECURE=true when running behind HTTPS.
docker pull rayderc/amethyst:latest
docker compose down && docker compose up -dDatabase and uploads are preserved in volumes — nothing is lost on update.
Prerequisites: Node.js 20+, npm
git clone https://github.com/RayderC/Amethyst.git
cd Amethyst
npm install
npm run devOpen http://localhost:3000, then navigate to /setup to create your admin account.
- Start the app (Docker or
npm run dev) - Go to
/setup— create your admin account (only works before any user exists) - Log in at
/login - Dashboard → Home Page — set your name, bio, hero text, and skills
- Dashboard → Projects → New Project — add your first project
- Toggle "Feature on home page" to show it on the front page
- Dashboard → Hub — add links to your self-hosted services
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router + Pages API Routes) |
| Language | TypeScript 5 |
| Database | SQLite via better-sqlite3 |
| Auth | iron-session (encrypted cookie sessions) |
| Markdown | react-markdown + remark-gfm |
| Styling | Custom CSS with CSS custom properties |
| Container | Docker (multi-platform: linux/amd64, linux/arm64) |
app/
components/ Shared UI — Navigation, ProjectCard, MarkdownEditor,
CircuitBackground, FooterAuth
dashboard/ Protected admin pages — projects, home editor, hub, users
hub/ Private service links page (any logged-in user)
projects/ Public project list and detail pages
page.tsx Home page (server-rendered, reads config from DB)
layout.tsx Root layout — circuit canvas, dynamic metadata
pages/api/ API routes (Next.js Pages Router)
login / logout / user / register / setup
projects/ CRUD for portfolio projects
sessions/ CRUD for hub service links
site-config Home page content
users/ User management
favicon Favicon proxy (direct fetch → Google fallback)
lib/
db.ts SQLite connection, schema migrations, helpers
session.ts iron-session config
siteConfig.ts Default site content (overridden by DB values)
url.ts URL normalization helpers
public/uploads/ Uploaded images (gitignored, mounted as Docker volume)
MIT