SSL Proxy for User Content
When the site is served over HTTPS but users embed images over HTTP, browsers block them (mixed content). An SSL proxy solves this problem.
Note: This feature is optional and only needed if you allow users to embed images from external sources.
Installing Camo
Camo is a proxy server that serves HTTP content over HTTPS.
Step 1: Install Node.js
curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
apt install nodejsStep 2: Install Camo
npm install -g camoStep 3: Generate a secret key
openssl rand -hex 32Save this key; you will need it in a later step.
Step 4: Run Camo
PORT=8081 CAMO_KEY="your_secret_key_here" camoConfiguring LCOJ
With Docker
Add to environment/site.env:
DMOJ_CAMO_URL=https://luyencode.net/camo
DMOJ_CAMO_KEY=your_secret_key_here
DMOJ_CAMO_EXCLUDE=luyencode.net,cdn.luyencode.netWith bare metal
Add to local_settings.py:
# Camo URL
DMOJ_CAMO_URL = "https://luyencode.net:8081"
# Secret key (must match CAMO_KEY)
DMOJ_CAMO_KEY = "your_secret_key_here"
# Domains that do not need proxying (your own domains)
DMOJ_CAMO_EXCLUDE = ["luyencode.net", "cdn.luyencode.net"]Configuring Nginx
Reverse proxy for Camo
location /camo/ {
proxy_pass http://localhost:8081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Restart
Docker:
docker compose restart nginx siteBare metal:
service nginx reload
supervisorctl restart siteRunning Camo with Supervisor
Create the file /etc/supervisor/conf.d/camo.conf:
[program:camo]
command=/usr/bin/camo
directory=/tmp
user=camo
environment=PORT="8081",CAMO_KEY="your_secret_key_here"
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/camo.logStart it:
supervisorctl update
supervisorctl start camoHow It Works
Without Camo
User -> HTTPS -> Website -> HTTP image -> ❌ BlockedWith Camo
User -> HTTPS -> Website -> HTTPS -> Camo -> HTTP image -> ✓ OKExample
Original URL:
http://example.com/image.pngURL through Camo:
https://luyencode.net/camo/abc123.../image.pngVerification
Test Camo
curl http://localhost:8081/If you see "hwhat", Camo is running.
Test the proxy
- Post a comment containing an HTTP image
- Inspect the page source
- The image URL should go through Camo
Troubleshooting
Images do not load:
- Check that Camo is running
- Check
DMOJ_CAMO_URLandDMOJ_CAMO_KEY - View Camo logs (Docker):
docker compose logs -f camo(if running in Docker) - View Camo logs (bare metal):
supervisorctl tail -f camo
Mixed content warning:
- Check that
DMOJ_CAMO_URLuses HTTPS - Check the nginx config
Images are blocked:
- Some sites block proxies
- There is no workaround; users must upload the image to the server
Security
Size limit
Add to the Camo config:
CAMO_MAX_SIZE=5242880 # 5MBFile type limit
Allow images only:
CAMO_ALLOWED_CONTENT_TYPES="image/*"Rate limiting
Use nginx to limit requests:
location /camo/ {
limit_req zone=camo burst=10;
proxy_pass http://localhost:8081/;
}Optimization
Cache
Camo caches automatically. To increase the cache time:
CAMO_TIMING_ALLOW_ORIGIN="*"
CAMO_HEADER_VIA="Camo"CDN
If you have a CDN, put Camo behind it:
User -> CDN -> Camo -> HTTP imageNotes
- Camo uses a lot of bandwidth because it proxies every image
- Limit file size and file type
- Do not proxy video (too heavy)
- Encourage users to upload images to the server instead of linking to external ones
