mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-12-10 14:02:31 -05:00
Compare commits
5 Commits
feat-docke
...
9ef4ef47f4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ef4ef47f4 | ||
|
|
b816a12be1 | ||
|
|
b2b8035984 | ||
|
|
2007659844 | ||
|
|
6ef45640d9 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,10 +1,5 @@
|
|||||||
cli-tool/.env
|
cli-tool/.env
|
||||||
frontend/package-lock.json
|
frontend/package-lock.json
|
||||||
custom/local_settings.py
|
|
||||||
custom/static/images/*
|
|
||||||
!custom/static/images/.gitkeep
|
|
||||||
custom/static/css/*
|
|
||||||
!custom/static/css/.gitkeep
|
|
||||||
media_files/encoded/
|
media_files/encoded/
|
||||||
media_files/original/
|
media_files/original/
|
||||||
media_files/hls/
|
media_files/hls/
|
||||||
@@ -40,4 +35,3 @@ frontend-tools/video-editor/client/public/videos/sample-video.mp3
|
|||||||
frontend-tools/chapters-editor/client/public/videos/sample-video.mp3
|
frontend-tools/chapters-editor/client/public/videos/sample-video.mp3
|
||||||
static/chapters_editor/videos/sample-video.mp3
|
static/chapters_editor/videos/sample-video.mp3
|
||||||
static/video_editor/videos/sample-video.mp3
|
static/video_editor/videos/sample-video.mp3
|
||||||
backups/
|
|
||||||
|
|||||||
@@ -1,441 +1,254 @@
|
|||||||
# MediaCMS Docker Restructure Summary - Version 7.3
|
# MediaCMS Docker Restructure Summary
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
MediaCMS 7.3 introduces a complete Docker architecture restructure, moving from a monolithic supervisord-based setup to modern microservices with proper separation of concerns.
|
This document summarizes the complete Docker architecture restructure for MediaCMS 7.3, eliminating supervisord and implementing modern Docker best practices.
|
||||||
|
|
||||||
**⚠️ BREAKING CHANGES** - See [`UPGRADE_TO_7.3.md`](./UPGRADE_TO_7.3.md) for migration guide.
|
## What Was Created
|
||||||
|
|
||||||
## Architecture Comparison
|
### New Files
|
||||||
|
|
||||||
### Before (7.x) - Monolithic
|
#### Dockerfiles
|
||||||
|
- `Dockerfile` - Multi-stage Dockerfile with targets (replaced old Dockerfile):
|
||||||
|
- `build-image` - FFmpeg and Bento4 builder
|
||||||
|
- `base` - Python/Django base image
|
||||||
|
- `web` - uWSGI web server
|
||||||
|
- `worker` - Celery worker (standard)
|
||||||
|
- `worker-full` - Celery worker with extra codecs
|
||||||
|
|
||||||
|
- `Dockerfile.nginx` - Vanilla nginx with MediaCMS configs baked in
|
||||||
|
|
||||||
|
#### Docker Compose Files
|
||||||
|
- `docker-compose.yaml` - Production deployment (no file mounts) - REPLACED
|
||||||
|
- `docker-compose-cert.yaml` - Production with HTTPS (Let's Encrypt) - REPLACED
|
||||||
|
- `docker-compose-dev.yaml` - Development with file mounts and hot reload - REPLACED
|
||||||
|
|
||||||
|
#### Scripts
|
||||||
|
- `scripts/entrypoint-web.sh` - Web container entrypoint
|
||||||
|
- `scripts/entrypoint-worker.sh` - Worker container entrypoint
|
||||||
|
- `scripts/run-migrations.sh` - Migration runner script
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
- `config/nginx/nginx.conf` - Main nginx config (from deploy/docker/)
|
||||||
|
- `config/nginx/site.conf` - Virtual host config (from deploy/docker/nginx_http_only.conf)
|
||||||
|
- `config/nginx/uwsgi_params` - uWSGI params (from deploy/docker/)
|
||||||
|
- `config/nginx-proxy/client_max_body_size.conf` - For nginx-proxy (from deploy/docker/reverse_proxy/)
|
||||||
|
- `config/uwsgi/uwsgi.ini` - uWSGI configuration (from deploy/docker/)
|
||||||
|
- `config/imagemagick/policy.xml` - ImageMagick policy (from deploy/docker/)
|
||||||
|
|
||||||
|
#### Documentation
|
||||||
|
- `docs/DOCKER_V7.3_MIGRATION.md` - Complete migration guide
|
||||||
|
- Updated `docs/admins_docs.md` - Sections 4 and 5
|
||||||
|
|
||||||
|
## Architecture Changes
|
||||||
|
|
||||||
|
### Before (Old Architecture)
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────┐
|
Single Container (supervisord managing multiple processes)
|
||||||
│ Single Container │
|
├── nginx (port 80)
|
||||||
│ ┌──────────┐ │
|
├── uwsgi (port 9000)
|
||||||
│ │Supervisor│ │
|
├── celery beat
|
||||||
│ └────┬─────┘ │
|
├── celery short workers
|
||||||
│ ├─── nginx (port 80) │
|
└── celery long workers
|
||||||
│ ├─── uwsgi (Django) │
|
|
||||||
│ ├─── celery beat │
|
Controlled by ENABLE_* environment variables
|
||||||
│ ├─── celery workers │
|
|
||||||
│ └─── migrations │
|
|
||||||
│ │
|
|
||||||
│ Volumes: ./ mounted to container │
|
|
||||||
└─────────────────────────────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### After (7.3) - Microservices
|
### After (New Architecture)
|
||||||
```
|
```
|
||||||
┌────────┐ ┌─────┐ ┌───────────┐ ┌──────────┐
|
Dedicated Containers (one process per container)
|
||||||
│ nginx │→ │ web │ │celery_beat│ │ celery │
|
├── nginx (port 80) → web:9000
|
||||||
│ │ │uwsgi│ │ │ │ workers │
|
├── web (uwsgi on port 9000)
|
||||||
└────────┘ └─────┘ └───────────┘ └──────────┘
|
├── celery_beat
|
||||||
│
|
├── celery_short (scalable)
|
||||||
┌───────┴────────┐
|
├── celery_long (scalable, optional :full image)
|
||||||
│ db │ redis │
|
├── migrations (runs on startup)
|
||||||
└───────┴────────┘
|
├── db (PostgreSQL)
|
||||||
|
└── redis
|
||||||
|
|
||||||
Volumes: Named volumes + custom/ bind mount
|
Volumes:
|
||||||
|
- static_files (nginx ← web)
|
||||||
|
- media_files (nginx ← web, workers)
|
||||||
|
- postgres_data
|
||||||
```
|
```
|
||||||
|
|
||||||
## What Changed
|
|
||||||
|
|
||||||
### 1. Container Services
|
|
||||||
|
|
||||||
| Component | Before (7.x) | After (7.3) |
|
|
||||||
|-----------|-------------|-------------|
|
|
||||||
| **nginx** | Inside main container | Separate container |
|
|
||||||
| **Django/uWSGI** | Inside main container | Dedicated `web` container |
|
|
||||||
| **Celery Beat** | Inside main container | Dedicated container |
|
|
||||||
| **Celery Workers** | Inside main container | Separate containers (short/long) |
|
|
||||||
| **Migrations** | Via environment flag | Init container (runs once) |
|
|
||||||
|
|
||||||
### 2. Volume Strategy
|
|
||||||
|
|
||||||
| Data | Before (7.x) | After (7.3) |
|
|
||||||
|------|-------------|-------------|
|
|
||||||
| **Application code** | Bind mount `./` | **Built into image** |
|
|
||||||
| **Media files** | `./media_files` | **Named volume** `media_files` |
|
|
||||||
| **Static files** | `./static` | **Built into image** (collectstatic at build) |
|
|
||||||
| **Logs** | `./logs` | **Named volume** `logs` |
|
|
||||||
| **PostgreSQL** | `../postgres_data` | **Named volume** `postgres_data` |
|
|
||||||
| **Custom config** | `cms/local_settings.py` | **Bind mount** `./custom/` |
|
|
||||||
|
|
||||||
### 3. Removed Components
|
|
||||||
|
|
||||||
- ❌ supervisord and all supervisord configs
|
|
||||||
- ❌ docker-entrypoint.sh (permission fixing script)
|
|
||||||
- ❌ `ENABLE_*` environment variables
|
|
||||||
- ❌ Runtime collectstatic
|
|
||||||
- ❌ nginx from base image
|
|
||||||
|
|
||||||
### 4. New Components
|
|
||||||
|
|
||||||
- ✅ `custom/` directory for user customizations
|
|
||||||
- ✅ Multi-stage Dockerfile (base, web, worker, worker-full)
|
|
||||||
- ✅ Separate nginx image (`Dockerfile.nginx`)
|
|
||||||
- ✅ Build-time collectstatic
|
|
||||||
- ✅ USER www-data (non-root containers)
|
|
||||||
- ✅ Health checks for all services
|
|
||||||
- ✅ Makefile with common tasks
|
|
||||||
|
|
||||||
## Key Improvements
|
## Key Improvements
|
||||||
|
|
||||||
### Security
|
### 1. **Removed Components**
|
||||||
- ✅ Containers run as `www-data` (UID 33), not root
|
- ❌ supervisord and all configs in `deploy/docker/supervisord/`
|
||||||
- ✅ Read-only mounts where possible
|
- ❌ `deploy/docker/start.sh`
|
||||||
- ✅ Smaller attack surface per container
|
- ❌ `deploy/docker/entrypoint.sh`
|
||||||
- ✅ No privilege escalation needed
|
- ❌ All `ENABLE_*` environment variables
|
||||||
|
|
||||||
### Performance
|
### 2. **Separated Services**
|
||||||
- ✅ Named volumes have better I/O than bind mounts
|
- Nginx runs in its own container
|
||||||
- ✅ Static files built into image (no runtime collection)
|
- Django/uWSGI in dedicated web container
|
||||||
- ✅ Faster container startups
|
- Celery workers split by task duration
|
||||||
- ✅ No chown on millions of files at startup
|
- Migrations run automatically on every startup
|
||||||
|
|
||||||
### Scalability
|
### 3. **Production Ready**
|
||||||
- ✅ Scale web and workers independently
|
- No file mounts in production (immutable images)
|
||||||
- ✅ Ready for load balancing
|
- Named volumes for data persistence
|
||||||
- ✅ Can use Docker Swarm or Kubernetes
|
- Proper health checks
|
||||||
- ✅ Horizontal scaling: `docker compose scale celery_short=3`
|
- Individual service scaling
|
||||||
|
|
||||||
### Maintainability
|
### 4. **Development Friendly**
|
||||||
- ✅ One process per container (proper separation)
|
- Separate `-dev` compose file with file mounts
|
||||||
- ✅ Clear service dependencies
|
- Django debug mode
|
||||||
- ✅ Standard Docker patterns
|
- Frontend hot reload
|
||||||
- ✅ Easier debugging (service-specific logs)
|
- Live code editing
|
||||||
- ✅ Immutable images
|
|
||||||
|
|
||||||
### Developer Experience
|
## Images to Build
|
||||||
- ✅ Separate dev compose with hot reload
|
|
||||||
- ✅ `custom/` directory for all customizations
|
|
||||||
- ✅ Clear documentation and examples
|
|
||||||
- ✅ Makefile targets for common tasks
|
|
||||||
|
|
||||||
## New Customization System
|
For production, these images need to be built and pushed to Docker Hub:
|
||||||
|
|
||||||
### The `custom/` Directory
|
|
||||||
|
|
||||||
All user customizations now go in a dedicated directory:
|
|
||||||
|
|
||||||
```
|
|
||||||
custom/
|
|
||||||
├── README.md # Full documentation
|
|
||||||
├── local_settings.py.example # Template file
|
|
||||||
├── local_settings.py # Your Django settings (gitignored)
|
|
||||||
└── static/
|
|
||||||
├── images/ # Custom logos (gitignored)
|
|
||||||
│ └── logo_dark.png
|
|
||||||
└── css/ # Custom CSS (gitignored)
|
|
||||||
└── custom.css
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefits:**
|
|
||||||
- Clear separation from core code
|
|
||||||
- Works out-of-box (empty directory is fine)
|
|
||||||
- Gitignored customizations
|
|
||||||
- Well documented with examples
|
|
||||||
|
|
||||||
See [`custom/README.md`](./custom/README.md) for usage guide.
|
|
||||||
|
|
||||||
## Docker Images
|
|
||||||
|
|
||||||
### Images to Build
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Web image (Django + uWSGI)
|
# Build base and web image
|
||||||
docker build --target web -t mediacms/mediacms:7.3 .
|
docker build --target web -t mediacms/mediacms:7.3 .
|
||||||
|
|
||||||
# Worker image (Celery)
|
# Build worker image
|
||||||
docker build --target worker -t mediacms/mediacms-worker:7.3 .
|
docker build --target worker -t mediacms/mediacms-worker:7.3 .
|
||||||
|
|
||||||
# Worker-full image (Celery with extra codecs)
|
# Build worker-full image
|
||||||
docker build --target worker-full -t mediacms/mediacms-worker:7.3-full .
|
docker build --target worker-full -t mediacms/mediacms-worker:7.3-full .
|
||||||
|
|
||||||
# Nginx image
|
# Build nginx image
|
||||||
docker build -f Dockerfile.nginx -t mediacms/mediacms-nginx:7.3 .
|
docker build -f Dockerfile.nginx -t mediacms/mediacms-nginx:7.3 .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Image Sizes
|
## Deployment Options
|
||||||
|
|
||||||
| Image | Approximate Size |
|
|
||||||
|-------|-----------------|
|
|
||||||
| mediacms:7.3 | ~800MB |
|
|
||||||
| mediacms-worker:7.3 | ~800MB |
|
|
||||||
| mediacms-worker:7.3-full | ~1.2GB |
|
|
||||||
| mediacms-nginx:7.3 | ~50MB |
|
|
||||||
|
|
||||||
## Deployment Scenarios
|
|
||||||
|
|
||||||
### 1. Development
|
### 1. Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose -f docker-compose-dev.yaml up
|
docker compose -f docker-compose-dev.yaml up
|
||||||
```
|
```
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- File mounts for live editing
|
- File mounts for live editing
|
||||||
- Django runserver with DEBUG=True
|
- Django runserver
|
||||||
- Frontend hot reload
|
- Frontend dev server
|
||||||
- Immediate code changes
|
|
||||||
|
|
||||||
### 2. Production (HTTP)
|
### 2. Production (HTTP)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Rename .new files first
|
||||||
|
mv docker-compose.yaml.new docker-compose.yaml
|
||||||
|
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Immutable images
|
- Immutable images
|
||||||
- Named volumes for data
|
- No file mounts
|
||||||
- Production-ready
|
|
||||||
- Port 80
|
- Port 80
|
||||||
|
|
||||||
### 3. Production (HTTPS with Let's Encrypt)
|
### 3. Production (HTTPS)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose -f docker-compose.yaml -f docker-compose-cert.yaml up -d
|
# Rename .new files first
|
||||||
|
mv docker-compose-cert.yaml.new docker-compose-cert.yaml
|
||||||
|
|
||||||
|
# Edit and set your domain/email
|
||||||
|
docker compose -f docker-compose-cert.yaml up -d
|
||||||
```
|
```
|
||||||
|
- Automatic Let's Encrypt certificates
|
||||||
**Features:**
|
|
||||||
- Automatic SSL certificates
|
|
||||||
- Auto-renewal
|
- Auto-renewal
|
||||||
- nginx-proxy + acme-companion
|
|
||||||
- Production-ready
|
|
||||||
|
|
||||||
## Minimal Deployment (No Code Required!)
|
## Migration Path for Existing Systems
|
||||||
|
|
||||||
**Version 7.3 requires ONLY:**
|
### For Production Systems Currently Running
|
||||||
|
|
||||||
1. ✅ `docker-compose.yaml` file
|
1. **Backup first**
|
||||||
2. ✅ Docker images (from Docker Hub)
|
```bash
|
||||||
3. ⚠️ `custom/` directory (optional, only if customizing)
|
docker exec <db_container> pg_dump -U mediacms mediacms > backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
**No git repo needed!** Download docker-compose.yaml from release/docs and start.
|
2. **Update compose file**
|
||||||
|
- Replace old docker-compose files with new ones
|
||||||
|
- Update domain settings in cert file if using HTTPS
|
||||||
|
|
||||||
## Migration Requirements
|
3. **Pull new images**
|
||||||
|
```bash
|
||||||
|
docker pull mediacms/mediacms:7.3
|
||||||
|
docker pull mediacms/mediacms-worker:7.3
|
||||||
|
docker pull mediacms/mediacms-nginx:7.3
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Restart**
|
||||||
|
```bash
|
||||||
|
docker compose down
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|
||||||
⚠️ **Not backward compatible** - Manual migration required
|
1. **No more ENABLE_* variables** - Remove from any custom configs
|
||||||
|
2. **deploy/docker/local_settings.py** - Now use environment variables or custom image
|
||||||
**What needs migration:**
|
3. **Service names changed**:
|
||||||
1. ✅ PostgreSQL database (dump and restore)
|
- `celery_worker` → `celery_short` + `celery_long`
|
||||||
2. ✅ Media files (copy to named volume)
|
- Added `nginx` service
|
||||||
3. ✅ Custom settings → `custom/local_settings.py` (if you had them)
|
|
||||||
4. ✅ Custom logos/CSS → `custom/static/` (if you had them)
|
|
||||||
5. ⚠️ Backup scripts (new volume paths)
|
|
||||||
6. ⚠️ Monitoring (new container names)
|
|
||||||
|
|
||||||
### Migration Steps
|
|
||||||
|
|
||||||
See [`UPGRADE_TO_7.3.md`](./UPGRADE_TO_7.3.md) for complete guide.
|
|
||||||
|
|
||||||
**Quick overview:**
|
|
||||||
```bash
|
|
||||||
# 1. Backup
|
|
||||||
docker compose exec db pg_dump -U mediacms mediacms > backup.sql
|
|
||||||
tar -czf media_backup.tar.gz media_files/
|
|
||||||
cp docker-compose.yaml docker-compose.yaml.old
|
|
||||||
|
|
||||||
# 2. Download new docker-compose.yaml
|
|
||||||
wget https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose.yaml
|
|
||||||
|
|
||||||
# 3. Create custom/ if needed
|
|
||||||
mkdir -p custom/static/{images,css}
|
|
||||||
# Copy your old settings/logos if you had them
|
|
||||||
|
|
||||||
# 4. Pull images and start
|
|
||||||
docker compose pull
|
|
||||||
docker compose up -d
|
|
||||||
|
|
||||||
# 5. Restore data
|
|
||||||
cat backup.sql | docker compose exec -T db psql -U mediacms mediacms
|
|
||||||
# (See full guide for media migration)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Files
|
|
||||||
|
|
||||||
### Created/Reorganized
|
|
||||||
|
|
||||||
```
|
|
||||||
├── Dockerfile # Multi-stage (base, web, worker)
|
|
||||||
├── Dockerfile.nginx # Nginx image
|
|
||||||
├── docker-compose.yaml # Production
|
|
||||||
├── docker-compose-cert.yaml # Production + HTTPS
|
|
||||||
├── docker-compose-dev.yaml # Development
|
|
||||||
├── Makefile # Common tasks
|
|
||||||
├── custom/ # User customizations
|
|
||||||
│ ├── README.md
|
|
||||||
│ ├── local_settings.py.example
|
|
||||||
│ └── static/
|
|
||||||
├── config/
|
|
||||||
│ ├── imagemagick/policy.xml
|
|
||||||
│ ├── nginx/
|
|
||||||
│ │ ├── nginx.conf
|
|
||||||
│ │ └── site.conf
|
|
||||||
│ ├── nginx-proxy/
|
|
||||||
│ │ └── client_max_body_size.conf
|
|
||||||
│ └── uwsgi/
|
|
||||||
│ └── uwsgi.ini
|
|
||||||
└── scripts/
|
|
||||||
└── run-migrations.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Makefile Targets
|
|
||||||
|
|
||||||
New Makefile with common operations:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make backup-db # PostgreSQL dump with timestamp
|
|
||||||
make admin-shell # Quick Django shell access
|
|
||||||
make build-frontend # Rebuild frontend assets
|
|
||||||
make test # Run test suite
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollback Strategy
|
|
||||||
|
|
||||||
If migration fails:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Stop new version
|
|
||||||
docker compose down
|
|
||||||
|
|
||||||
# 2. Checkout old version
|
|
||||||
git checkout main
|
|
||||||
|
|
||||||
# 3. Restore old compose
|
|
||||||
git checkout main docker-compose.yaml
|
|
||||||
|
|
||||||
# 4. Restore data from backups
|
|
||||||
# (See UPGRADE_TO_7.3.md for details)
|
|
||||||
|
|
||||||
# 5. Start old version
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing Checklist
|
## Testing Checklist
|
||||||
|
|
||||||
Before production deployment:
|
Before deploying to production, test:
|
||||||
|
|
||||||
- [ ] Migrations run successfully
|
- [ ] Migrations run successfully
|
||||||
- [ ] Static files load correctly
|
- [ ] Static files served correctly
|
||||||
- [ ] Media files upload/download work
|
- [ ] Media files served correctly
|
||||||
- [ ] Video transcoding works (check celery_long logs)
|
- [ ] Django admin accessible
|
||||||
- [ ] Admin panel accessible
|
- [ ] Video upload works
|
||||||
- [ ] Custom settings loaded (if using custom/)
|
- [ ] Video transcoding works (celery_long)
|
||||||
- [ ] Database persists across restarts
|
- [ ] Thumbnail generation works (celery_short)
|
||||||
- [ ] Media persists across restarts
|
- [ ] HTTPS redirects work (if using cert file)
|
||||||
- [ ] Logs accessible via `docker compose logs`
|
- [ ] Database persistence across restarts
|
||||||
- [ ] Health checks pass: `docker compose ps`
|
- [ ] Media files persistence across restarts
|
||||||
|
|
||||||
## Common Post-Upgrade Tasks
|
## Configuration Examples
|
||||||
|
|
||||||
### View Logs
|
### Use Full Worker Image
|
||||||
```bash
|
```yaml
|
||||||
# Before: tail -f logs/uwsgi.log
|
celery_long:
|
||||||
# After:
|
image: mediacms/mediacms-worker:7.3-full
|
||||||
docker compose logs -f web
|
|
||||||
docker compose logs -f celery_long
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Access Shell
|
### Set Custom Domain
|
||||||
```bash
|
```yaml
|
||||||
# Before: docker exec -it <container> bash
|
environment:
|
||||||
# After:
|
FRONTEND_HOST: 'https://videos.example.com'
|
||||||
make admin-shell
|
PORTAL_NAME: 'My Video Portal'
|
||||||
# Or: docker compose exec web bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### Restart Service
|
|
||||||
```bash
|
|
||||||
# Before: docker restart <container>
|
|
||||||
# After:
|
|
||||||
docker compose restart web
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Scale Workers
|
### Scale Workers
|
||||||
```bash
|
```bash
|
||||||
# New capability:
|
|
||||||
docker compose up -d --scale celery_short=3 --scale celery_long=2
|
docker compose up -d --scale celery_short=3 --scale celery_long=2
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database Backup
|
## Files to Review Before Finalizing
|
||||||
```bash
|
|
||||||
# Before: Custom script
|
|
||||||
# After:
|
|
||||||
make backup-db
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Considerations
|
1. **Dockerfile** - Review Python/Django/uWSGI configuration
|
||||||
|
2. **config/nginx/site.conf** - Review nginx paths and proxy settings
|
||||||
### Startup Time
|
3. **docker-compose.yaml** - Review volume mounts and service dependencies
|
||||||
- **Before**: Slower (chown on all files)
|
4. **scripts/run-migrations.sh** - Review migration logic
|
||||||
- **After**: Faster (no permission fixing)
|
|
||||||
|
|
||||||
### I/O Performance
|
|
||||||
- **Before**: Bind mount overhead
|
|
||||||
- **After**: Named volumes (better performance)
|
|
||||||
|
|
||||||
### Memory Usage
|
|
||||||
- **Before**: Single large container
|
|
||||||
- **After**: Multiple smaller containers (better resource allocation)
|
|
||||||
|
|
||||||
## New Volume Management
|
|
||||||
|
|
||||||
### List Volumes
|
|
||||||
```bash
|
|
||||||
docker volume ls | grep mediacms
|
|
||||||
```
|
|
||||||
|
|
||||||
### Inspect Volume
|
|
||||||
```bash
|
|
||||||
docker volume inspect mediacms_media_files
|
|
||||||
```
|
|
||||||
|
|
||||||
### Backup Volume
|
|
||||||
```bash
|
|
||||||
docker run --rm \
|
|
||||||
-v mediacms_media_files:/data:ro \
|
|
||||||
-v $(pwd):/backup \
|
|
||||||
alpine tar czf /backup/media_backup.tar.gz -C /data .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- **Upgrade Guide**: [`UPGRADE_TO_7.3.md`](./UPGRADE_TO_7.3.md)
|
|
||||||
- **Customization**: [`custom/README.md`](./custom/README.md)
|
|
||||||
- **Admin Docs**: `docs/admins_docs.md`
|
|
||||||
|
|
||||||
## Timeline Estimates
|
|
||||||
|
|
||||||
| Instance Size | Expected Migration Time |
|
|
||||||
|---------------|------------------------|
|
|
||||||
| Small (<100 videos) | 30-60 minutes |
|
|
||||||
| Medium (100-1000 videos) | 1-3 hours |
|
|
||||||
| Large (>1000 videos) | 3-8 hours |
|
|
||||||
|
|
||||||
**Plan accordingly and schedule during low-traffic periods!**
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
1. Read [`UPGRADE_TO_7.3.md`](./UPGRADE_TO_7.3.md) thoroughly
|
|
||||||
2. Check [`custom/README.md`](./custom/README.md) for customization
|
|
||||||
3. Search GitHub Issues
|
|
||||||
4. Test in staging first
|
|
||||||
5. Keep backups for at least 1 week post-upgrade
|
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
1. ✅ Read [`UPGRADE_TO_7.3.md`](./UPGRADE_TO_7.3.md)
|
To finalize this restructure:
|
||||||
2. ✅ Test in development: `docker compose -f docker-compose-dev.yaml up`
|
|
||||||
3. ✅ Backup production data
|
|
||||||
4. ✅ Test migration in staging
|
|
||||||
5. ✅ Plan maintenance window
|
|
||||||
6. ✅ Execute migration
|
|
||||||
7. ✅ Monitor for 24-48 hours
|
|
||||||
|
|
||||||
---
|
1. **Test locally** with docker-compose-dev.yaml
|
||||||
|
2. **Build images** and push to Docker Hub
|
||||||
|
3. **Update CI/CD** to build new images
|
||||||
|
4. **Test in staging environment**
|
||||||
|
5. **Create release notes** referencing migration guide
|
||||||
|
|
||||||
**Ready to upgrade?** Start with: [`UPGRADE_TO_7.3.md`](./UPGRADE_TO_7.3.md)
|
## Backup
|
||||||
|
|
||||||
|
Old Docker files have been backed up to `.docker-backup/` directory.
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
If issues arise, rollback by:
|
||||||
|
1. Reverting to old docker-compose files
|
||||||
|
2. Using old image tags
|
||||||
|
3. Restoring database from backup if needed
|
||||||
|
|
||||||
|
Old files are preserved in `.docker-backup/` directory.
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
- Migration Guide: `docs/DOCKER_V7.3_MIGRATION.md`
|
||||||
|
- Admin Docs: `docs/admins_docs.md` (updated sections 4, 5)
|
||||||
|
- Issues: https://github.com/mediacms-io/mediacms/issues
|
||||||
|
|||||||
34
Dockerfile
34
Dockerfile
@@ -1,5 +1,6 @@
|
|||||||
FROM python:3.13.5-slim-bookworm AS build-image
|
FROM python:3.13.5-slim-bookworm AS build-image
|
||||||
|
|
||||||
|
# Install system dependencies needed for downloading and extracting
|
||||||
RUN apt-get update -y && \
|
RUN apt-get update -y && \
|
||||||
apt-get install -y --no-install-recommends wget xz-utils unzip && \
|
apt-get install -y --no-install-recommends wget xz-utils unzip && \
|
||||||
rm -rf /var/lib/apt/lists/* && \
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
@@ -13,6 +14,7 @@ RUN mkdir -p ffmpeg-tmp && \
|
|||||||
cp -v ffmpeg-tmp/ffmpeg ffmpeg-tmp/ffprobe ffmpeg-tmp/qt-faststart /usr/local/bin && \
|
cp -v ffmpeg-tmp/ffmpeg ffmpeg-tmp/ffprobe ffmpeg-tmp/qt-faststart /usr/local/bin && \
|
||||||
rm -rf ffmpeg-tmp ffmpeg-release-amd64-static.tar.xz
|
rm -rf ffmpeg-tmp ffmpeg-release-amd64-static.tar.xz
|
||||||
|
|
||||||
|
# Install Bento4 in the specified location
|
||||||
RUN mkdir -p /home/mediacms.io/bento4 && \
|
RUN mkdir -p /home/mediacms.io/bento4 && \
|
||||||
wget -q http://zebulon.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip && \
|
wget -q http://zebulon.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip && \
|
||||||
unzip Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip -d /home/mediacms.io/bento4 && \
|
unzip Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip -d /home/mediacms.io/bento4 && \
|
||||||
@@ -36,6 +38,7 @@ ENV PYTHONUNBUFFERED=1 \
|
|||||||
VIRTUAL_ENV=/home/mediacms.io \
|
VIRTUAL_ENV=/home/mediacms.io \
|
||||||
PATH="$VIRTUAL_ENV/bin:$PATH"
|
PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||||
|
|
||||||
|
# Install system dependencies (no nginx, no supervisor)
|
||||||
RUN apt-get update -y && \
|
RUN apt-get update -y && \
|
||||||
apt-get -y upgrade && \
|
apt-get -y upgrade && \
|
||||||
apt-get install --no-install-recommends -y \
|
apt-get install --no-install-recommends -y \
|
||||||
@@ -49,16 +52,18 @@ RUN apt-get update -y && \
|
|||||||
libxmlsec1-dev \
|
libxmlsec1-dev \
|
||||||
libxmlsec1-openssl \
|
libxmlsec1-openssl \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
gosu \
|
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN mkdir -p /home/mediacms.io/mediacms/{logs,media_files,static} && \
|
# Set up virtualenv
|
||||||
|
RUN mkdir -p /home/mediacms.io/mediacms/{logs,media_files,static_files} && \
|
||||||
cd /home/mediacms.io && \
|
cd /home/mediacms.io && \
|
||||||
python3 -m venv $VIRTUAL_ENV
|
python3 -m venv $VIRTUAL_ENV
|
||||||
|
|
||||||
|
# Copy requirements files
|
||||||
COPY requirements.txt requirements-dev.txt ./
|
COPY requirements.txt requirements-dev.txt ./
|
||||||
|
|
||||||
|
# Install Python dependencies using pip (within virtualenv)
|
||||||
ARG DEVELOPMENT_MODE=False
|
ARG DEVELOPMENT_MODE=False
|
||||||
RUN pip install --no-cache-dir uv && \
|
RUN pip install --no-cache-dir uv && \
|
||||||
uv pip install --no-binary lxml --no-binary xmlsec -r requirements.txt && \
|
uv pip install --no-binary lxml --no-binary xmlsec -r requirements.txt && \
|
||||||
@@ -73,30 +78,25 @@ RUN pip install --no-cache-dir uv && \
|
|||||||
libxmlsec1-dev \
|
libxmlsec1-dev \
|
||||||
libpq-dev
|
libpq-dev
|
||||||
|
|
||||||
|
# Copy ffmpeg and Bento4 from build image
|
||||||
COPY --from=build-image /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
|
COPY --from=build-image /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
|
||||||
COPY --from=build-image /usr/local/bin/ffprobe /usr/local/bin/ffprobe
|
COPY --from=build-image /usr/local/bin/ffprobe /usr/local/bin/ffprobe
|
||||||
COPY --from=build-image /usr/local/bin/qt-faststart /usr/local/bin/qt-faststart
|
COPY --from=build-image /usr/local/bin/qt-faststart /usr/local/bin/qt-faststart
|
||||||
COPY --from=build-image /home/mediacms.io/bento4 /home/mediacms.io/bento4
|
COPY --from=build-image /home/mediacms.io/bento4 /home/mediacms.io/bento4
|
||||||
|
|
||||||
|
# Copy application files with correct ownership
|
||||||
COPY --chown=www-data:www-data . /home/mediacms.io/mediacms
|
COPY --chown=www-data:www-data . /home/mediacms.io/mediacms
|
||||||
WORKDIR /home/mediacms.io/mediacms
|
WORKDIR /home/mediacms.io/mediacms
|
||||||
|
|
||||||
# Copy imagemagick policy for sprite thumbnail generation
|
# Copy imagemagick policy for sprite thumbnail generation
|
||||||
COPY config/imagemagick/policy.xml /etc/ImageMagick-6/policy.xml
|
COPY config/imagemagick/policy.xml /etc/ImageMagick-6/policy.xml
|
||||||
|
|
||||||
|
# Copy local_settings.py from config to cms/ for default Docker config (if exists)
|
||||||
|
RUN cp config/local_settings.py cms/local_settings.py 2>/dev/null || true
|
||||||
|
|
||||||
# Create www-data user directories and set permissions
|
# Create www-data user directories and set permissions
|
||||||
RUN mkdir -p /var/run/mediacms && \
|
RUN mkdir -p /var/run/mediacms && \
|
||||||
chown -R www-data:www-data /home/mediacms.io/mediacms/logs \
|
chown www-data:www-data /var/run/mediacms
|
||||||
/home/mediacms.io/mediacms/media_files \
|
|
||||||
/home/mediacms.io/mediacms/static \
|
|
||||||
/var/run/mediacms
|
|
||||||
|
|
||||||
# Collect static files during build
|
|
||||||
RUN python manage.py collectstatic --noinput && \
|
|
||||||
chown -R www-data:www-data /home/mediacms.io/mediacms/static
|
|
||||||
|
|
||||||
# Run container as www-data user
|
|
||||||
USER www-data
|
|
||||||
|
|
||||||
############ WEB IMAGE (Django/uWSGI) ############
|
############ WEB IMAGE (Django/uWSGI) ############
|
||||||
FROM base AS web
|
FROM base AS web
|
||||||
@@ -107,6 +107,8 @@ RUN uv pip install uwsgi
|
|||||||
# Copy uWSGI configuration
|
# Copy uWSGI configuration
|
||||||
COPY config/uwsgi/uwsgi.ini /home/mediacms.io/mediacms/uwsgi.ini
|
COPY config/uwsgi/uwsgi.ini /home/mediacms.io/mediacms/uwsgi.ini
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
|
||||||
EXPOSE 9000
|
EXPOSE 9000
|
||||||
|
|
||||||
CMD ["/home/mediacms.io/bin/uwsgi", "--ini", "/home/mediacms.io/mediacms/uwsgi.ini"]
|
CMD ["/home/mediacms.io/bin/uwsgi", "--ini", "/home/mediacms.io/mediacms/uwsgi.ini"]
|
||||||
@@ -114,13 +116,19 @@ CMD ["/home/mediacms.io/bin/uwsgi", "--ini", "/home/mediacms.io/mediacms/uwsgi.i
|
|||||||
############ WORKER IMAGE (Celery) ############
|
############ WORKER IMAGE (Celery) ############
|
||||||
FROM base AS worker
|
FROM base AS worker
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
|
||||||
# CMD will be overridden in docker-compose for different worker types
|
# CMD will be overridden in docker-compose for different worker types
|
||||||
|
|
||||||
############ FULL WORKER IMAGE (Celery with extra codecs) ############
|
############ FULL WORKER IMAGE (Celery with extra codecs) ############
|
||||||
FROM worker AS worker-full
|
FROM worker AS worker-full
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
COPY requirements-full.txt ./
|
COPY requirements-full.txt ./
|
||||||
RUN mkdir -p /root/.cache/ && \
|
RUN mkdir -p /root/.cache/ && \
|
||||||
chmod go+rwx /root/ && \
|
chmod go+rwx /root/ && \
|
||||||
chmod go+rwx /root/.cache/ && \
|
chmod go+rwx /root/.cache/ && \
|
||||||
uv pip install -r requirements-full.txt
|
uv pip install -r requirements-full.txt
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
|||||||
15
Makefile
15
Makefile
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: admin-shell build-frontend backup-db
|
.PHONY: admin-shell build-frontend
|
||||||
|
|
||||||
admin-shell:
|
admin-shell:
|
||||||
@container_id=$$(docker compose ps -q web); \
|
@container_id=$$(docker compose ps -q web); \
|
||||||
@@ -17,16 +17,3 @@ build-frontend:
|
|||||||
test:
|
test:
|
||||||
docker compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest
|
docker compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest
|
||||||
|
|
||||||
backup-db:
|
|
||||||
@echo "Creating PostgreSQL database dump..."
|
|
||||||
@mkdir -p backups
|
|
||||||
@timestamp=$$(date +%Y%m%d_%H%M%S); \
|
|
||||||
dump_file="backups/mediacms_dump_$${timestamp}.sql"; \
|
|
||||||
docker compose exec -T db pg_dump -U mediacms -d mediacms > "$${dump_file}"; \
|
|
||||||
if [ $$? -eq 0 ]; then \
|
|
||||||
echo "Database dump created successfully: $${dump_file}"; \
|
|
||||||
else \
|
|
||||||
echo "Database dump failed"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|||||||
292
QUICKSTART.md
292
QUICKSTART.md
@@ -1,292 +0,0 @@
|
|||||||
# MediaCMS 7.3 - Quick Start
|
|
||||||
|
|
||||||
## Minimal Deployment (No Code Required!)
|
|
||||||
|
|
||||||
MediaCMS 7.3 can be deployed with **just 2 files**:
|
|
||||||
|
|
||||||
1. `docker-compose.yaml`
|
|
||||||
2. `custom/` directory (optional)
|
|
||||||
|
|
||||||
**No git repo, no code checkout needed!** Everything runs from Docker images.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fresh Installation
|
|
||||||
|
|
||||||
### 1. Create deployment directory
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir mediacms && cd mediacms
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Download docker-compose.yaml
|
|
||||||
|
|
||||||
```bash
|
|
||||||
wget https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Or with curl:
|
|
||||||
```bash
|
|
||||||
curl -O https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Start MediaCMS
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Access your site
|
|
||||||
|
|
||||||
- **Frontend**: http://localhost
|
|
||||||
- **Admin**: http://localhost/admin
|
|
||||||
- Username: `admin`
|
|
||||||
- Password: Check logs for auto-generated password:
|
|
||||||
```bash
|
|
||||||
docker compose logs migrations | grep "password:"
|
|
||||||
```
|
|
||||||
|
|
||||||
**That's it!** 🎉
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Optional: Customization
|
|
||||||
|
|
||||||
### Add Custom Settings
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Create custom directory
|
|
||||||
mkdir -p custom/static/{images,css}
|
|
||||||
|
|
||||||
# 2. Download example template
|
|
||||||
wget -O custom/local_settings.py.example \
|
|
||||||
https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/custom/local_settings.py.example
|
|
||||||
|
|
||||||
# 3. Copy and edit
|
|
||||||
cp custom/local_settings.py.example custom/local_settings.py
|
|
||||||
nano custom/local_settings.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Example customizations:
|
|
||||||
```python
|
|
||||||
# custom/local_settings.py
|
|
||||||
DEBUG = False
|
|
||||||
ALLOWED_HOSTS = ['media.example.com']
|
|
||||||
PORTAL_NAME = "My Media Portal"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Add Custom Logo
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Copy your logo
|
|
||||||
cp ~/my-logo.png custom/static/images/logo_dark.png
|
|
||||||
|
|
||||||
# 2. Reference in settings
|
|
||||||
cat >> custom/local_settings.py <<EOF
|
|
||||||
PORTAL_LOGO_DARK_PNG = "/custom/static/images/logo_dark.png"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 3. Restart (no rebuild needed!)
|
|
||||||
docker compose restart web
|
|
||||||
```
|
|
||||||
|
|
||||||
### Add Custom CSS
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Create CSS file
|
|
||||||
cat > custom/static/css/custom.css <<EOF
|
|
||||||
body {
|
|
||||||
font-family: 'Arial', sans-serif;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 2. Reference in settings
|
|
||||||
cat >> custom/local_settings.py <<EOF
|
|
||||||
EXTRA_CSS_PATHS = ["/custom/static/css/custom.css"]
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 3. Restart (no rebuild needed!)
|
|
||||||
docker compose restart web
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note**: Both settings AND static files only need restart - nginx serves custom/ files directly!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## HTTPS with Let's Encrypt
|
|
||||||
|
|
||||||
### 1. Download cert overlay
|
|
||||||
|
|
||||||
```bash
|
|
||||||
wget https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose-cert.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Edit domains
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nano docker-compose-cert.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Change these lines:
|
|
||||||
```yaml
|
|
||||||
VIRTUAL_HOST: 'media.example.com' # Your domain
|
|
||||||
LETSENCRYPT_HOST: 'media.example.com' # Your domain
|
|
||||||
LETSENCRYPT_EMAIL: 'admin@example.com' # Your email
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Start with SSL
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose.yaml -f docker-compose-cert.yaml up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
**SSL certificates are issued automatically!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
Your deployment directory:
|
|
||||||
|
|
||||||
```
|
|
||||||
mediacms/
|
|
||||||
├── docker-compose.yaml # Required
|
|
||||||
├── docker-compose-cert.yaml # Optional (for HTTPS)
|
|
||||||
└── custom/ # Optional (for customizations)
|
|
||||||
├── local_settings.py # Django settings
|
|
||||||
└── static/
|
|
||||||
├── images/ # Custom logos
|
|
||||||
└── css/ # Custom CSS
|
|
||||||
```
|
|
||||||
|
|
||||||
**Named volumes** (managed by Docker):
|
|
||||||
- `mediacms_postgres_data` - Database
|
|
||||||
- `mediacms_media_files` - Uploaded media
|
|
||||||
- `mediacms_static_files` - Static assets
|
|
||||||
- `mediacms_logs` - Application logs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Common Commands
|
|
||||||
|
|
||||||
### View logs
|
|
||||||
```bash
|
|
||||||
docker compose logs -f web
|
|
||||||
docker compose logs -f celery_long
|
|
||||||
```
|
|
||||||
|
|
||||||
### Access Django shell
|
|
||||||
```bash
|
|
||||||
docker compose exec web python manage.py shell
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create admin user
|
|
||||||
```bash
|
|
||||||
docker compose exec web python manage.py createsuperuser
|
|
||||||
```
|
|
||||||
|
|
||||||
### Restart service
|
|
||||||
```bash
|
|
||||||
docker compose restart web
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stop everything
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
### Update to newer version
|
|
||||||
```bash
|
|
||||||
docker compose pull
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backup
|
|
||||||
|
|
||||||
### Database backup
|
|
||||||
```bash
|
|
||||||
docker compose exec db pg_dump -U mediacms mediacms > backup_$(date +%Y%m%d).sql
|
|
||||||
```
|
|
||||||
|
|
||||||
### Media files backup
|
|
||||||
```bash
|
|
||||||
docker run --rm \
|
|
||||||
-v mediacms_media_files:/data:ro \
|
|
||||||
-v $(pwd):/backup \
|
|
||||||
alpine tar czf /backup/media_backup_$(date +%Y%m%d).tar.gz -C /data .
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Upgrading from 7.x?
|
|
||||||
|
|
||||||
If you're upgrading from an older MediaCMS version, see:
|
|
||||||
- **[UPGRADE_TO_7.3.md](./UPGRADE_TO_7.3.md)** - Complete migration guide
|
|
||||||
- **[DOCKER_RESTRUCTURE_SUMMARY.md](./DOCKER_RESTRUCTURE_SUMMARY.md)** - What changed
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- **Customization**: Download [`custom/README.md`](https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/custom/README.md)
|
|
||||||
- **Upgrade Guide**: [UPGRADE_TO_7.3.md](./UPGRADE_TO_7.3.md)
|
|
||||||
- **Architecture**: [DOCKER_RESTRUCTURE_SUMMARY.md](./DOCKER_RESTRUCTURE_SUMMARY.md)
|
|
||||||
- **Project Docs**: https://docs.mediacms.io
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Can't access the site?
|
|
||||||
|
|
||||||
Check services are running:
|
|
||||||
```bash
|
|
||||||
docker compose ps
|
|
||||||
```
|
|
||||||
|
|
||||||
All services should be "Up" or "Exited (0)" for migrations.
|
|
||||||
|
|
||||||
### Forgot admin password?
|
|
||||||
|
|
||||||
Check logs:
|
|
||||||
```bash
|
|
||||||
docker compose logs migrations | grep "password:"
|
|
||||||
```
|
|
||||||
|
|
||||||
Or create new admin:
|
|
||||||
```bash
|
|
||||||
docker compose exec web python manage.py createsuperuser
|
|
||||||
```
|
|
||||||
|
|
||||||
### Videos not encoding?
|
|
||||||
|
|
||||||
Check celery workers:
|
|
||||||
```bash
|
|
||||||
docker compose logs celery_long
|
|
||||||
docker compose logs celery_short
|
|
||||||
```
|
|
||||||
|
|
||||||
### Port 80 already in use?
|
|
||||||
|
|
||||||
Edit docker-compose.yaml to use different port:
|
|
||||||
```yaml
|
|
||||||
nginx:
|
|
||||||
ports:
|
|
||||||
- "8080:80" # Use port 8080 instead
|
|
||||||
```
|
|
||||||
|
|
||||||
Then access at http://localhost:8080
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
- **Issues**: https://github.com/mediacms-io/mediacms/issues
|
|
||||||
- **Discussions**: https://github.com/mediacms-io/mediacms/discussions
|
|
||||||
- **Docs**: https://docs.mediacms.io
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎉 Enjoy MediaCMS!**
|
|
||||||
@@ -1,477 +0,0 @@
|
|||||||
# Upgrade Guide: MediaCMS 7.x to 7.3
|
|
||||||
|
|
||||||
**IMPORTANT: This is a major architectural change. Read this entire guide before upgrading.**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Fresh Install (Not Upgrading)?
|
|
||||||
|
|
||||||
If you're starting fresh with 7.3, you don't need this guide!
|
|
||||||
|
|
||||||
**All you need:**
|
|
||||||
```bash
|
|
||||||
# 1. Download docker-compose.yaml
|
|
||||||
wget https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose.yaml
|
|
||||||
|
|
||||||
# 2. Start (creates everything automatically)
|
|
||||||
docker compose up -d
|
|
||||||
|
|
||||||
# 3. Done! Visit http://localhost
|
|
||||||
```
|
|
||||||
|
|
||||||
**Optional: Add customizations**
|
|
||||||
```bash
|
|
||||||
# Create custom/ directory
|
|
||||||
mkdir -p custom/static/{images,css}
|
|
||||||
|
|
||||||
# Download example settings
|
|
||||||
wget -O custom/local_settings.py.example \
|
|
||||||
https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/custom/local_settings.py.example
|
|
||||||
|
|
||||||
# Edit and use
|
|
||||||
cp custom/local_settings.py.example custom/local_settings.py
|
|
||||||
nano custom/local_settings.py
|
|
||||||
|
|
||||||
# Restart
|
|
||||||
docker compose restart web
|
|
||||||
```
|
|
||||||
|
|
||||||
See [`custom/README.md`](https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/custom/README.md) for customization options.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ Upgrading from 7.x? Continue reading...
|
|
||||||
|
|
||||||
## What Changed in 7.3
|
|
||||||
|
|
||||||
### Architecture Changes
|
|
||||||
- **Before**: Monolithic container (supervisor + nginx + uwsgi + celery in one)
|
|
||||||
- **After**: Microservices (separate nginx, web, celery_beat, celery_short, celery_long containers)
|
|
||||||
|
|
||||||
### Volume Strategy Changes
|
|
||||||
- **Before**: Entire project directory mounted (`./:/home/mediacms.io/mediacms/`)
|
|
||||||
- **After**: Named volumes for data, bind mount only for `custom/` directory
|
|
||||||
|
|
||||||
### Specific Changes
|
|
||||||
|
|
||||||
| Component | Before (7.x) | After (7.3) |
|
|
||||||
|-----------|-------------|-------------|
|
|
||||||
| media_files | Bind mount `./media_files` | Named volume `media_files` |
|
|
||||||
| static files | Bind mount `./static` | Named volume `static_files` (built into image) |
|
|
||||||
| logs | Bind mount `./logs` | Named volume `logs` |
|
|
||||||
| postgres_data | `../postgres_data` | Named volume `postgres_data` |
|
|
||||||
| Custom config | `cms/local_settings.py` in mounted dir | `custom/local_settings.py` bind mount |
|
|
||||||
| Static collection | Runtime (via entrypoint) | Build time (in Dockerfile) |
|
|
||||||
| User | Root with gosu switch | www-data from start |
|
|
||||||
|
|
||||||
## What You Need for 7.3
|
|
||||||
|
|
||||||
**Minimal deployment - NO CODE REQUIRED:**
|
|
||||||
|
|
||||||
1. ✅ `docker-compose.yaml` (download from release or docs)
|
|
||||||
2. ✅ Docker images (pulled from Docker Hub)
|
|
||||||
3. ⚠️ `custom/` directory (only if you have customizations)
|
|
||||||
|
|
||||||
**That's it!** No git repo, no code checkout needed.
|
|
||||||
|
|
||||||
## Pre-Upgrade Checklist
|
|
||||||
|
|
||||||
### 1. Backup Everything
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Stop services
|
|
||||||
docker compose down
|
|
||||||
|
|
||||||
# Backup media files
|
|
||||||
tar -czf backup_media_$(date +%Y%m%d).tar.gz media_files/
|
|
||||||
|
|
||||||
# Backup database
|
|
||||||
docker compose up -d db
|
|
||||||
docker compose exec db pg_dump -U mediacms mediacms > backup_db_$(date +%Y%m%d).sql
|
|
||||||
docker compose down
|
|
||||||
|
|
||||||
# Backup logs (optional)
|
|
||||||
tar -czf backup_logs_$(date +%Y%m%d).tar.gz logs/
|
|
||||||
|
|
||||||
# Backup local settings if you had them
|
|
||||||
cp cms/local_settings.py backup_local_settings.py 2>/dev/null || echo "No local_settings.py found"
|
|
||||||
|
|
||||||
# Backup current docker-compose.yaml
|
|
||||||
cp docker-compose.yaml docker-compose.yaml.old
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Document Current Setup
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Save current docker-compose version
|
|
||||||
git branch backup-pre-7.3-upgrade
|
|
||||||
|
|
||||||
# Document current state
|
|
||||||
docker compose ps > pre_upgrade_state.txt
|
|
||||||
docker compose config > pre_upgrade_config.yaml
|
|
||||||
df -h > pre_upgrade_disk_usage.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Check Disk Space
|
|
||||||
|
|
||||||
You'll need enough space for:
|
|
||||||
- Existing data (media_files, postgres_data)
|
|
||||||
- New Docker volumes (will copy data here)
|
|
||||||
- Database dump
|
|
||||||
|
|
||||||
```bash
|
|
||||||
du -sh media_files/ postgres_data/ logs/
|
|
||||||
df -h .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Upgrade Methods
|
|
||||||
|
|
||||||
### Method 1: Clean Migration (Recommended)
|
|
||||||
|
|
||||||
This method migrates your data to the new volume structure.
|
|
||||||
|
|
||||||
#### Step 1: Get New docker-compose.yaml
|
|
||||||
|
|
||||||
**Option A: Download from release**
|
|
||||||
```bash
|
|
||||||
# Download docker-compose.yaml for 7.3
|
|
||||||
wget https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose.yaml
|
|
||||||
|
|
||||||
# Or using curl
|
|
||||||
curl -O https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose.yaml
|
|
||||||
|
|
||||||
# Optional: Download HTTPS version
|
|
||||||
wget https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/docker-compose-cert.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
**Option B: Copy from docs/release notes**
|
|
||||||
- Copy the docker-compose.yaml content from release notes
|
|
||||||
- Save as `docker-compose.yaml` in your deployment directory
|
|
||||||
|
|
||||||
#### Step 2: Prepare Custom Configuration (if needed)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Create custom directory structure (only if you need customizations)
|
|
||||||
mkdir -p custom/static/{images,css}
|
|
||||||
touch custom/static/{images,css}/.gitkeep
|
|
||||||
|
|
||||||
# If you had local_settings.py, create it in custom/
|
|
||||||
if [ -f backup_local_settings.py ]; then
|
|
||||||
# Copy your old settings
|
|
||||||
cp backup_local_settings.py custom/local_settings.py
|
|
||||||
echo "✓ Migrated local_settings.py"
|
|
||||||
else
|
|
||||||
# Download example template (optional)
|
|
||||||
wget -O custom/local_settings.py.example \
|
|
||||||
https://raw.githubusercontent.com/mediacms-io/mediacms/v7.3/custom/local_settings.py.example
|
|
||||||
echo "Downloaded example template to custom/local_settings.py.example"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Copy any custom logos/css you had
|
|
||||||
# (adjust paths as needed for your old setup)
|
|
||||||
# cp my-old-logo.png custom/static/images/logo_dark.png
|
|
||||||
# cp my-custom.css custom/static/css/custom.css
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 3: Start New Stack (Without Data)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Pull new images
|
|
||||||
docker compose pull
|
|
||||||
|
|
||||||
# Start database first
|
|
||||||
docker compose up -d db redis
|
|
||||||
|
|
||||||
# Wait for DB to be ready
|
|
||||||
sleep 10
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 4: Restore Database
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Copy backup into container
|
|
||||||
docker compose cp backup_db_*.sql db:/tmp/backup.sql
|
|
||||||
|
|
||||||
# Restore database
|
|
||||||
docker compose exec db psql -U mediacms mediacms < /tmp/backup.sql
|
|
||||||
|
|
||||||
# Or from host:
|
|
||||||
cat backup_db_*.sql | docker compose exec -T db psql -U mediacms mediacms
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 5: Restore Media Files
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Start all services (will create volumes)
|
|
||||||
docker compose up -d
|
|
||||||
|
|
||||||
# Find the volume name
|
|
||||||
docker volume ls | grep media_files
|
|
||||||
|
|
||||||
# Copy media files to volume
|
|
||||||
# Method A: Using a temporary container
|
|
||||||
docker run --rm \
|
|
||||||
-v $(pwd)/media_files:/source:ro \
|
|
||||||
-v mediacms_media_files:/dest \
|
|
||||||
alpine sh -c "cp -av /source/* /dest/"
|
|
||||||
|
|
||||||
# Method B: Using existing container
|
|
||||||
docker compose exec web sh -c "exit" # Ensure web is running
|
|
||||||
# Then copy from host
|
|
||||||
tar -C media_files -cf - . | docker compose exec -T web tar -C /home/mediacms.io/mediacms/media_files -xf -
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 6: Verify and Test
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check logs
|
|
||||||
docker compose logs -f web
|
|
||||||
|
|
||||||
# Verify media files are accessible
|
|
||||||
docker compose exec web ls -la /home/mediacms.io/mediacms/media_files/
|
|
||||||
|
|
||||||
# Check database connection
|
|
||||||
docker compose exec web python manage.py dbshell
|
|
||||||
|
|
||||||
# Access the site
|
|
||||||
curl http://localhost
|
|
||||||
|
|
||||||
# Check admin panel
|
|
||||||
# Visit http://localhost/admin
|
|
||||||
```
|
|
||||||
|
|
||||||
### Method 2: In-Place Migration with Symlinks (Advanced)
|
|
||||||
|
|
||||||
**Warning**: This is more complex but avoids data copying.
|
|
||||||
|
|
||||||
#### Step 1: Keep Old Data Locations
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Modify docker-compose.yaml to mount old locations temporarily
|
|
||||||
# Add to appropriate services:
|
|
||||||
volumes:
|
|
||||||
- ./media_files:/home/mediacms.io/mediacms/media_files
|
|
||||||
- ./logs:/home/mediacms.io/mediacms/logs
|
|
||||||
# Instead of named volumes
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 2: Gradually Migrate
|
|
||||||
|
|
||||||
After confirming everything works:
|
|
||||||
1. Copy data to named volumes
|
|
||||||
2. Remove bind mounts
|
|
||||||
3. Switch to named volumes
|
|
||||||
|
|
||||||
### Method 3: Fresh Install (If Possible)
|
|
||||||
|
|
||||||
If your MediaCMS instance is new or test:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Backup what you need
|
|
||||||
# ...
|
|
||||||
|
|
||||||
# Clean slate
|
|
||||||
docker compose down -v
|
|
||||||
rm -rf media_files/ logs/ static/
|
|
||||||
|
|
||||||
# Fresh start
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## Post-Upgrade Steps
|
|
||||||
|
|
||||||
### 1. Verify Everything Works
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check all services are running
|
|
||||||
docker compose ps
|
|
||||||
|
|
||||||
# Should see: migrations (exited 0), web, nginx, celery_beat, celery_short, celery_long, db, redis
|
|
||||||
|
|
||||||
# Check logs for errors
|
|
||||||
docker compose logs web
|
|
||||||
docker compose logs nginx
|
|
||||||
|
|
||||||
# Test upload functionality
|
|
||||||
# Test video encoding (check celery_long logs)
|
|
||||||
# Test frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Verify Media Files
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check media files are accessible
|
|
||||||
docker compose exec web ls -lh /home/mediacms.io/mediacms/media_files/
|
|
||||||
|
|
||||||
# Check file counts match
|
|
||||||
# Old: ls media_files/ | wc -l
|
|
||||||
# New: docker compose exec web sh -c "ls /home/mediacms.io/mediacms/media_files/ | wc -l"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Verify Database
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check users
|
|
||||||
docker compose exec db psql -U mediacms mediacms -c "SELECT count(*) FROM users_user;"
|
|
||||||
|
|
||||||
# Check videos
|
|
||||||
docker compose exec db psql -U mediacms mediacms -c "SELECT count(*) FROM files_media;"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Update Backups
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Update your backup scripts for new volume locations
|
|
||||||
# Use: make backup-db (if Makefile target exists)
|
|
||||||
# Or: docker compose exec db pg_dump ...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollback Procedure
|
|
||||||
|
|
||||||
If something goes wrong:
|
|
||||||
|
|
||||||
### Quick Rollback
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Stop new version
|
|
||||||
docker compose down
|
|
||||||
|
|
||||||
# Restore old docker-compose file
|
|
||||||
mv docker-compose.yaml.old docker-compose.yaml
|
|
||||||
|
|
||||||
# Pull old images (if you had old image tags documented)
|
|
||||||
docker compose pull
|
|
||||||
|
|
||||||
# Start old version
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### Full Rollback with Data Restore
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Stop everything
|
|
||||||
docker compose down -v
|
|
||||||
|
|
||||||
# Restore old docker-compose
|
|
||||||
mv docker-compose.yaml.old docker-compose.yaml
|
|
||||||
|
|
||||||
# Restore backups
|
|
||||||
tar -xzf backup_media_*.tar.gz -C ./media_files
|
|
||||||
cat backup_db_*.sql | docker compose exec -T db psql -U mediacms mediacms
|
|
||||||
|
|
||||||
# Start old version
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Issues & Solutions
|
|
||||||
|
|
||||||
### Issue: "Volume not found"
|
|
||||||
|
|
||||||
**Solution**: Volumes are created with project name prefix. Check:
|
|
||||||
```bash
|
|
||||||
docker volume ls
|
|
||||||
# Look for: mediacms_media_files, mediacms_static_files, etc.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issue: "Permission denied" on media files
|
|
||||||
|
|
||||||
**Solution**: Files must be owned by www-data (UID 33)
|
|
||||||
```bash
|
|
||||||
docker compose exec web chown -R www-data:www-data /home/mediacms.io/mediacms/media_files
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issue: Static files not loading
|
|
||||||
|
|
||||||
**Solution**: Rebuild image (collectstatic runs at build time)
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
docker compose build --no-cache web
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issue: Database connection refused
|
|
||||||
|
|
||||||
**Solution**: Check database is healthy
|
|
||||||
```bash
|
|
||||||
docker compose logs db
|
|
||||||
docker compose exec db pg_isready -U mediacms
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issue: Custom settings not loading
|
|
||||||
|
|
||||||
**Solution**: Check custom/local_settings.py exists and syntax
|
|
||||||
```bash
|
|
||||||
docker compose exec web cat /home/mediacms.io/mediacms/custom/local_settings.py
|
|
||||||
docker compose exec web python -m py_compile /home/mediacms.io/mediacms/custom/local_settings.py
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Considerations
|
|
||||||
|
|
||||||
### New Volume Performance
|
|
||||||
|
|
||||||
Named volumes are typically faster than bind mounts:
|
|
||||||
- **Before**: Filesystem overhead on host
|
|
||||||
- **After**: Direct container filesystem (better I/O)
|
|
||||||
|
|
||||||
### Monitoring Volume Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check volume sizes
|
|
||||||
docker system df -v
|
|
||||||
|
|
||||||
# Check specific volume
|
|
||||||
docker volume inspect mediacms_media_files
|
|
||||||
```
|
|
||||||
|
|
||||||
## New Backup Strategy
|
|
||||||
|
|
||||||
With named volumes, backups change:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Database backup
|
|
||||||
docker compose exec db pg_dump -U mediacms mediacms > backup.sql
|
|
||||||
|
|
||||||
# Media files backup
|
|
||||||
docker run --rm \
|
|
||||||
-v mediacms_media_files:/data:ro \
|
|
||||||
-v $(pwd):/backup \
|
|
||||||
alpine tar czf /backup/media_backup_$(date +%Y%m%d).tar.gz -C /data .
|
|
||||||
```
|
|
||||||
|
|
||||||
Or use the Makefile:
|
|
||||||
```bash
|
|
||||||
make backup-db
|
|
||||||
```
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
If you encounter issues:
|
|
||||||
|
|
||||||
1. **Check logs**: `docker compose logs <service>`
|
|
||||||
2. **Check GitHub Issues**: Search for similar problems
|
|
||||||
3. **Rollback**: Use the rollback procedure above
|
|
||||||
4. **Report**: Open an issue with:
|
|
||||||
- Your docker-compose.yaml
|
|
||||||
- Output of `docker compose ps`
|
|
||||||
- Relevant logs
|
|
||||||
- Steps to reproduce
|
|
||||||
|
|
||||||
## Summary of Benefits
|
|
||||||
|
|
||||||
After upgrading to 7.3:
|
|
||||||
|
|
||||||
✅ **Better separation of concerns** - each service has one job
|
|
||||||
✅ **Easier scaling** - scale web/workers independently
|
|
||||||
✅ **Better security** - containers run as www-data, not root
|
|
||||||
✅ **Faster deployments** - static files built into image
|
|
||||||
✅ **Cleaner customization** - dedicated custom/ directory
|
|
||||||
✅ **Easier SSL setup** - docker-compose-cert.yaml overlay
|
|
||||||
✅ **Better volume management** - named volumes instead of bind mounts
|
|
||||||
|
|
||||||
## Timeline Recommendation
|
|
||||||
|
|
||||||
- **Small instance** (<100 videos): 30-60 minutes
|
|
||||||
- **Medium instance** (100-1000 videos): 1-3 hours
|
|
||||||
- **Large instance** (>1000 videos): Plan for several hours
|
|
||||||
|
|
||||||
Schedule during low-traffic period!
|
|
||||||
@@ -112,22 +112,18 @@ SITE_ID = 1
|
|||||||
# set new paths for svg or png if you want to override
|
# set new paths for svg or png if you want to override
|
||||||
# svg has priority over png, so if you want to use
|
# svg has priority over png, so if you want to use
|
||||||
# custom pngs and not svgs, remove the lines with svgs
|
# custom pngs and not svgs, remove the lines with svgs
|
||||||
# Logo paths (served from /static/)
|
# or set as empty strings
|
||||||
# Default logos are built into the image
|
|
||||||
# To customize: place files in custom/static/images/ and reference as /custom/static/images/file.png
|
|
||||||
# or set as empty strings to disable
|
|
||||||
# example:
|
# example:
|
||||||
# PORTAL_LOGO_DARK_PNG = "/custom/static/images/my-logo.png"
|
|
||||||
# PORTAL_LOGO_DARK_SVG = ""
|
# PORTAL_LOGO_DARK_SVG = ""
|
||||||
|
# PORTAL_LOGO_LIGHT_SVG = ""
|
||||||
|
# place the files on static/images folder
|
||||||
PORTAL_LOGO_DARK_SVG = "/static/images/logo_dark.svg"
|
PORTAL_LOGO_DARK_SVG = "/static/images/logo_dark.svg"
|
||||||
PORTAL_LOGO_DARK_PNG = "/static/images/logo_dark.png"
|
PORTAL_LOGO_DARK_PNG = "/static/images/logo_dark.png"
|
||||||
PORTAL_LOGO_LIGHT_SVG = "/static/images/logo_light.svg"
|
PORTAL_LOGO_LIGHT_SVG = "/static/images/logo_light.svg"
|
||||||
PORTAL_LOGO_LIGHT_PNG = "/static/images/logo_dark.png"
|
PORTAL_LOGO_LIGHT_PNG = "/static/images/logo_dark.png"
|
||||||
|
|
||||||
# Extra CSS files to include in templates
|
# paths to extra css files to be included, eg "/static/css/custom.css"
|
||||||
# To add custom CSS: place files in custom/static/css/ and add paths here
|
# place css inside static/css folder
|
||||||
# Use /custom/static/ prefix for files in custom/ directory
|
|
||||||
# Example: EXTRA_CSS_PATHS = ["/custom/static/css/custom.css"]
|
|
||||||
EXTRA_CSS_PATHS = []
|
EXTRA_CSS_PATHS = []
|
||||||
# protection agains anonymous users
|
# protection agains anonymous users
|
||||||
# per ip address limit, for actions as like/dislike/report
|
# per ip address limit, for actions as like/dislike/report
|
||||||
@@ -183,10 +179,6 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
STATIC_URL = "/static/" # where js/css files are stored on the filesystem
|
STATIC_URL = "/static/" # where js/css files are stored on the filesystem
|
||||||
MEDIA_URL = "/media/" # URL where static files are served from the server
|
MEDIA_URL = "/media/" # URL where static files are served from the server
|
||||||
STATIC_ROOT = BASE_DIR + "/static/"
|
STATIC_ROOT = BASE_DIR + "/static/"
|
||||||
# Additional locations for static files
|
|
||||||
# Note: custom/static is NOT included here because it's served directly by nginx
|
|
||||||
# at /custom/static/ and doesn't need collectstatic
|
|
||||||
STATICFILES_DIRS = []
|
|
||||||
# where uploaded + encoded media are stored
|
# where uploaded + encoded media are stored
|
||||||
MEDIA_ROOT = BASE_DIR + "/media_files/"
|
MEDIA_ROOT = BASE_DIR + "/media_files/"
|
||||||
|
|
||||||
@@ -261,7 +253,7 @@ POST_UPLOAD_AUTHOR_MESSAGE_UNLISTED_NO_COMMENTARY = ""
|
|||||||
CANNOT_ADD_MEDIA_MESSAGE = "User cannot add media, or maximum number of media uploads has been reached."
|
CANNOT_ADD_MEDIA_MESSAGE = "User cannot add media, or maximum number of media uploads has been reached."
|
||||||
|
|
||||||
# mp4hls command, part of Bento4
|
# mp4hls command, part of Bento4
|
||||||
MP4HLS_COMMAND = "/home/mediacms.io/bento4/bin/mp4hls"
|
MP4HLS_COMMAND = "/home/mediacms.io/mediacms/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/bin/mp4hls"
|
||||||
|
|
||||||
# highly experimental, related with remote workers
|
# highly experimental, related with remote workers
|
||||||
ADMIN_TOKEN = ""
|
ADMIN_TOKEN = ""
|
||||||
@@ -378,30 +370,41 @@ FILE_UPLOAD_HANDLERS = [
|
|||||||
"django.core.files.uploadhandler.TemporaryFileUploadHandler",
|
"django.core.files.uploadhandler.TemporaryFileUploadHandler",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
LOGS_DIR = os.path.join(BASE_DIR, "logs")
|
||||||
|
|
||||||
|
error_filename = os.path.join(LOGS_DIR, "debug.log")
|
||||||
|
if not os.path.exists(LOGS_DIR):
|
||||||
|
try:
|
||||||
|
os.mkdir(LOGS_DIR)
|
||||||
|
except PermissionError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not os.path.isfile(error_filename):
|
||||||
|
open(error_filename, 'a').close()
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"disable_existing_loggers": False,
|
"disable_existing_loggers": False,
|
||||||
"formatters": {
|
|
||||||
"verbose": {
|
|
||||||
"format": "%(levelname)s %(asctime)s %(module)s "
|
|
||||||
"%(process)d %(thread)d %(message)s"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"handlers": {
|
"handlers": {
|
||||||
"console": {
|
"file": {
|
||||||
"level": "DEBUG",
|
"level": "ERROR",
|
||||||
"class": "logging.StreamHandler",
|
"class": "logging.FileHandler",
|
||||||
"formatter": "verbose",
|
"filename": error_filename,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
"loggers": {
|
||||||
|
"django": {
|
||||||
|
"handlers": ["file"],
|
||||||
|
"level": "ERROR",
|
||||||
|
"propagate": True,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"root": {"level": "INFO", "handlers": ["console"]},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DATABASES = {"default": {"ENGINE": "django.db.backends.postgresql", "NAME": "mediacms", "HOST": "db", "PORT": "5432", "USER": "mediacms", "PASSWORD": "mediacms", "OPTIONS": {'pool': True}}}
|
DATABASES = {"default": {"ENGINE": "django.db.backends.postgresql", "NAME": "mediacms", "HOST": "127.0.0.1", "PORT": "5432", "USER": "mediacms", "PASSWORD": "mediacms", "OPTIONS": {'pool': True}}}
|
||||||
|
|
||||||
|
|
||||||
REDIS_LOCATION = "redis://redis:6379/1"
|
REDIS_LOCATION = "redis://127.0.0.1:6379/1"
|
||||||
CACHES = {
|
CACHES = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
@@ -597,15 +600,13 @@ WHISPER_MODEL = "base"
|
|||||||
SIDEBAR_FOOTER_TEXT = ""
|
SIDEBAR_FOOTER_TEXT = ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Load custom settings from custom/local_settings.py
|
# keep a local_settings.py file for local overrides
|
||||||
import sys
|
from .local_settings import * # noqa
|
||||||
sys.path.insert(0, BASE_DIR)
|
|
||||||
from custom.local_settings import * # noqa
|
|
||||||
|
|
||||||
# ALLOWED_HOSTS needs a url/ip
|
# ALLOWED_HOSTS needs a url/ip
|
||||||
ALLOWED_HOSTS.append(FRONTEND_HOST.replace("http://", "").replace("https://", ""))
|
ALLOWED_HOSTS.append(FRONTEND_HOST.replace("http://", "").replace("https://", ""))
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# custom/local_settings.py not in use or empty
|
# local_settings not in use
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Don't add new settings below that could be overridden in local_settings.py!!!
|
# Don't add new settings below that could be overridden in local_settings.py!!!
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
user nginx;
|
user www-data;
|
||||||
worker_processes auto;
|
worker_processes auto;
|
||||||
pid /run/nginx.pid;
|
pid /run/nginx.pid;
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ server {
|
|||||||
alias /var/www/static ;
|
alias /var/www/static ;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /custom/static {
|
|
||||||
alias /var/www/custom ;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /media/original {
|
location /media/original {
|
||||||
alias /var/www/media/original;
|
alias /var/www/media/original;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ threads = 2
|
|||||||
|
|
||||||
master = true
|
master = true
|
||||||
|
|
||||||
socket = 0.0.0.0:9000
|
socket = 127.0.0.1:9000
|
||||||
|
|
||||||
workers = 2
|
workers = 2
|
||||||
|
|
||||||
|
|||||||
238
custom/README.md
238
custom/README.md
@@ -1,238 +0,0 @@
|
|||||||
# Custom Configuration
|
|
||||||
|
|
||||||
This directory allows you to customize MediaCMS without modifying the codebase or rebuilding images.
|
|
||||||
|
|
||||||
## How It Works - Production Ready!
|
|
||||||
|
|
||||||
**The Flow:**
|
|
||||||
|
|
||||||
```
|
|
||||||
1. CI/CD builds base image: docker build (no custom files)
|
|
||||||
↓
|
|
||||||
Pushes to Docker Hub
|
|
||||||
|
|
||||||
2. Production pulls image: docker compose pull
|
|
||||||
↓
|
|
||||||
Mounts custom/ directory
|
|
||||||
|
|
||||||
3. You add files: custom/static/css/custom.css
|
|
||||||
custom/static/images/logo.png
|
|
||||||
↓
|
|
||||||
Nginx serves directly!
|
|
||||||
|
|
||||||
4. You reference in settings: EXTRA_CSS_PATHS = ["/custom/static/css/custom.css"]
|
|
||||||
PORTAL_LOGO_DARK_PNG = "/custom/static/images/logo.png"
|
|
||||||
↓
|
|
||||||
Restart containers
|
|
||||||
|
|
||||||
5. Done! No rebuild needed!
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Points:**
|
|
||||||
- ✅ Files go in `custom/static/` on your host
|
|
||||||
- ✅ Nginx serves them directly from `/custom/static/` URL
|
|
||||||
- ✅ **NO rebuild needed** - just restart containers!
|
|
||||||
- ✅ Works with pre-built images from Docker Hub
|
|
||||||
- ✅ Perfect for production deployments
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
### Option 1: No Customization (Default)
|
|
||||||
Just run docker compose - everything works out of the box:
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option 2: With Customization
|
|
||||||
Add your custom files, then restart:
|
|
||||||
```bash
|
|
||||||
# 1. Copy example settings
|
|
||||||
cp custom/local_settings.py.example custom/local_settings.py
|
|
||||||
|
|
||||||
# 2. Edit settings
|
|
||||||
nano custom/local_settings.py
|
|
||||||
|
|
||||||
# 3. Restart containers (no rebuild!)
|
|
||||||
docker compose restart web celery_beat celery_short celery_long
|
|
||||||
```
|
|
||||||
|
|
||||||
## Customization Options
|
|
||||||
|
|
||||||
### 1. Django Settings (`local_settings.py`)
|
|
||||||
|
|
||||||
**Create the file:**
|
|
||||||
```bash
|
|
||||||
cp custom/local_settings.py.example custom/local_settings.py
|
|
||||||
```
|
|
||||||
|
|
||||||
**Edit with your settings:**
|
|
||||||
```python
|
|
||||||
# custom/local_settings.py
|
|
||||||
DEBUG = False
|
|
||||||
ALLOWED_HOSTS = ['example.com']
|
|
||||||
PORTAL_NAME = "My Media Site"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Apply changes (restart only - no rebuild):**
|
|
||||||
```bash
|
|
||||||
docker compose restart web celery_beat celery_short celery_long
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Custom Logo
|
|
||||||
|
|
||||||
**Add your logo:**
|
|
||||||
```bash
|
|
||||||
cp ~/my-logo.png custom/static/images/logo_dark.png
|
|
||||||
```
|
|
||||||
|
|
||||||
**Reference it in settings:**
|
|
||||||
```bash
|
|
||||||
cat >> custom/local_settings.py <<EOF
|
|
||||||
PORTAL_LOGO_DARK_PNG = "/custom/static/images/logo_dark.png"
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
**Restart (no rebuild needed!):**
|
|
||||||
```bash
|
|
||||||
docker compose restart web
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Custom CSS
|
|
||||||
|
|
||||||
**Create CSS file:**
|
|
||||||
```bash
|
|
||||||
cat > custom/static/css/custom.css <<EOF
|
|
||||||
body {
|
|
||||||
font-family: 'Arial', sans-serif;
|
|
||||||
}
|
|
||||||
.header {
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
**Reference it in settings:**
|
|
||||||
```bash
|
|
||||||
cat >> custom/local_settings.py <<EOF
|
|
||||||
EXTRA_CSS_PATHS = ["/custom/static/css/custom.css"]
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
**Restart (no rebuild needed!):**
|
|
||||||
```bash
|
|
||||||
docker compose restart web
|
|
||||||
```
|
|
||||||
|
|
||||||
## Directory Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
custom/
|
|
||||||
├── README.md # This file
|
|
||||||
├── local_settings.py.example # Template (copy to local_settings.py)
|
|
||||||
├── local_settings.py # Your settings (gitignored)
|
|
||||||
└── static/
|
|
||||||
├── images/ # Custom logos (gitignored)
|
|
||||||
│ └── logo_dark.png
|
|
||||||
└── css/ # Custom CSS (gitignored)
|
|
||||||
└── custom.css
|
|
||||||
```
|
|
||||||
|
|
||||||
## Important Notes
|
|
||||||
|
|
||||||
✅ **No rebuild needed** - nginx serves custom/ files directly
|
|
||||||
✅ **Works with pre-built images** - perfect for production
|
|
||||||
✅ **Files are gitignored** - your customizations won't be committed
|
|
||||||
✅ **Settings need restart only** - just restart containers
|
|
||||||
✅ **Static files also just restart** - served directly by nginx
|
|
||||||
|
|
||||||
## Complete Example
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Create settings file
|
|
||||||
cp custom/local_settings.py.example custom/local_settings.py
|
|
||||||
|
|
||||||
# 2. Add custom logo
|
|
||||||
cp ~/logo.png custom/static/images/logo_dark.png
|
|
||||||
|
|
||||||
# 3. Add custom CSS
|
|
||||||
echo "body { background: #f5f5f5; }" > custom/static/css/custom.css
|
|
||||||
|
|
||||||
# 4. Configure settings to use them
|
|
||||||
cat >> custom/local_settings.py <<EOF
|
|
||||||
|
|
||||||
# Custom branding
|
|
||||||
PORTAL_NAME = "My Media Portal"
|
|
||||||
PORTAL_LOGO_DARK_PNG = "/custom/static/images/logo_dark.png"
|
|
||||||
EXTRA_CSS_PATHS = ["/custom/static/css/custom.css"]
|
|
||||||
|
|
||||||
# Security
|
|
||||||
DEBUG = False
|
|
||||||
ALLOWED_HOSTS = ['media.example.com']
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 5. Apply changes (just restart!)
|
|
||||||
docker compose restart web
|
|
||||||
|
|
||||||
# Done! No rebuild needed.
|
|
||||||
```
|
|
||||||
|
|
||||||
## URL Paths Explained
|
|
||||||
|
|
||||||
| Your file | nginx serves at | You reference as |
|
|
||||||
|-----------|----------------|------------------|
|
|
||||||
| `custom/static/css/custom.css` | `http://localhost/custom/static/css/custom.css` | `"/custom/static/css/custom.css"` |
|
|
||||||
| `custom/static/images/logo.png` | `http://localhost/custom/static/images/logo.png` | `"/custom/static/images/logo.png"` |
|
|
||||||
|
|
||||||
**Why `/custom/static/`?**
|
|
||||||
- Distinguishes from core `/static/` (built into image)
|
|
||||||
- Allows nginx to serve from different mount point
|
|
||||||
- No rebuild needed when files change
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
**Changes not appearing?**
|
|
||||||
- Restart containers: `docker compose restart web nginx`
|
|
||||||
- Check nginx has custom/ mounted: `docker compose exec nginx ls /var/www/custom`
|
|
||||||
- Check file exists: `docker compose exec nginx ls /var/www/custom/css/`
|
|
||||||
- Test URL: `curl http://localhost/custom/static/css/custom.css`
|
|
||||||
|
|
||||||
**Import errors?**
|
|
||||||
- Make sure `local_settings.py` has valid Python syntax
|
|
||||||
- Check logs: `docker compose logs web`
|
|
||||||
|
|
||||||
**Logo not showing?**
|
|
||||||
- Verify file is in `custom/static/images/`
|
|
||||||
- Check path in `local_settings.py` uses `/custom/static/` prefix
|
|
||||||
- Restart web container: `docker compose restart web`
|
|
||||||
|
|
||||||
## Advanced: Multiple CSS Files
|
|
||||||
|
|
||||||
```python
|
|
||||||
# custom/local_settings.py
|
|
||||||
EXTRA_CSS_PATHS = [
|
|
||||||
"/custom/static/css/colors.css",
|
|
||||||
"/custom/static/css/fonts.css",
|
|
||||||
"/custom/static/css/layout.css",
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Advanced: Environment-Specific Settings
|
|
||||||
|
|
||||||
```python
|
|
||||||
# custom/local_settings.py
|
|
||||||
import os
|
|
||||||
|
|
||||||
if os.getenv('ENVIRONMENT') == 'production':
|
|
||||||
DEBUG = False
|
|
||||||
ALLOWED_HOSTS = ['media.example.com']
|
|
||||||
else:
|
|
||||||
DEBUG = True
|
|
||||||
ALLOWED_HOSTS = ['*']
|
|
||||||
```
|
|
||||||
|
|
||||||
Then set in docker-compose.yaml:
|
|
||||||
```yaml
|
|
||||||
web:
|
|
||||||
environment:
|
|
||||||
ENVIRONMENT: production
|
|
||||||
```
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
# MediaCMS Local Settings Example
|
|
||||||
# Copy this file to local_settings.py and customize as needed:
|
|
||||||
# cp custom/local_settings.py.example custom/local_settings.py
|
|
||||||
|
|
||||||
# ===== Basic Settings =====
|
|
||||||
|
|
||||||
# DEBUG = False
|
|
||||||
# ALLOWED_HOSTS = ['example.com', 'www.example.com']
|
|
||||||
# PORTAL_NAME = "My Media Portal"
|
|
||||||
|
|
||||||
# ===== Database Settings =====
|
|
||||||
|
|
||||||
# DATABASES = {
|
|
||||||
# 'default': {
|
|
||||||
# 'ENGINE': 'django.db.backends.postgresql',
|
|
||||||
# 'NAME': 'mediacms',
|
|
||||||
# 'USER': 'mediacms',
|
|
||||||
# 'PASSWORD': 'mediacms',
|
|
||||||
# 'HOST': 'db',
|
|
||||||
# 'PORT': '5432',
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
|
|
||||||
# ===== Custom Branding =====
|
|
||||||
|
|
||||||
# Custom logos (place files in custom/static/images/)
|
|
||||||
# Nginx serves these directly from /custom/static/ (no rebuild needed!)
|
|
||||||
# PORTAL_LOGO_DARK_SVG = "/custom/static/images/logo_dark.svg"
|
|
||||||
# PORTAL_LOGO_DARK_PNG = "/custom/static/images/logo_dark.png"
|
|
||||||
# PORTAL_LOGO_LIGHT_SVG = "/custom/static/images/logo_light.svg"
|
|
||||||
# PORTAL_LOGO_LIGHT_PNG = "/custom/static/images/logo_light.png"
|
|
||||||
|
|
||||||
# Custom CSS (place files in custom/static/css/)
|
|
||||||
# Nginx serves these directly from /custom/static/ (no rebuild needed!)
|
|
||||||
# EXTRA_CSS_PATHS = ["/custom/static/css/custom.css"]
|
|
||||||
|
|
||||||
# ===== Email Settings =====
|
|
||||||
|
|
||||||
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
||||||
# EMAIL_HOST = 'smtp.gmail.com'
|
|
||||||
# EMAIL_PORT = 587
|
|
||||||
# EMAIL_USE_TLS = True
|
|
||||||
# EMAIL_HOST_USER = 'your-email@example.com'
|
|
||||||
# EMAIL_HOST_PASSWORD = 'your-password'
|
|
||||||
# DEFAULT_FROM_EMAIL = 'noreply@example.com'
|
|
||||||
|
|
||||||
# ===== Security Settings =====
|
|
||||||
|
|
||||||
# SECRET_KEY = 'your-secret-key-here'
|
|
||||||
# SECURE_SSL_REDIRECT = True
|
|
||||||
# SESSION_COOKIE_SECURE = True
|
|
||||||
# CSRF_COOKIE_SECURE = True
|
|
||||||
|
|
||||||
# ===== Other Settings =====
|
|
||||||
|
|
||||||
# Any other Django setting can be overridden here
|
|
||||||
# See cms/settings.py for available settings
|
|
||||||
@@ -1,18 +1,9 @@
|
|||||||
version: "3.8"
|
version: "3.8"
|
||||||
|
|
||||||
# HTTPS/SSL certificate overlay for docker-compose.yaml
|
# Production setup with automatic HTTPS via Let's Encrypt
|
||||||
# Uses nginx-proxy with Let's Encrypt via acme-companion
|
# Uses https://github.com/nginx-proxy/acme-companion
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# docker compose -f docker-compose.yaml -f docker-compose-cert.yaml up -d
|
|
||||||
#
|
|
||||||
# Before running:
|
|
||||||
# 1. Change VIRTUAL_HOST to your domain
|
|
||||||
# 2. Change LETSENCRYPT_HOST to your domain
|
|
||||||
# 3. Change LETSENCRYPT_EMAIL to your email
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# Reverse proxy with automatic SSL
|
|
||||||
nginx-proxy:
|
nginx-proxy:
|
||||||
image: nginxproxy/nginx-proxy
|
image: nginxproxy/nginx-proxy
|
||||||
container_name: nginx-proxy
|
container_name: nginx-proxy
|
||||||
@@ -29,7 +20,6 @@ services:
|
|||||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||||
- ./config/nginx-proxy/client_max_body_size.conf:/etc/nginx/conf.d/client_max_body_size.conf:ro
|
- ./config/nginx-proxy/client_max_body_size.conf:/etc/nginx/conf.d/client_max_body_size.conf:ro
|
||||||
|
|
||||||
# Let's Encrypt certificate manager
|
|
||||||
acme-companion:
|
acme-companion:
|
||||||
image: nginxproxy/acme-companion
|
image: nginxproxy/acme-companion
|
||||||
container_name: nginx-proxy-acme
|
container_name: nginx-proxy-acme
|
||||||
@@ -41,22 +31,131 @@ services:
|
|||||||
- acme:/etc/acme.sh
|
- acme:/etc/acme.sh
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
|
||||||
# Override nginx to work with nginx-proxy
|
migrations:
|
||||||
|
image: mediacms/mediacms:7.3
|
||||||
|
command: ["/bin/bash", "/home/mediacms.io/mediacms/scripts/run-migrations.sh"]
|
||||||
|
environment:
|
||||||
|
ADMIN_USER: 'admin'
|
||||||
|
ADMIN_EMAIL: 'admin@localhost'
|
||||||
|
# ADMIN_PASSWORD: 'uncomment_and_set_password_here'
|
||||||
|
restart: "no"
|
||||||
|
depends_on:
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- static_files:/home/mediacms.io/mediacms/static_files
|
||||||
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
|
web:
|
||||||
|
image: mediacms/mediacms:7.3
|
||||||
|
restart: unless-stopped
|
||||||
|
expose:
|
||||||
|
- "9000"
|
||||||
|
depends_on:
|
||||||
|
migrations:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- static_files:/home/mediacms.io/mediacms/static_files
|
||||||
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
|
image: mediacms/mediacms-nginx:7.3
|
||||||
|
restart: unless-stopped
|
||||||
expose:
|
expose:
|
||||||
- "80"
|
- "80"
|
||||||
ports: [] # Remove ports, nginx-proxy handles external access
|
|
||||||
environment:
|
environment:
|
||||||
# CHANGE THESE VALUES:
|
# These are required for nginx-proxy to route traffic correctly
|
||||||
VIRTUAL_HOST: 'mediacms.example.com'
|
VIRTUAL_HOST: 'mediacms.example.com' # CHANGE THIS to your domain
|
||||||
LETSENCRYPT_HOST: 'mediacms.example.com'
|
LETSENCRYPT_HOST: 'mediacms.example.com' # CHANGE THIS to your domain
|
||||||
LETSENCRYPT_EMAIL: 'admin@example.com'
|
LETSENCRYPT_EMAIL: 'admin@example.com' # CHANGE THIS to your email
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
volumes:
|
||||||
|
- static_files:/var/www/static:ro
|
||||||
|
- media_files:/var/www/media:ro
|
||||||
|
- logs:/var/log/mediacms
|
||||||
|
|
||||||
|
celery_beat:
|
||||||
|
image: mediacms/mediacms-worker:7.3
|
||||||
|
restart: unless-stopped
|
||||||
|
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "beat", "--loglevel=INFO"]
|
||||||
|
depends_on:
|
||||||
|
migrations:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
|
celery_short:
|
||||||
|
image: mediacms/mediacms-worker:7.3
|
||||||
|
restart: unless-stopped
|
||||||
|
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "short_tasks", "-c", "10", "--soft-time-limit=300", "--loglevel=INFO", "-n", "short@%h"]
|
||||||
|
depends_on:
|
||||||
|
migrations:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
|
celery_long:
|
||||||
|
image: mediacms/mediacms-worker:7.3
|
||||||
|
# To use extra codecs, change image to: mediacms/mediacms-worker:7.3-full
|
||||||
|
restart: unless-stopped
|
||||||
|
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "worker", "-Q", "long_tasks", "-c", "1", "-Ofair", "--prefetch-multiplier=1", "--loglevel=INFO", "-n", "long@%h"]
|
||||||
|
depends_on:
|
||||||
|
migrations:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:17.2-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: mediacms
|
||||||
|
POSTGRES_PASSWORD: mediacms
|
||||||
|
POSTGRES_DB: mediacms
|
||||||
|
TZ: Europe/London
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# nginx-proxy volumes
|
|
||||||
conf:
|
conf:
|
||||||
vhost:
|
vhost:
|
||||||
html:
|
html:
|
||||||
dhparam:
|
dhparam:
|
||||||
certs:
|
certs:
|
||||||
acme:
|
acme:
|
||||||
|
postgres_data:
|
||||||
|
static_files:
|
||||||
|
media_files:
|
||||||
|
logs:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
ADMIN_USER: 'admin'
|
ADMIN_USER: 'admin'
|
||||||
ADMIN_EMAIL: 'admin@localhost'
|
ADMIN_EMAIL: 'admin@localhost'
|
||||||
ADMIN_PASSWORD: # ADMIN_PASSWORD: 'uncomment_and_set_password_here'
|
# ADMIN_PASSWORD: 'uncomment_and_set_password_here'
|
||||||
restart: "no"
|
restart: "no"
|
||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
@@ -15,8 +15,7 @@ services:
|
|||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- ./custom:/home/mediacms.io/mediacms/custom:ro
|
- static_files:/home/mediacms.io/mediacms/static_files
|
||||||
- static_files:/home/mediacms.io/mediacms/static
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
@@ -33,8 +32,7 @@ services:
|
|||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- ./custom:/home/mediacms.io/mediacms/custom:ro
|
- static_files:/home/mediacms.io/mediacms/static_files
|
||||||
- static_files:/home/mediacms.io/mediacms/static
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
@@ -46,7 +44,6 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- web
|
- web
|
||||||
volumes:
|
volumes:
|
||||||
- ./custom/static:/var/www/custom:ro
|
|
||||||
- static_files:/var/www/static:ro
|
- static_files:/var/www/static:ro
|
||||||
- media_files:/var/www/media:ro
|
- media_files:/var/www/media:ro
|
||||||
- logs:/var/log/mediacms
|
- logs:/var/log/mediacms
|
||||||
@@ -54,14 +51,13 @@ services:
|
|||||||
celery_beat:
|
celery_beat:
|
||||||
image: mediacms/mediacms-worker:7.3
|
image: mediacms/mediacms-worker:7.3
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "beat", "--loglevel=INFO", "--schedule=/home/mediacms.io/mediacms/logs/celerybeat-schedule"]
|
command: ["/home/mediacms.io/bin/celery", "-A", "cms", "beat", "--loglevel=INFO"]
|
||||||
depends_on:
|
depends_on:
|
||||||
migrations:
|
migrations:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- ./custom:/home/mediacms.io/mediacms/custom:ro
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
@@ -75,7 +71,6 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- ./custom:/home/mediacms.io/mediacms/custom:ro
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
@@ -90,7 +85,6 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- ./custom:/home/mediacms.io/mediacms/custom:ro
|
|
||||||
- media_files:/home/mediacms.io/mediacms/media_files
|
- media_files:/home/mediacms.io/mediacms/media_files
|
||||||
- logs:/home/mediacms.io/mediacms/logs
|
- logs:/home/mediacms.io/mediacms/logs
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ urlpatterns = [
|
|||||||
re_path(r"^manage/users$", views.manage_users, name="manage_users"),
|
re_path(r"^manage/users$", views.manage_users, name="manage_users"),
|
||||||
# Media uploads in ADMIN created pages
|
# Media uploads in ADMIN created pages
|
||||||
re_path(r"^tinymce/upload/", tinymce_handlers.upload_image, name="tinymce_upload_image"),
|
re_path(r"^tinymce/upload/", tinymce_handlers.upload_image, name="tinymce_upload_image"),
|
||||||
re_path(r"^(?P<slug>[\w.-]*)$", views.get_page, name="get_page"),
|
re_path("^(?P<slug>[\w.-]*)$", views.get_page, name="get_page"), # noqa: W605
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Fix permissions on mounted volumes if running as root
|
|
||||||
if [ "$(id -u)" = "0" ]; then
|
|
||||||
echo "Fixing permissions on data directories..."
|
|
||||||
chown -R www-data:www-data /home/mediacms.io/mediacms/logs \
|
|
||||||
/home/mediacms.io/mediacms/media_files \
|
|
||||||
/home/mediacms.io/mediacms/static_files \
|
|
||||||
/var/run/mediacms 2>/dev/null || true
|
|
||||||
|
|
||||||
# If command starts with python or celery, run as www-data
|
|
||||||
if [ "${1:0:1}" != '-' ]; then
|
|
||||||
exec gosu www-data "$@"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Execute the command
|
|
||||||
exec "$@"
|
|
||||||
@@ -5,22 +5,18 @@ echo "========================================="
|
|||||||
echo "MediaCMS Migrations Starting..."
|
echo "MediaCMS Migrations Starting..."
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
|
|
||||||
# Ensure virtualenv is activated
|
# Wait for database to be ready
|
||||||
export VIRTUAL_ENV=/home/mediacms.io
|
until python manage.py migrate --check 2>/dev/null; do
|
||||||
export PATH="$VIRTUAL_ENV/bin:$PATH"
|
echo "Waiting for database to be ready..."
|
||||||
|
sleep 2
|
||||||
# Use explicit python path from virtualenv
|
done
|
||||||
PYTHON="$VIRTUAL_ENV/bin/python"
|
|
||||||
|
|
||||||
echo "Using Python: $PYTHON"
|
|
||||||
$PYTHON --version
|
|
||||||
|
|
||||||
# Run migrations
|
# Run migrations
|
||||||
echo "Running database migrations..."
|
echo "Running database migrations..."
|
||||||
$PYTHON manage.py migrate
|
python manage.py migrate
|
||||||
|
|
||||||
# Check if this is a new installation
|
# Check if this is a new installation
|
||||||
EXISTING_INSTALLATION=$(echo "from users.models import User; print(User.objects.exists())" | $PYTHON manage.py shell)
|
EXISTING_INSTALLATION=$(echo "from users.models import User; print(User.objects.exists())" | python manage.py shell)
|
||||||
|
|
||||||
if [ "$EXISTING_INSTALLATION" = "True" ]; then
|
if [ "$EXISTING_INSTALLATION" = "True" ]; then
|
||||||
echo "Existing installation detected, skipping initial data load"
|
echo "Existing installation detected, skipping initial data load"
|
||||||
@@ -28,14 +24,14 @@ else
|
|||||||
echo "New installation detected, loading initial data..."
|
echo "New installation detected, loading initial data..."
|
||||||
|
|
||||||
# Load fixtures
|
# Load fixtures
|
||||||
$PYTHON manage.py loaddata fixtures/encoding_profiles.json
|
python manage.py loaddata fixtures/encoding_profiles.json
|
||||||
$PYTHON manage.py loaddata fixtures/categories.json
|
python manage.py loaddata fixtures/categories.json
|
||||||
|
|
||||||
# Create admin user
|
# Create admin user
|
||||||
RANDOM_ADMIN_PASS=$($PYTHON -c "import secrets;chars = 'abcdefghijklmnopqrstuvwxyz0123456789';print(''.join(secrets.choice(chars) for i in range(10)))")
|
RANDOM_ADMIN_PASS=$(python -c "import secrets;chars = 'abcdefghijklmnopqrstuvwxyz0123456789';print(''.join(secrets.choice(chars) for i in range(10)))")
|
||||||
ADMIN_PASSWORD=${ADMIN_PASSWORD:-$RANDOM_ADMIN_PASS}
|
ADMIN_PASSWORD=${ADMIN_PASSWORD:-$RANDOM_ADMIN_PASS}
|
||||||
|
|
||||||
DJANGO_SUPERUSER_PASSWORD=$ADMIN_PASSWORD $PYTHON manage.py createsuperuser \
|
DJANGO_SUPERUSER_PASSWORD=$ADMIN_PASSWORD python manage.py createsuperuser \
|
||||||
--no-input \
|
--no-input \
|
||||||
--username=${ADMIN_USER:-admin} \
|
--username=${ADMIN_USER:-admin} \
|
||||||
--email=${ADMIN_EMAIL:-admin@localhost} \
|
--email=${ADMIN_EMAIL:-admin@localhost} \
|
||||||
@@ -46,6 +42,10 @@ else
|
|||||||
echo "========================================="
|
echo "========================================="
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Collect static files
|
||||||
|
echo "Collecting static files..."
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
echo "Migrations completed successfully!"
|
echo "Migrations completed successfully!"
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
|
|||||||
Reference in New Issue
Block a user