Skip to main content

Lightweight self-hosted collaboration platform for messaging

Project description

MiniMost


License: MIT Python: 3.6+ Built with Flask Database: SQLite PWA Code style: black Code style: prettier Build Bandit Semgrep pip-audit CodeQL Documentation Status Quality Gate Maintainability Reliability Security Rating

MiniMost is a lightweight, self-hosted chat platform built for private networks. It runs entirely on Python and SQLite — no external database, no root access, no infrastructure required. Just Flask and a browser.


Screenshots

Login page The login page — clean, minimal, and version-tagged.

Chat interface The main chat interface — channel list, direct messages, inline image attachments, and real-time typing indicators.

Message search Full-text message search with highlighted results.


Features

  • Sign up in seconds — pick a username and password and you're in; no email verification, no waiting. Changed your mind? Accounts can be deleted just as quickly.
  • 🔒 Your password stays secret — passwords are hashed and salted (PBKDF2) with enforced complexity, so not even the server admin can see what you typed.
  • 📁 Messages are read-protected — the message database is locked down on disk, so your conversations aren't sitting around for anyone to open.
  • 💬 Channels & direct messages — public channels (configurable), invite-only private channels you can rename and manage, and one-on-one or group DMs that keep going so anyone can catch up on what they missed.
  • 🔍 Every message is saved & searchable — nothing disappears, and full-text search finds any message in an instant. New users see the history from day one.
  • 📷 Images show up inline — paste, drag-and-drop, or use the paperclip button to attach any file. Images embed right in the conversation; everything else becomes a download link.
  • ✏️ Replies, edits & reactions — quote any message to reply in context, edit or delete your own messages, and react with emoji. Every change syncs to everyone in real time.
  • 👀 Presence, typing & @mentions — see who's online, watch the typing dots, and ping the right person with an @mention (or @everyone). Mentions alert you with a sound and desktop notification even while the tab is focused, and read receipts show who's seen your messages.
  • 📞 Voice, video & screen sharing — jump on a call or share your screen right from the chat in any DM or private channel. Calls grow into group calls with the in-call "Add person" button, and participant tiles reflow automatically with live speaking indicators.
  • 🛡️ LAN-first, peer-to-peer media — call and screen-share media is sent directly between participants over WebRTC and never touches the server. A small bundled STUN server means there's nothing external to configure — it even works on fully air-gapped LANs.
  • 🎨 Make it yours — upload a profile avatar (or use the default initials), pick a display-name colour, and hide DM threads you're done with (they reappear if a new message arrives).
  • 🔔 Notifications, your way — desktop and sound alerts are configurable per session and mutable with one click.
  • 🖥️ Works everywhere — runs right in your browser on Linux and Windows, with a touch-friendly, mobile-responsive layout, a drawer sidebar, and pinch-to-zoom font sizing.
  • 🌙 Dark theme — easy on the eyes.
  • 🧹 Tidies up after itself — a background thread automatically removes old messages and attachments past a configurable age (default: 770 days for messages, 30 for files) and trims the oldest content once the database or uploads grow past a size cap. Runs every 24 hours, no cron job required.
  • 🗑️ Account self-deletion — delete your own account from Settings. A soft delete re-attributes your messages to "Deleted User" while preserving chat history; a hard delete removes every message you ever sent. Both require password confirmation.
  • 🔑 Admin password reset — generate a one-time, time-limited reset URL from the CLI; the user gets an in-app notification when a reset is requested.

Free, MIT licensed, and fully auditable

MiniMost is released under the MIT License — free to use, free to modify, and free to redistribute, with no strings attached.

  • 💯 Truly free — there's no license to set up, no activation key, no seat count to track, and no paid tier hiding features behind a paywall.
  • 👥 No user limit — invite your whole team, your whole company, or your whole LAN. The software never counts heads or asks you to upgrade.
  • 🔍 Every line is open to inspect & audit — all of the code is right here in this repository. Unlike "open core" products that ship a stripped-down public version while keeping the real functionality closed, there is no hidden enterprise edition and nothing held back. What you read is exactly what you run.

Requirements

  • Python 3.6+
  • Flask (pip install flask)

That's it!


Installation

From source

git clone https://github.com/SamuelDonovan/minimost.git
cd minimost
pip install -e .

From wheel (latest build)

