Lightweight markdown sharing service. Upload .md files via API or CLI, get a clean URL with beautifully rendered content. Supports single files and directory bundles with hierarchy. Dark/light theme, syntax highlighting, Google OAuth, storage quotas. AI-agent friendly. Self-hosted, no database — just Node.js and the filesystem.
npm install
cp .env.example .env # edit values
npm startOr with Docker:
docker compose up -dServer runs at http://localhost:3737.
Tested on fresh Ubuntu 22.04/24.04. Copy-paste the commands one block at a time.
ssh root@YOUR_SERVER_IPcurl -fsSL https://get.docker.com | shmkdir sharemd && cd sharemd
curl -O https://raw.githubusercontent.com/a2u/sharemd/main/docker-compose.prod.yml
curl -o .env https://raw.githubusercontent.com/a2u/sharemd/main/.env.example
mv docker-compose.prod.yml docker-compose.ymlNo git clone needed — the prebuilt image is pulled from ghcr.io/a2u/sharemd.
nano .envSet at minimum:
BASE_URL=https://share.yourdomain.com
SITE_DOMAIN=share.yourdomain.com
Save with Ctrl+O, Enter, then Ctrl+X.
Google OAuth is optional — leave GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET empty if you don't need web login (you can still upload via API using a token in data/users.json).
docker compose up -dCheck it's running:
curl http://localhost:3737/health
# → {"status":"ok","uptime":...}In your DNS provider, create an A record:
share.yourdomain.com → YOUR_SERVER_IP
Skip this step if you're using a different reverse proxy (Caddy, Traefik, etc.) or already have one set up.
apt update && apt install -y nginx certbot python3-certbot-nginxCreate /etc/nginx/sites-available/sharemd:
nano /etc/nginx/sites-available/sharemdPaste:
server {
server_name share.yourdomain.com;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:3737;
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;
}
}Enable it and issue a cert:
ln -s /etc/nginx/sites-available/sharemd /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d share.yourdomain.comDone. Open https://share.yourdomain.com in a browser.
docker compose logs -fNew versions are published to ghcr.io/a2u/sharemd automatically on every push to main and on version tags. To pull the latest and restart:
cd sharemd
docker compose pull
docker compose up -dYour data in ./data/ is not touched — it's on a host volume, so the container can be recreated without losing files or tokens.
Check which version is running:
curl http://localhost:3737/health
# → {"status":"ok","uptime":12,"version":"1.0.0"}The version number is also shown in the footer of the landing page.
To pin a specific version instead of always tracking latest, edit docker-compose.yml:
image: ghcr.io/a2u/sharemd:1.0.0Log in at https://your-instance/ and open /panel. Copy the install command shown there and run it once on any machine:
curl -fsSL "https://your-instance/install?token=shmd_tk_xxxx" | bashThis drops the sharemd binary into ~/.local/bin/sharemd and wires your shell (.bashrc / .zshrc) with the right token and URL. Needs curl and jq.
# Single file
sharemd article.md
# → https://share.example.com/article.md
# Directory
sharemd docs/
# → https://share.example.com/docsAll API endpoints require Authorization: Bearer <token> header. Token is in your /panel after Google login.
# Upload
curl -X POST https://share.example.com/api/upload \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SHAREMD_TOKEN" \
-d '{"content": "# Hello\nWorld", "filename": "hello.md"}'
# List files
curl https://share.example.com/api/files \
-H "Authorization: Bearer $SHAREMD_TOKEN"
# Delete
curl -X DELETE https://share.example.com/api/delete \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SHAREMD_TOKEN" \
-d '{"path": "hello.md"}'See docs/api.md for the full API reference.
- Server-side markdown rendering (markdown-it + highlight.js)
- Dark/light theme toggle (persisted in localStorage)
- Sticky header with clickable path breadcrumb
- Raw markdown view (
?raw) - In-page delete button (owner only) with confirmation modal
- Google OAuth login + auto-registration
- Registration allowlist by email/domain (
ALLOWED_EMAILS) - User panel with storage bar, file browser (live search + pagination), and one-line CLI installer
- One-liner install:
curl … | bashdrops the CLI with token pre-configured - Per-user storage quotas
- Directory uploads with hierarchy preserved
- Duplicate detection with overwrite prompt
- AI skill for agent integration
- Docker deployment with health checks and multi-arch GHCR image
| Variable | Default | Description |
|---|---|---|
PORT |
3737 |
Server port |
BASE_URL |
http://localhost:3737 |
Public URL for generated links |
DATA_DIR |
./data |
Where files are stored on disk |
SITE_DOMAIN |
sharemd |
Domain shown in header |
GOOGLE_CLIENT_ID |
— | Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
— | Google OAuth client secret |
ALLOWED_EMAILS |
— | Registration allowlist, comma-separated. @domain.com or full email. Empty = allow all |
ADMIN_EMAIL |
— | Admin contact shown on access-denied page |
npm test # 63 tests- Architecture — how it works under the hood
- API Reference — all endpoints with examples
- CLI Reference — command-line usage
- Deployment — Docker, reverse proxy, configuration
-
/ai-skillpage — renderskill.mdas HTML for agents to discover - Rate limiting
- File expiration / TTL — auto-delete shared files after N days
- Versioning — keep previous versions on overwrite,
?v=1access - AI formatting —
format: trueflag to auto-format raw text into clean markdown - Webhooks — trigger external URL on upload/delete events
- CI/CD — GitHub Actions for tests and Docker image builds
- Password-protected shares
MIT — Vitalii Rudnykh