HTTPS Configuration
D2L requires HTTPS for iframe embedding. Here's how to set it up.
Why HTTPS?
- D2L requirement — Iframes must load over HTTPS
- Security — Protects student data in transit
- Browser policies — Modern browsers block mixed content
Option 1: Cloudflare (Recommended)
The easiest approach for most deployments.
Setup Steps
Add your domain to Cloudflare
- Sign up at cloudflare.com
- Add your domain and update nameservers
Enable SSL/TLS
- Go to SSL/TLS settings
- Set encryption mode to Full or Full (strict)
Configure DNS
- Add an A record pointing to your server IP
- Enable the orange cloud (proxy)
Done!
- Cloudflare provides free SSL certificates
- Automatic certificate renewal
Advantages
- Free SSL certificates
- Automatic renewal
- DDoS protection
- CDN caching
Option 2: Let's Encrypt
Free certificates directly on your server.
Install Certbot
bash
# Ubuntu/Debian
sudo apt update
sudo apt install certbot
# CentOS/RHEL
sudo yum install certbotGet Certificate
bash
# Stop your server temporarily
pm2 stop gradescope-submitter
# Get certificate (standalone mode)
sudo certbot certonly --standalone -d your-domain.com
# Restart server
pm2 start gradescope-submitterCopy Certificates
bash
# Create keys directory
mkdir -p keys
# Copy certificates
sudo cp /etc/letsencrypt/live/your-domain.com/privkey.pem keys/origin-cert.key
sudo cp /etc/letsencrypt/live/your-domain.com/fullchain.pem keys/origin-cert.pem
# Set permissions
sudo chown $USER:$USER keys/*.pem
chmod 600 keys/*.pemAuto-Renewal
Let's Encrypt certificates expire every 90 days. Set up auto-renewal:
bash
# Test renewal
sudo certbot renew --dry-run
# Add to crontab
sudo crontab -eAdd this line:
0 0 1 * * certbot renew --post-hook "pm2 restart gradescope-submitter"Option 3: Self-Signed (Development Only)
WARNING
Self-signed certificates will show browser warnings. Only use for local development.
bash
# Create keys directory
mkdir -p keys
# Generate self-signed certificate
openssl req -x509 -newkey rsa:4096 \
-keyout keys/origin-cert.key \
-out keys/origin-cert.pem \
-days 365 \
-nodes \
-subj "/CN=localhost"Server Configuration
The Express server automatically starts HTTPS if certificates exist in keys/:
javascript
// From app.js
if (fs.existsSync('keys/origin-cert.key')) {
const httpsOptions = {
key: fs.readFileSync('keys/origin-cert.key'),
cert: fs.readFileSync('keys/origin-cert.pem')
};
https.createServer(httpsOptions, app).listen(3443, () => {
console.log('HTTPS server running on port 3443');
});
}Ports
| Protocol | Default Port | Usage |
|---|---|---|
| HTTP | 3000 | Development, redirects |
| HTTPS | 3443 | Production |
Firewall Configuration
Ensure your firewall allows HTTPS traffic:
bash
# Ubuntu/Debian with UFW
sudo ufw allow 443/tcp
sudo ufw allow 3443/tcp
# CentOS/RHEL with firewalld
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=3443/tcp
sudo firewall-cmd --reloadReverse Proxy (Optional)
For production, consider using Nginx as a reverse proxy:
nginx
server {
listen 443 ssl;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}Verifying HTTPS
- Browser check — Visit
https://your-domain.comand look for the lock icon - SSL Labs — Test at ssllabs.com/ssltest
- curl test:
bash
curl -I https://your-domain.comTroubleshooting
Certificate not found
- Verify files exist in
keys/directory - Check file permissions (should be readable by Node.js process)
- Restart the server after adding certificates
Mixed content warnings
- Ensure all resources (CSS, JS, images) load over HTTPS
- Check for hardcoded
http://URLs in your code
Certificate expired
- Renew with
sudo certbot renew - Copy new certificates to
keys/directory - Restart the server