8.4 KiB
markMyWords
A self-hostable Docker application for hosting and searching markdown files with optional password protection and encryption.
Features
- 🚀 Self-hosted: Run entirely on your own infrastructure
- 📦 Docker-ready: Simple Docker Compose setup
- 🔍 Full-text Search: Search across all markdown files
- 📄 Markdown Rendering: Beautiful HTML rendering with syntax highlighting
- 🔐 Encryption: Optional password-based file encryption
- 🛡️ Access Control: Password-protect individual files
- ⚡ Simple Setup: Just add files to the
content/directory
Quick Start
1. Setup Directory
cd markmywords
# Create necessary directories
mkdir -p content config data
2. Add Markdown Files
Copy your markdown files to the content/ directory:
cp /path/to/your/markdown/files/* ./content/
Organize with subdirectories as needed:
content/
├── README.md
├── docs/
│ ├── guide.md
│ └── tutorial.md
└── blog/
├── post1.md
└── post2.md
3. Run with Docker Compose
docker-compose up -d
The application will be available at http://localhost:5000
4. Access the Application
-
Main Page: http://localhost:5000
- Browse all files organized by directory
- Search across all markdown content
-
View File: Click on any markdown file to view as HTML
-
Encrypted Files: Files with
.md.encextension require password authentication -
Search: Full-text search across all unencrypted files
5. (Optional) Encrypt Files
Use the management script to encrypt sensitive files:
# Encrypt a file with a password
# File is automatically encrypted AND password-protected
python manage_content.py encrypt content/secret.md "mypassword"
# In browser: User enters password → file is decrypted and displayed
# Same password used for both encryption and browser access
See ENCRYPTION.md for more details.
File Management
Adding Content
Simply add markdown files to ./content/ and they appear automatically:
echo "# New Document" > content/new-file.md
The search index updates automatically when the app starts.
Directory Structure
Files are organized hierarchically in the UI:
content/
├── index.md → Shows as "index" in root
├── docs/
│ ├── guide.md → Shows as "docs > guide"
│ └── images/ → Images in subdirectories
│ └── diagram.png
└── archive/
└── old.md → Shows as "archive > old"
Supported Formats
- Markdown:
.md,.markdown - Encrypted Markdown:
.md.enc(password-protected, viewed in browser) - Images:
.png,.jpg,.jpeg,.gif,.webp(referenced in markdown) - Relative Paths: Images referenced with relative paths work correctly
Configuration
Docker Compose Configuration
The docker-compose.yml file manages:
- Port mapping (default 5000)
- Volume mounts for content and data
- Restart policies
- Encryption settings
To modify settings, edit docker-compose.yml:
services:
markmywords:
ports:
- "5000:5000" # Change port here if needed
volumes:
- ./content:/content:rw # Your markdown files
- ./config:/config:rw # Password/protection config
- ./data:/data:rw # Search index
environment:
ENCRYPTION_ENABLED: "true" # Enable/disable encryption
Environment Variables
# Flask secret key (REQUIRED for production)
export FLASK_SECRET_KEY="your-secure-random-key-here"
# Admin password for API operations (optional)
export MARKMYWORDS_ADMIN_PASSWORD="admin-password"
# Enable/disable file encryption feature
export ENCRYPTION_ENABLED="true"
API Endpoints
GET /- Main page with file browserGET /view/<filepath>- View markdown file as HTMLGET /image/<filepath>- Serve images from contentGET /api/search?q=<query>- Full-text searchGET /api/status- Application statusPOST /api/auth/<filepath>- Authenticate for protected filePOST /api/protect/<filepath>- Protect/unprotect files (admin only)
ports:
- "8080:5000" # Change external port to 8080
Advanced Configuration
SSH Repositories
For private repositories using SSH:
- Mount your SSH key:
volumes:
- ~/.ssh:/root/.ssh:ro
- ./config:/config:ro
- markmywords_data:/data
- Use SSH URL in configuration:
{
"private-repo": {
"url": "git@github.com:username/private-repo.git",
"enabled": true,
"schedule": "0 * * * *"
}
}
Custom Port
Edit docker-compose.yml:
ports:
- "3000:5000"
Persistent Data
The Docker volume markmywords_data stores:
- Cloned repositories (
/data/repos) - Search index (
/data/search_index)
To backup data:
docker-compose exec markmywords tar czf - /data > markmywords_backup.tar.gz
API Reference
GET /
Main page with repository list and search interface
GET /view//
View a markdown file as HTML
Parameters:
repo: Repository namepath: Path to markdown file within the repository
Example: /view/my-wiki/docs/getting-started.md
GET /api/search
Search across all markdown files
Query Parameters:
q: Search query (minimum 2 characters)
Response:
{
"results": [
{
"path": "repo-name/path/to/file.md",
"title": "File Title"
}
]
}
GET /api/status
Get application status and repository information
Response:
{
"status": "running",
"repositories": {
"repo-name": {
"cloned": true,
"last_modified": "2024-01-15T10:30:00"
}
},
"timestamp": "2024-01-15T11:00:00"
}
Troubleshooting
Repositories Not Updating
- Check configuration file syntax:
docker-compose exec markmywords cat /config/repositories.json
- View application logs:
docker-compose logs -f markmywords
- Verify git access:
docker-compose exec markmywords git clone <url> /tmp/test
Search Not Working
- Ensure markdown files are present:
docker-compose exec markmywords ls -la /data/repos/
- Check search index:
docker-compose exec markmywords ls -la /data/search_index/
- Rebuild search index by restarting:
docker-compose restart markmywords
Port Already in Use
Change the port in docker-compose.yml:
ports:
- "5001:5000"
Then run:
docker-compose up -d
Permissions
- Git operations require read access to repositories
- For private repositories, ensure proper SSH key setup
- Web service runs as root inside container (safe for self-hosted)
Security Considerations
- Only use HTTPS git URLs or secure SSH keys
- Mount SSH keys as read-only
- Use firewall rules to restrict access
- Consider running behind a reverse proxy (nginx)
- No authentication built-in; add via reverse proxy if needed
Performance
- Search uses Whoosh full-text index
- Index built on startup and updated after each pull
- Markdown rendering uses Python markdown library with extensions
Architecture
┌─────────────────────────────────┐
│ markMyWords │
│ (Flask + APScheduler) │
├─────────────────────────────────┤
│ Scheduled Git Pulls (cron) │
│ Markdown → HTML Conversion │
│ Full-text Search (Whoosh) │
├─────────────────────────────────┤
│ Docker Volume │
│ - Cloned Repositories │
│ - Search Index │
└─────────────────────────────────┘
Development
Local Setup
# Create virtual environment
python -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Create config
mkdir -p config
cp config/repositories.json.example config/repositories.json
# Run locally
python app.py
Requirements
- Python 3.11+
- Flask 3.0+
- APScheduler 3.10+
- markdown 3.5+
- Whoosh 2.7+
License
MIT License - See LICENSE file for details
Contributing
Contributions welcome! Please submit issues and pull requests.
Support
For issues, questions, or suggestions, please open an issue on GitHub.