Your memories, beautifully preserved. Fully private. Fully yours.
Memora is a self-hosted photo and video management application built for privacy-first users who want complete control over their media. Deploy it on your own server, NAS, or Raspberry Pi in under a minute.
amd64 and arm64 (Raspberry Pi, Apple Silicon, AWS Graviton)docker run and go; secrets are auto-generateddocker run -d \
--name memora \
-p 8000:8000 \
-v memora_uploads:/app/uploads \
-v memora_db:/app/db_data \
-v memora_data:/app/data \
--restart unless-stopped \
certyiknofetch/memora:latest
Open http://localhost:8000 -- the first registered user automatically becomes the admin.
services:
memora:
image: certyiknofetch/memora:latest
container_name: memora
ports:
- "8000:8000"
volumes:
- ./uploads:/app/uploads
- ./db_data:/app/db_data
- ./data:/app/data
restart: unless-stopped
docker compose up -d
| Feature | Description |
|---|---|
| Photo & Video Upload | Drag-and-drop uploads; supports photos up to 50 MB and videos up to 2 GB |
| Format Support | JPG, PNG, GIF, WebP, HEIC, HEIF, AVIF, BMP, TIFF, MP4, MOV, AVI, MKV, WebM, M4V, 3GP |
| Auto Thumbnails | Automatic JPEG thumbnail generation for all uploaded images |
| Albums | Organize media into albums with custom cover photos and drag-to-reorder |
| Favorites | Star your best shots for quick access |
| Search & Filters | Filter by name, media type (photo/video), and date range |
| Built-in Editor | Crop, rotate, apply filters, draw, and add text -- right in the browser |
| Public Sharing | Share individual photos or entire albums via secure access links |
| Public Gallery | Optional public-facing gallery page for shared content |
| Feature | Description |
|---|---|
| JWT + HttpOnly Cookies | Tokens stored in secure, HttpOnly cookies -- not accessible to JavaScript |
| Two-Factor Auth (TOTP) | Optional 2FA with any authenticator app (Google Authenticator, Authy, etc.) |
| TOTP Replay Protection | Each TOTP code can only be used once within its validity window |
| Security Questions | Three encrypted security questions for account recovery |
| Bcrypt Password Hashing | Industry-standard password hashing with automatic salting |
| Password Policy | Enforced minimum 8 characters with uppercase, lowercase, digit, and special character |
| Rate Limiting | Per-IP and per-account lockout after failed login attempts |
| CSRF Protection | Custom header requirement + Origin validation on all state-changing requests |
| Security Headers | CSP, X-Frame-Options, X-Content-Type-Options, HSTS (when HTTPS enabled), and more |
| File Validation | Magic-byte verification ensures uploaded files match their claimed type |
| Token Blacklisting | Logout actually invalidates the token server-side |
| Session Invalidation | Password changes immediately invalidate all existing sessions |
| Field Encryption | Sensitive data (security questions) encrypted at rest with Fernet (AES-128-CBC + HMAC) |
| Feature | Description |
|---|---|
| Auto Admin | First registered user becomes admin automatically |
| User Management | View, activate, and deactivate user accounts |
| Registration Control | Toggle new user registration on or off |
| Dashboard Stats | Total users, photos, videos, storage usage at a glance |
| Structured Logging | JSON-formatted logs with request IDs for easy debugging and monitoring |
| Architecture | Tag |
|---|---|
| x86-64 | certyiknofetch/memora:latest |
| ARM64 / aarch64 | certyiknofetch/memora:latest |
The image is a multi-platform manifest -- Docker automatically pulls the correct architecture for your system.
| Tag | Description |
|---|---|
latest | Most recent stable release |
1.0 | First stable release (v1.0) |
| Container Path | Purpose | Description |
|---|---|---|
/app/uploads | Media storage | All uploaded photos and videos with thumbnails |
/app/db_data | Database | SQLite database file |
/app/data | App data | Auto-generated secret key and app state |
Important: Always mount persistent volumes. Without them, your data is lost when the container is recreated.
| Variable | Default | Description |
|---|---|---|
SECRET_KEY | auto-generated | JWT signing key. Leave empty to auto-generate and persist to /app/data/.secret_key |
USE_HTTPS | false | Set to true when running behind an HTTPS reverse proxy (enables secure cookies and HSTS) |
DATABASE_URL | SQLite | Database connection string. Default: sqlite+aiosqlite:////app/db_data/memora.db |
UPLOAD_DIR | /app/uploads | Media storage directory inside the container |
MAX_PHOTO_SIZE_MB | 50 | Maximum upload size for photos (in MB) |
MAX_VIDEO_SIZE_MB | 2048 | Maximum upload size for videos (in MB, default 2 GB) |
ALLOWED_IMAGE_EXTENSIONS | jpg,jpeg,png,gif,webp,heic,heif,bmp,tiff,tif,avif | Comma-separated list of allowed image formats |
ALLOWED_VIDEO_EXTENSIONS | mp4,mov,avi,mkv,webm,m4v,3gp | Comma-separated list of allowed video formats |
ACCESS_TOKEN_EXPIRE_MINUTES | 1440 | Login session duration in minutes (default 24 hours) |
MAX_LOGIN_ATTEMPTS | 5 | Failed login attempts before account/IP lockout |
LOGIN_LOCKOUT_MINUTES | 15 | Lockout duration after max failed attempts |
APP_NAME | Memora | Application display name |
DEBUG | false | Debug mode. Keep false in production |
LOG_LEVEL | INFO | Log verbosity: DEBUG, INFO, WARNING, ERROR |
When placing Memora behind Nginx, Caddy, Nginx Proxy Manager, or Traefik, set USE_HTTPS=true so cookies use the Secure flag and HSTS headers are sent.
memora (container name) and Forward Port to 8000client_max_body_size 2048M;photos.example.com {
reverse_proxy memora:8000
request_body {
max_size 2GB
}
}
server {
listen 443 ssl http2;
server_name photos.example.com;
client_max_body_size 2048M;
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
}
docker compose stop memora
tar -czvf memora-backup-$(date +%Y%m%d).tar.gz uploads/ db_data/ data/
docker compose start memora
docker compose stop memora
tar -xzvf memora-backup-20260217.tar.gz
docker compose start memora
Once running, interactive API docs are available at:
| Endpoint | Description |
|---|---|
/docs | Swagger UI -- interactive API explorer |
/redoc | ReDoc -- alternative API documentation |
/health | Health check endpoint (returns {"status": "healthy"}) |
| Component | Technology |
|---|---|
| Backend | Python 3.11, FastAPI, Uvicorn |
| Database | SQLite (async via aiosqlite), SQLAlchemy 2.0 |
| Auth | JWT (python-jose), bcrypt, TOTP (pyotp) |
| Encryption | Fernet / AES (cryptography) |
| Image Processing | Pillow |
| Frontend | Vanilla JavaScript, HTML5, CSS3 |
| Container | Docker, multi-arch (amd64 + arm64) |
| Action | Command |
|---|---|
| Start | docker compose up -d |
| Stop | docker compose down |
| View logs | docker logs -f memora |
| Update | docker compose pull && docker compose up -d |
| Restart | docker compose restart |
| Shell | docker exec -it memora /bin/sh |
| Health check | curl http://localhost:8000/health |
The source code is available on GitHub. Contributions, issues, and feature requests are welcome.
MIT License -- free for personal and commercial use.
Content type
Image
Digest
sha256:34b4438b4…
Size
83.2 MB
Last updated
7 months ago
docker pull certyiknofetch/memora