Installing LCOJ with Docker
This guide walks you through installing LCOJ with Docker, the recommended and simplest approach.
Repository: lcoj-docker
System requirements
Minimum hardware
- CPU: 2 cores
- RAM: 4GB
- Disk: 20GB free
- OS: Linux (Ubuntu 20.04+ recommended)
Recommended hardware
- CPU: 4+ cores
- RAM: 8GB+
- Disk: 50GB+ SSD
- Network: 100Mbps+
Software
- Docker 20.10+
- Docker Compose 2.0+
- Git
Step 1: Install Docker
Ubuntu/Debian
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Add your user to the docker group
sudo usermod -aG docker $USER
# Log out and log back in for the change to take effectVerify
docker --version
docker compose versionStep 2: Clone the repository
git clone --recursive https://github.com/luyencode/lcoj-docker.git
cd lcoj-docker/dmojNote: The --recursive flag is essential: it clones the submodules as well.
Step 3: Initialize
Run the initialization script:
./scripts/initializeThis script:
- Creates the required directories
- Copies the sample configuration files
- Sets permissions
Step 4: Configure
4.1. Create the environment files
cp environment/mysql-admin.env.example environment/mysql-admin.env
cp environment/mysql.env.example environment/mysql.env
cp environment/site.env.example environment/site.env4.2. Configure MySQL
File: environment/mysql.env
MYSQL_DATABASE=lcoj
MYSQL_USER=lcoj
MYSQL_PASSWORD=<strong_password>File: environment/mysql-admin.env
MYSQL_ROOT_PASSWORD=<strong_root_password>Note: Replace <strong_password> with an actual password!
4.3. Configure the site
File: environment/site.env
# Database
MYSQL_HOST=db
MYSQL_DATABASE=lcoj
MYSQL_USER=lcoj
MYSQL_PASSWORD=<same_as_mysql.env>
# Site
SITE_NAME=LCOJ
SITE_LONG_NAME=LuyenCode Online Judge
SITE_ADMIN_EMAIL=[email protected]
# Secret key (generate a new one)
SECRET_KEY=<long_random_secret_key>
# Host
HOST=luyencode.net
# Debug (MUST BE CHANGED TO False IN PRODUCTION)
DEBUG=TrueGenerate a SECRET_KEY:
python3 -c "import secrets; print(secrets.token_urlsafe(50))"4.4. Configure Nginx
File: nginx/conf.d/nginx.conf
Change server_name:
server {
listen 80;
server_name luyencode.net; # Change to your domain
# ... leave the rest unchanged
}Step 5: Build the Docker images
docker compose buildThis takes 10–20 minutes, depending on your network speed and machine.
Step 6: Start the services
6.1. Start the database and cache
docker compose up -d db redisWait about 10 seconds for the database to finish starting up.
6.2. Start the site and Celery
docker compose up -d site celery6.3. Create the database schema
./scripts/migrate6.4. Generate static files
./scripts/copy_static6.5. Load sample data
./scripts/manage.py loaddata navbar
./scripts/manage.py loaddata language_small
./scripts/manage.py loaddata demoWarning: demo creates an admin account with username and password admin. Change it immediately after logging in!
6.6. Create a superuser
./scripts/manage.py createsuperuserFollow the prompts to create your admin account.
Step 7: Start all services
docker compose up -dCheck that all containers are running:
docker compose psYou should see:
NAME STATUS
lcoj_bridged Up
lcoj_celery Up
lcoj_mysql Up
lcoj_nginx Up
lcoj_redis Up
lcoj_site Up
lcoj_wsevent UpStep 8: Verify
Open http://localhost (or your domain) to verify the installation.
You should see the LCOJ home page!
Directory structure
dmoj/
├── base/ # Base Docker image
├── bridged/ # Bridge service
├── celery/ # Celery worker
├── config/ # Config files
├── database/ # MySQL data (created automatically)
├── environment/ # Environment variables
├── media/ # User uploads
├── nginx/ # Nginx config
├── problems/ # Problem data
├── repo/ # Site source code (submodule)
├── scripts/ # Helper scripts
├── site/ # Site Docker image
├── wsevent/ # WebSocket event server
└── docker-compose.yml # Docker Compose configServices
| Service | Container | Port | Description |
|---|---|---|---|
| nginx | lcoj_nginx | 80 | Web server |
| site | lcoj_site | - | Django application |
| celery | lcoj_celery | - | Background tasks |
| bridged | lcoj_bridged | 9998, 9999 | Judge bridge |
| wsevent | lcoj_wsevent | 15100-15102 | WebSocket events |
| db | lcoj_mysql | 3306 | MariaDB database |
| redis | lcoj_redis | 6379 | Cache & message broker |
Managing services
View logs
# All services
docker compose logs -f
# A specific service
docker compose logs -f site
docker compose logs -f celery
docker compose logs -f nginxRestart a service
docker compose restart site
docker compose restart celeryStop everything
docker compose downStart again
docker compose up -dUpdating
Update the code
cd lcoj-docker/dmoj
git pull
git submodule update --init --recursiveRebuild and restart
docker compose up -d --build site celery bridged wseventRun migrations
./scripts/migrateUpdate static files
./scripts/copy_staticBackup
Back up the database
docker exec lcoj_mysql mysqldump -u root -p<root_password> lcoj > backup_$(date +%Y%m%d).sqlBack up media files
tar -czf media_backup_$(date +%Y%m%d).tar.gz dmoj/media/Back up problems
tar -czf problems_backup_$(date +%Y%m%d).tar.gz dmoj/problems/Restore
Restore the database
docker exec -i lcoj_mysql mysql -u root -p<root_password> lcoj < backup_20240101.sqlRestore media
tar -xzf media_backup_20240101.tar.gzMonitoring
Check resource usage
docker statsCheck disk usage
docker system dfFollow logs in real time
# Site logs
docker compose logs -f --tail=100 site
# Celery logs
docker compose logs -f --tail=100 celery
# Nginx access logs
docker compose exec nginx tail -f /var/log/nginx/access.logTroubleshooting
Container won't start
# View logs
docker compose logs <service_name>
# View details
docker inspect <container_name>Database connection error
# Check that MySQL is running
docker compose ps db
# Check the logs
docker compose logs db
# Restart the database
docker compose restart dbStatic files not loading
# Re-run copy_static
./scripts/copy_static
# Restart nginx
docker compose restart nginxOut of memory
# Check memory usage
docker stats
# Raise the memory limit in docker-compose.yml
# Add to the relevant service:
deploy:
resources:
limits:
memory: 2GDisk full
# Remove unused images
docker image prune -a
# Remove unused volumes
docker volume prune
# Remove unused containers
docker container pruneProduction checklist
Before deploying to production:
Configuring HTTPS
With Let's Encrypt
# Install certbot
apt install certbot python3-certbot-nginx
# Obtain a certificate
certbot --nginx -d luyencode.net
# Auto-renew
certbot renew --dry-runUpdate the nginx config
Certbot updates the nginx config automatically. Then run:
docker compose restart nginxPerformance tuning
Increase the number of Celery workers
File: celery/Dockerfile
CMD celery -A dmoj_celery worker -l info --concurrency=4Increase the number of uWSGI workers
File: site/Dockerfile
CMD uwsgi --ini uwsgi.ini --processes=4Configure Redis persistence
File: docker-compose.yml
redis:
command: redis-server --appendonly yes
volumes:
- redis-data:/dataSee also
Support
If you run into problems:
- Check the logs:
docker compose logs -f - Open an issue on GitHub Issues
- Contact support at https://luyencode.net/about/#lien-he