Download the latest .whl from the releases page, then:

pip install minimost-*.whl

Dependencies only (no internet access)

Download the Flask wheel and its dependencies, then:

pip install --user *.whl

Running

minimost

Or without installing:

python3 -m minimost

On first run MiniMost automatically generates a self-signed TLS certificate (cert.pem / key.pem) in pure Python (no openssl binary required) and serves over HTTPS. The server starts at https://127.0.0.1:5000 by default. Use --host and --port to change the bind address:

# Listen on all interfaces (accessible from other machines on the network)
minimost --host 0.0.0.0

# Listen on a specific IP and port
minimost --host 192.168.1.10 --port 8080

To reach the server from another machine, navigate to https://<server-ip>:<port> in a browser. The generated certificate is self-signed, so your browser will show a security warning — add a permanent exception to dismiss it.

Note: HTTPS is required for voice and video calling (browsers only allow camera/microphone and WebRTC access in secure contexts). The certificate is generated in pure Python (standard library only — no openssl binary required), so this works the same on Linux, macOS, and Windows.

Note: Calls and screen shares connect peers directly over WebRTC. For this to work, peers must be on the same LAN/subnet and able to reach each other (and the bundled STUN server on UDP 3478, configurable via stun_port in settings.json) over UDP. No public STUN/TURN server is used, so calls work on air-gapped networks, but they will not traverse the public internet or connect peers on different subnets.

Ports & firewall

Port Protocol Open on Required for Notes
6767 (Gunicorn) / 5000 (dev) TCP Server (inbound) Everything — web UI, chat, file uploads, call signaling The only port needed for text chat. Set via --port or gunicorn.conf.py.
3478 UDP Server (inbound) Voice/video calls & screen sharing Bundled STUN server. Set via stun_port in settings.json.
Ephemeral UDP (Linux 3276860999) UDP Between clients WebRTC media (audio/video/screen) Peer-to-peer, browser-chosen; only matters if clients run host firewalls or sit on segmented LANs.

No outbound internet access is required (no external database, no public STUN/TURN) — MiniMost runs fully air-gapped. There is no TURN relay, so peers must be on the same LAN/subnet, and SQLite is file-based so there is no database port. See the deployment docs for an administrator setup checklist plus firewalld / ufw examples.

Production deployment

The built-in Flask server is suitable for development and small private networks. For a more robust deployment, run MiniMost behind a WSGI server such as Gunicorn:

pip install gunicorn

# From an installed package (wheel or `pip install -e .`) — uses the config
# module shipped inside the package, so no source checkout is required:
gunicorn "minimost:create_app()" -c python:minimost.gunicorn_conf

# From a source checkout — equivalent thin shim that re-exports the same config:
gunicorn "minimost:create_app()" --config gunicorn.conf.py

Both forms handle automatic TLS certificate generation before Gunicorn starts. The bundled gunicorn.conf.py is a thin shim around the packaged minimost.gunicorn_conf module, so the two are interchangeable.

Configuration

Edit settings.json (bundled with the package at src/minimost/settings.json) to configure MiniMost. All keys are optional and fall back to sensible defaults if omitted:

{
  "channels": ["general", "software", "firmware", "systems", "off-topic"],
  "image_retention_days": 30,
  "file_retention_days": 30,
  "message_retention_days": 770,
  "max_message_db_size_mb": 1024,
  "max_upload_dir_size_mb": 2048,
  "max_upload_size_mb": 25,
  "max_avatar_size_mb": 5,
  "stun_port": 3478,
  "max_login_attempts": 5,
  "lockout_duration_minutes": 15
}

MiniMost bounds disk usage two complementary ways: age-based retention deletes content once it gets old enough, and size-based caps delete the oldest content once a store grows past a limit (whichever triggers first). Note the difference between the two upload settings: max_upload_size_mb is a per-file ceiling enforced at upload time, while max_upload_dir_size_mb caps the total size of all stored attachments.

