Flask App Deployment Guide - mikr.us VPS
Project Structure
project/
├── app/
│ ├── __init__.py
│ ├── routes.py # Main Flask routes
│ ├── models.py # Database operations
│ ├── raindrop.py # External API calls
│ └── templates/
│ ├── base.html
│ ├── index.html
│ └── tags.html
├── static/
│ └── css/
│ └── style.css
├── .env # Environment variables
├── requirements.txt
└── README.md
Common Issues & Solutions
1. Duplicate Module Files
Problem: Having models.py in both root and app/ causes import confusion.
Solution: Keep one structure:
app/models.py- main modules- No duplicate files in root
2. Relative Imports Fail When Run Directly
Problem: from .models import ... fails with python routes.py
Solution: Use sys.path and absolute imports:
import sys
import os
sys.path.insert(0, os.path.dirname(__file__))
from models import ...
from raindrop import ...
3. IPv6 Binding for mikr.us
Problem: App doesn’t work with mikr.us subdomain.
Solution: Listen on IPv6:
# In routes.py
if __name__ == '__main__':
host = os.environ.get('HOST', '::') # IPv6 for mikr.us
port = int(os.environ.get('PORT', 5000))
app.run(host=host, port=port)
Run with:
HOST='::' PORT=5010 python app/routes.py
4. Database Schema Bug
Problem: Storing wrong ID in join tables.
Bad:
upsert_bookmark(raindrop_id, ...)
sync_tags(raindrop_id, tags) # Wrong! Uses raindrop_id
Good:
upsert_bookmark(raindrop_id, ...)
bookmark_db_id = get_bookmark_id(raindrop_id) # Get internal ID
sync_tags(bookmark_db_id, tags)
Deployment Steps
1. Prepare Files
# Fix imports in all files
# Ensure sys.path points to app/ directory
# Test locally
cd project && python app/routes.py
2. Sync to VPS
rsync -avz -e "ssh -p 10212 -i ~/.ssh/mikrus" \
app/ .env requirements.txt \
user@cezary212.mikrus.xyz:/path/to/project/
3. Install Dependencies
ssh -p 10212 -i ~/.ssh/mikrus user@cezary212.mikrus.xyz \
"cd /path/to/project && pip install -r requirements.txt"
4. Run App
ssh -p 10212 -i ~/.ssh/mikrus user@cezary212.mikrus.xyz \
"cd /path/to/project && HOST='::' PORT=5010 nohup python app/routes.py > /tmp/flask.log 2>&1 &"
Subdomain Setup on mikr.us
mikr.us provides free subdomains that point to your app’s port.
Option 1: Command Line (domena)
Random subdomain:
domena 5010
# Creates something like: c212-5010.byst.re
Custom subdomain:
domena myapp.byst.re 5010
# Creates: myapp.byst.re -> port 5010
For dedicated domains (tojest.dev, bieda.it, etc.):
domena raindrop.tojest.dev 5010
Option 2: Via mikr.us Panel
- Go to https://mikr.us/panel/?a=domain
- Click “Dodaj subdomenę” (Add subdomain)
- Fill in:
- Nazwa:
myapp - Domena:
tojest.dev(or choose from available) - Port:
5010 - Protokół: HTTP or HTTPS
- Nazwa:
- Click “Dodaj”
Available Domain Options
| Domain | Use Case |
|---|---|
byst.re |
Quick test apps |
wykr.es |
Apps on assigned IPv4 ports |
mikrus.cloud |
Apps on any IPv6 port |
tojest.dev |
Your dedicated domain |
bieda.it |
Your dedicated domain |
Dynamic format (automatic):
{server}-{port}.wykr.es- e.g.,cezary212-5010.wykr.es{server}-{port}.mikrus.cloud- e.g.,cezary212-5010.mikrus.cloud
Subdomain Requirements
- App must listen on IPv6 (
::or:::or[::]), not127.0.0.1or0.0.0.0 - Port must be open and app running before creating subdomain
- App must not return 50x errors
Verify Subdomain Created
# Check from VPS
host myapp.tojest.dev
# Should return: myapp.tojest.dev has address 37.27.69.181 (your VPS IP)
# Test from local machine
curl -v http://myapp.tojest.dev/
Delete Subdomain
Via panel or ask mikr.us support.
Troubleshooting Subdomains
| Problem | Solution |
|---|---|
| Subdomain not created | App must listen on IPv6 (::) |
| 50x error returned | Check app logs, fix error first |
| Connection refused | App not running or wrong port |
| Wrong IP in DNS | Wait for propagation (a few minutes) |
| SSL/HTTPS issues | Select HTTPS in panel, or use HTTP only |
Configure App for Subdomain (Optional)
If your app needs to know its domain (for links, redirects, analytics, etc.):
Set in .env:
echo 'APP_URL=https://myapp.tojest.dev' >> .env
Use in routes.py:
import os
APP_URL = os.environ.get('APP_URL', 'http://localhost:5010')
Use in templates for absolute URLs:
<a href="{{ app_url }}/tag/sometag">Share this tag</a>
Or detect from request headers:
from flask import request, g
@app.before_request
def set_domain():
g.domain = request.headers.get('Host', 'localhost:5010')
g.app_url = f"{request.scheme}://{g.domain}"
Verify
# Test from local machine
curl http://myapp.byst.re/
# Test health endpoint
curl http://localhost:5010/health
# Check subdomain resolves
host myapp.tojest.dev
Docker Deployment (Alternative)
Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ .
ENV HOST=::
ENV PORT=5000
CMD ["python", "app/routes.py"]
Build & Run
docker build -t my-flask-app .
docker run -d -p 5010:5000 --restart unless-stopped --name my-app my-flask-app
# Create subdomain
domena myapp.byst.re 5010
Managing the App
Restart
pkill -f 'python app/routes' 2>/dev/null
cd /path/to/project && HOST='::' PORT=5010 nohup python app/routes.py > /tmp/flask.log 2>&1 &
View Logs
ssh ... "cat /tmp/flask.log"
ssh ... "tail -f /tmp/flask.log"
Check Status
curl http://localhost:5010/health
Trigger Sync (if needed)
curl -X POST http://localhost:5010/api/sync
Useful Commands
# Check if running
ps aux | grep 'python app/routes'
lsof -i :5010
# Test locally
curl http://localhost:5010/
# Test with specific host header
curl -H 'Host: myapp.byst.re' http://127.0.0.1/
# Kill all python processes (careful!)
pkill -9 python
Troubleshooting
404 from nginx
- Check app is running:
ps aux | grep routes - Check port:
lsof -i :5010 - Check logs:
cat /tmp/flask.log
Subdomain not working
- App must listen on IPv6 (
::), not IPv4 - Check:
lsof -i :5010should show*:5010or[::]:5010 - Restart with
HOST='::'
Import errors
- Check sys.path in routes.py
- Ensure no duplicate
.pyfiles - Run from project root
Database issues
- Check
bookmarks.dbexists - Verify schema:
sqlite3 app/bookmarks.db ".schema"