Manage Transactions Daily
A lightweight, self-hosted bookkeeping tool for UK sole traders and the self-employed.
Features • Quick Start • Local Development • Self-Hosted Deployment • Documentation
MTDify is a Django-based bookkeeping application designed specifically for UK sole traders and self-employed individuals. It provides a simple, privacy-focused way to track income, expenses, and VAT—all while keeping your data under your complete control.
Key Principles:
- You own your data — Everything is stored locally in SQLite
- Privacy first — No cloud dependencies, no data sharing
- Simple and focused — Built for sole traders, not enterprise accounting
- UK tax year aware — Automatically handles April-to-April tax years and UK dates.
- Transaction Management — Track income and expenses with categorisation
- VAT Calculations — Automatic VAT rate application and tracking
- Quarterly Summaries — View your finances by UK tax quarters (Q1-Q4)
- Tax Year Reports — Year-to-date profit/loss statements
- CSV Exports — Export all your data when needed
- Receipt Storage — Attach receipt images to expenses
- Recurring Entries — Set up automatic monthly transactions
- Daily Backups — Automatic database backups - backups appear at /app/data/db/backups/ inside the container
- Multi-user Ready — Support for multiple user accounts
MTDify uses Adminita, a clean and modern Django admin theme. Adminita provides a new look for the Django admin panel with improved typography, spacing, and visual hierarchy.
Choose your preferred deployment method:
| Method | Best For | Difficulty |
|---|---|---|
| Local Development | Testing, development, personal use on your machine | Easy |
| Self-Hosted (Docker) | Production server deployment | Medium |
| Self-Hosted (Manual) | VPS/dedicated server without Docker | Medium |
Run MTDify locally on your machine for development, testing, or personal use. This method runs the Django development server which is perfect for single-user scenarios.
- Python 3.11 or higher
- pip (Python package manager)
- Git
-
Clone the repository
git clone https://github.com/djangify/mtdify.git cd mtdify -
Create a virtual environment
python -m venv .venv # On Windows: .venv\Scripts\activate # On macOS/Linux: source .venv/bin/activate
-
Install dependencies
pip install -r requirements.txt
-
Create environment file
cp .env.example .env
Edit
.envand set your configuration (see Configuration below). -
Initialize the database
python manage.py migrate
-
Create a superuser account
python manage.py createsuperuser
Or create a default demo user:
python manage.py create_default_user
This creates a user with email
demo@example.comand passworddemo123. -
Collect static files
python manage.py collectstatic --noinput
-
Run the development server
python manage.py runserver
-
Access the application
Open your browser and navigate to:
- Application: http://127.0.0.1:8000
- Admin Panel: http://127.0.0.1:8000/admin
python manage.py runserver 0.0.0.0:8080To access MTDify from other devices (phone, tablet, other computers):
-
Add your local IP to
ALLOWED_HOSTSin.env:ALLOWED_HOSTS=localhost,127.0.0.1,192.168.1.100 -
Run the server binding to all interfaces:
python manage.py runserver 0.0.0.0:8000
-
Access from other devices at
http://192.168.1.100:8000(use your actual local IP).
Deploy MTDify on your own server for production use with multiple users or remote access.
The recommended way to deploy MTDify in production.
- Docker and Docker Compose installed
- A domain name (optional, for HTTPS)
-
Clone the repository
git clone https://github.com/djangify/mtdify.git cd mtdify -
Create environment file
cp .env.example .env
Edit
.envwith production settings:DEBUG=False SECRET_KEY=your-very-long-random-secret-key-here ALLOWED_HOSTS=your-domain.com,www.your-domain.com
Generate a secure secret key:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())" -
Build and start the container
docker-compose up -d --build
-
Run initial setup
# Run migrations docker-compose exec web python manage.py migrate # Create superuser docker-compose exec web python manage.py createsuperuser # Collect static files docker-compose exec web python manage.py collectstatic --noinput
-
Access the application
- HTTP: http://your-server-ip:8000
- With reverse proxy: https://your-domain.com
# Start services
docker-compose up -d
# Stop services
docker-compose down
# View logs
docker-compose logs -f web
# Run Django management commands
docker-compose exec web python manage.py <command>
# Restart services
docker-compose restart
# Rebuild after code changes
docker-compose up -d --buildData is persisted in Docker volumes:
| Volume | Purpose |
|---|---|
mtdify_data |
SQLite database and media files |
mtdify_static |
Collected static files |
To backup your data:
# Backup database
docker-compose exec web cp /app/data/db/db.sqlite3 /app/data/db/backup-$(date +%Y%m%d).sqlite3
# Copy backup to host
docker cp mtdify_web_1:/app/data/db/backup-*.sqlite3 ./backups/Deploy without Docker on a VPS or dedicated server.
- Python 3.11+
- A web server (Nginx recommended)
- Supervisor or systemd for process management
-
Clone and configure
git clone https://github.com/djangify/mtdify.git cd mtdify python -m venv .venv source .venv/bin/activate pip install -r requirements.txt
-
Configure environment
cp .env.example .env # Edit .env with production settings -
Initialize application
python manage.py migrate python manage.py createsuperuser python manage.py collectstatic --noinput
-
Create systemd service
Create
/etc/systemd/system/mtdify.service:[Unit] Description=MTDify Gunicorn Daemon After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/path/to/mtdify Environment="PATH=/path/to/mtdify/.venv/bin" ExecStart=/path/to/mtdify/.venv/bin/gunicorn \ --workers 3 \ --bind unix:/path/to/mtdify/mtdify.sock \ mtdify.wsgi:application [Install] WantedBy=multi-user.target
Enable and start:
sudo systemctl enable mtdify sudo systemctl start mtdify -
Configure Nginx
Create
/etc/nginx/sites-available/mtdify:server { listen 80; server_name your-domain.com; location /static/ { alias /path/to/mtdify/staticfiles/; } location /media/ { alias /path/to/mtdify/data/media/; } location / { proxy_pass http://unix:/path/to/mtdify/mtdify.sock; 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 the site:
sudo ln -s /etc/nginx/sites-available/mtdify /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx
-
Set up HTTPS (recommended)
sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your-domain.com
Create a .env file in the project root with the following variables:
| Variable | Description | Default | Required |
|---|---|---|---|
DEBUG |
Enable debug mode | True |
No |
SECRET_KEY |
Django secret key | change-me-in-production |
Yes (production) |
ALLOWED_HOSTS |
Comma-separated list of allowed hosts | localhost,127.0.0.1 |
Yes (production) |
DEBUG=True
SECRET_KEY=dev-secret-key-not-for-production
ALLOWED_HOSTS=localhost,127.0.0.1DEBUG=False
SECRET_KEY=your-super-long-random-secret-key-minimum-50-characters
ALLOWED_HOSTS=mtdify.yourdomain.com,www.mtdify.yourdomain.comWhen DEBUG=False, the following security features are automatically enabled:
- HTTPS redirect (
SECURE_SSL_REDIRECT) - Secure session cookies (
SESSION_COOKIE_SECURE) - Secure CSRF cookies (
CSRF_COOKIE_SECURE) - CSRF trusted origins based on
ALLOWED_HOSTS
Important: Always use HTTPS in production and ensure your reverse proxy sets the X-Forwarded-Proto header.
mtdify/
├── accounts/ # User authentication and management
├── bookkeeping/ # Core transaction tracking
│ ├── models.py # Income, Expense, Category, RecurringEntry
│ ├── views/ # Transaction and report views
│ └── utils.py # Tax year utilities
├── business/ # Business profile management
├── mtdify/ # Django project settings
│ ├── settings.py # Application configuration
│ ├── urls.py # URL routing
│ └── views.py # Dashboard and home views
├── templates/ # HTML templates
├── static/ # CSS, JS, images
├── data/ # SQLite database and media (gitignored)
│ ├── db/ # Database files
│ └── media/ # Uploaded receipts
├── requirements.txt # Python dependencies
├── manage.py # Django management script
├── Dockerfile # Docker image definition
└── docker-compose.yml # Docker Compose configuration
- Log in with your created account
- Create a Business — Navigate to Business → Add Business
- Set your tax year — The system defaults to the current UK tax year
- Start tracking — Add income and expenses from the dashboard
When you generate printable reports, MTDify displays your email address by default. To include your full name and business name on reports:
- Go to Admin Panel (
/admin) - Navigate to Users and select your account
- Add your First Name and Last Name
- Ensure you've created a Business with your business name
Reports will then display your name, email, and business name in the header — useful for professional record-keeping.
Income:
- Navigate to Bookkeeping → Add Income
- Enter date, description, amount, and category
- Optionally add client name and invoice number
Expenses:
- Navigate to Bookkeeping → Add Expense
- Enter date, description, amount, and category
- Set VAT rate (0%, 5%, or 20%)
- Upload receipt image (optional)
Access reports from the Dashboard:
- Quarterly Summary — View income, expenses, and profit by quarter
- Category Breakdown — See spending by category
- CSV Export — Download data for your accountant
MTDify follows the UK tax year (6 April – 5 April):
- Q1: April – June
- Q2: July – September
- Q3: October – December
- Q4: January – March
Switch between tax years using the dropdown in the navigation bar.
MTDify does not currently expose a public API. All interactions are through the web interface.
"CSRF verification failed"
- Ensure
ALLOWED_HOSTSincludes your domain - Check that your reverse proxy passes the
X-Forwarded-Protoheader
Static files not loading
- Run
python manage.py collectstatic --noinput - Check that WhiteNoise is properly configured (it is by default)
Database locked errors
- SQLite can have issues with concurrent writes
- For heavy multi-user scenarios, consider PostgreSQL
Permission denied on data directory
- Ensure the application user has write access to
data/directory - In Docker, check volume permissions
- Documentation:
- Issues: https://github.com/djangify/mtdify/issues
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
- Fork the repository
- Clone your fork
- Create a virtual environment and install dependencies
- Create a branch for your feature
- Make your changes
- Run tests (when available)
- Submit a pull request
This project is licensed under the MIT License. See the LICENSE file for details.
Built with:
- Django — The web framework
- django-allauth — Authentication
- WhiteNoise — Static file serving
- Gunicorn — WSGI server
- Tailwind CSS — Styling
MTDify is provided "as is" without warranty of any kind. If you choose to self-host this software, you do so at your own risk. The developer accepts no responsibility for data loss, inaccuracies, or any issues arising from its use. Always maintain your own backups and verify calculations independently.
Made for UK self employed and sole traders
Introducing Manage Transactions Daily
Maintained by Diane Corriette