Key Default Description
channels ["general"] Public channel names shown in the sidebar. Restart required.
image_retention_days 30 Days before image attachments are auto-deleted. No restart needed.
file_retention_days 30 Days before non-image attachments are auto-deleted. No restart needed.
message_retention_days 770 Days before messages are permanently deleted from the database. No restart needed.
max_message_db_size_mb 1024 Total size cap (MB) for the message database users/messages.db; oldest messages are deleted when exceeded. 0 disables. No restart needed.
max_upload_dir_size_mb 2048 Total size cap (MB) for the uploads/ attachment directory; oldest files are deleted when exceeded. 0 disables. No restart needed.
max_upload_size_mb 25 Maximum size in MB for a single file attachment, rejected at upload time. Restart required.
max_avatar_size_mb 5 Maximum size in MB for a profile avatar upload. Restart required.
stun_port 3478 UDP port for the bundled STUN server used by WebRTC calls/screen share. Must be 165535. Restart required.
max_login_attempts 5 Consecutive failed logins before an account is locked. Set to 0 to disable lockout. No restart needed.
lockout_duration_minutes 15 How long an account stays locked after too many failed logins. No restart needed.

Keyboard Shortcuts

Messaging

Key Action
Enter Send message
Shift + Enter New line
@ Open the mention dropdown (/ navigate, Enter/Tab accept)
Esc Unfocus input / close menus

Navigation

Key Action
i Focus message input
o Start a new DM
/ or f Search messages
j / k Scroll down / up
d / u Scroll down / up (2×)
G Jump to bottom
g Jump to top
Ctrl + J / Ctrl + K Next / previous channel
? Open help menu

Visual Mode

Press v in normal mode (input unfocused) to enter visual mode, which highlights a single message for direct keyboard actions. The topbar shows -- visual -- while active.

Key Action
v Enter visual mode (selects most recent message)
j / Move selection to next (newer) message
k / Move selection to previous (older) message
d Delete highlighted message
c Edit highlighted message
o Reply to highlighted message
y Copy highlighted message text to clipboard
e React to highlighted message with emoji
Esc Exit visual mode

Text Formatting

Key Action
Ctrl + B Bold
Ctrl + I Italic
Ctrl + U Underline
Ctrl + S Strikethrough

All formatting uses Markdown syntax (underline uses __text__). Shortcuts work on selected text or toggle the format on/off while typing.

Media & Display

  • Attach files — paste from clipboard, drag onto the message box, or use the paperclip button; any file type is accepted
  • Images are displayed inline; all other file types appear as a download link showing the original filename
  • File size limit — configurable per-upload maximum (default 25 MB); the browser warns before attempting an oversized upload
  • Font size — pinch (mobile) or Ctrl + Scroll (desktop); preference is saved across sessions

Security

  • Passwords are salted and hashed with PBKDF2 via Werkzeug — no plaintext or bare SHA-256 storage
  • Password complexity is enforced on both frontend and backend (8+ characters, uppercase, number, special character)
  • All database queries use parameterized statements — no SQL injection surface
  • Messages live in a single shared SQLite database; every read enforces channel access control (public channels, private-channel membership, and DM participation)
  • SAST scanning via Bandit, Semgrep, CodeQL, and SonarCloud in CI
  • Dependency vulnerabilities audited on every push with pip-audit
  • Flask debug mode is disabled in production

FAQ

Are messages encrypted?

Messages are not end-to-end encrypted. All data lives in SQLite files on the server filesystem. These files are not world-readable, but an administrator with filesystem access can read/audit them. Treat this as an internal LAN tool, not a secure messenger.

What if a user forgets their password?

An administrator can generate a one-time reset link from the command line:

minimost reset-password <username>

This prints a URL valid for 60 minutes (configurable with --expires) and sends the user an in-app notification via a system DM. Share the URL with the user through another channel (email, phone, etc.). When they open it, they can set a new password. The link expires after use or when the timer runs out — whichever comes first. Run minimost reset-password --help for all options.

Does it have feature X from Slack/Discord/Mattermost?

Probably not. Those products have hundreds of engineers and years of development. MiniMost is intentionally minimal — the goal is something that runs anywhere with zero infrastructure overhead.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

minimost-0.0.1-py3-none-any.whl (2.0 MB view details)

Uploaded Python 3

File details

Details for the file minimost-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: minimost-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 2.0 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for minimost-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ef01db4e6cb0149dcb6aa5c8a18ada73c1ffb63bf33692e15d7ac5cecc3c9c3d
MD5 19da49c0ccc82c1b644ebd32a33ad1b9
BLAKE2b-256 9c77ac81541a225602db4f360aafebc3282f32b988924f40548b56348d100562

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page