Overview
QFieldCloud requires HTTPS for secure communication. You can use:
- Let’s Encrypt - Free, automated certificates (recommended for production)
- Self-signed certificates - Automatically generated for development
- Custom certificates - Bring your own certificates
Let’s Encrypt (Recommended)
Let’s Encrypt provides free, automated SSL certificates that are trusted by all modern browsers.
Prerequisites
- Public domain name pointing to your server
- Ports 80 and 443 accessible from the internet
- DNS records properly configured
Configuration
1. Update Environment Variables
Edit your .env file:
# Set your domain
QFIELDCLOUD_HOST=qfield.yourcompany.com
# Configure Let's Encrypt
LETSENCRYPT_EMAIL=[email protected]
LETSENCRYPT_RSA_KEY_SIZE=4096
# Use staging for testing (no rate limits)
LETSENCRYPT_STAGING=1 # Change to 0 for production
# Configure certificate paths
QFIELDCLOUD_TLS_CERT="/etc/letsencrypt/live/${QFIELDCLOUD_HOST}/fullchain.pem"
QFIELDCLOUD_TLS_KEY="/etc/letsencrypt/live/${QFIELDCLOUD_HOST}/privkey.pem"
2. Initialize Let’s Encrypt
Run the initialization script:
./scripts/init_letsencrypt.sh
This script will:
- Request a certificate from Let’s Encrypt
- Store certificates in
./conf/certbot/conf
- Configure nginx to use the certificates
- Set up automatic renewal
Testing First: Always start with LETSENCRYPT_STAGING=1 to avoid hitting Let’s Encrypt rate limits during testing. Once everything works, change to LETSENCRYPT_STAGING=0 and re-run the script.
3. Verify Certificate
Check that your certificate was issued:
docker compose exec nginx ls -la /etc/letsencrypt/live/${QFIELDCLOUD_HOST}/
You should see:
fullchain.pem - Full certificate chain
privkey.pem - Private key
cert.pem - Server certificate
chain.pem - Intermediate certificates
4. Test HTTPS
Access your instance:
curl https://qfield.yourcompany.com/api/v1/status/
Or open in a browser and check for the padlock icon.
Automatic Renewal
Let’s Encrypt certificates are valid for 90 days. The certbot container automatically renews certificates:
- Checks for renewal twice daily
- Renews certificates within 30 days of expiration
- Automatically reloads nginx after renewal
You can manually trigger renewal:
docker compose exec certbot certbot renew
Let’s Encrypt Script Details
The init_letsencrypt.sh script performs the following:
#!/bin/bash
set -e
# Load environment variables
set -o allexport
source .env
set +o allexport
echo "### Requesting Let's Encrypt certificate for $QFIELDCLOUD_HOST ..."
domain_args="-d ${QFIELDCLOUD_HOST}"
# Enable staging mode if needed
if [ $LETSENCRYPT_STAGING != "0" ]; then staging_arg="--staging"; fi
# Request certificate
docker compose run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
$domain_args \
--email $LETSENCRYPT_EMAIL \
--rsa-key-size $LETSENCRYPT_RSA_KEY_SIZE \
--agree-tos \
--force-renewal" certbot
echo
echo "### Reloading nginx ..."
docker compose exec nginx nginx -s reload
Troubleshooting Let’s Encrypt
Rate Limit Errors
Error: too many certificates already issued
Solution: Let’s Encrypt has rate limits. Use staging mode for testing:
DNS Not Resolving
Error: Failed to connect to host
Solution: Verify DNS is properly configured:
dig qfield.yourcompany.com
nslookup qfield.yourcompany.com
Port 80 Not Accessible
Error: Connection refused or Timeout
Solution: Ensure port 80 is open and accessible:
# Check if port is listening
sudo netstat -tlnp | grep :80
# Test external access
curl http://qfield.yourcompany.com/.well-known/acme-challenge/test
Certificate Not Loading
Error: nginx still using self-signed certificate
Solution:
- Verify certificate paths in
.env
- Check certificate files exist:
docker compose exec nginx ls -la /etc/letsencrypt/live/${QFIELDCLOUD_HOST}/
- Reload nginx:
docker compose exec nginx nginx -s reload
Self-Signed Certificates
QFieldCloud automatically generates self-signed certificates for development and testing.
Automatic Generation
On first startup, the mkcert container automatically:
- Creates a local Certificate Authority (CA)
- Generates a certificate for
QFIELDCLOUD_HOST
- Stores certificates in
./conf/nginx/certs/
Certificates are generated for the domain specified in QFIELDCLOUD_HOST:
mkcert:
image: vishnunair/docker-mkcert
environment:
domain: ${QFIELDCLOUD_HOST}
volumes:
- ./conf/nginx/certs/:/root/.local/share/mkcert/
command: /bin/sh -c 'mkcert -install && for i in $$(echo $$domain | sed "s/,/ /g"); do [ ! -f /root/.local/share/mkcert/$$i.pem ] && mkcert $$i; done && tail -f -n0 /etc/hosts'
Trust Self-Signed Certificate
Browsers and tools will show security warnings for self-signed certificates. To trust them:
On Debian/Ubuntu
# Copy root certificate
sudo cp ./conf/nginx/certs/rootCA.pem /usr/local/share/ca-certificates/rootCA.crt
# Update certificate store
sudo update-ca-certificates
Verify Trust
curl https://localhost/api/v1/status/
No certificate errors should appear.
Remove Self-Signed Certificate
If you need to remove or regenerate the certificate:
# Remove certificate
sudo rm /usr/local/share/ca-certificates/rootCA.crt
# Update certificate store
sudo update-ca-certificates --fresh
# Remove generated certificates
rm -rf ./conf/nginx/certs/*
# Restart to regenerate
docker compose restart mkcert nginx
Configuration
Default configuration for self-signed certificates:
# In .env
QFIELDCLOUD_HOST=localhost
QFIELDCLOUD_TLS_CERT="/etc/nginx/certs/${QFIELDCLOUD_HOST}.pem"
QFIELDCLOUD_TLS_KEY="/etc/nginx/certs/${QFIELDCLOUD_HOST}-key.pem"
Development Only: Self-signed certificates should only be used for development and testing. Never use them in production!
Custom Certificates
You can use your own SSL certificates from any Certificate Authority.
Installation
1. Place Certificate Files
Copy your certificate files to the nginx certs directory:
# Create directory if it doesn't exist
mkdir -p ./conf/nginx/certs/
# Copy certificate and key
cp /path/to/your/certificate.pem ./conf/nginx/certs/
cp /path/to/your/private-key.pem ./conf/nginx/certs/
# Set proper permissions
chmod 600 ./conf/nginx/certs/private-key.pem
chmod 644 ./conf/nginx/certs/certificate.pem
Update .env with certificate paths:
QFIELDCLOUD_TLS_CERT="/etc/nginx/certs/certificate.pem"
QFIELDCLOUD_TLS_KEY="/etc/nginx/certs/private-key.pem"
3. Generate Diffie-Hellman Parameters
For enhanced security, generate DH parameters:
# Create directory
mkdir -p ./conf/nginx/dhparams/
# Generate parameters (takes several minutes)
openssl dhparam -out ./conf/nginx/dhparams/ssl-dhparams.pem 4096
# Set in .env
QFIELDCLOUD_TLS_DHPARAMS="/etc/nginx/dhparams/ssl-dhparams.pem"
Generating 4096-bit DH parameters can take 10-30 minutes. You can use 2048-bit for faster generation, but 4096-bit is more secure.
4. Restart Services
docker compose restart nginx
Certificate Requirements
Your certificates must:
- Be in PEM format
- Include the full certificate chain
- Match your domain name
- Not be expired
- Have proper permissions (key file: 600, cert file: 644)
Verify Custom Certificate
# Check certificate details
openssl x509 -in ./conf/nginx/certs/certificate.pem -text -noout
# Verify certificate matches key
openssl x509 -in ./conf/nginx/certs/certificate.pem -noout -modulus | md5sum
openssl rsa -in ./conf/nginx/certs/private-key.pem -noout -modulus | md5sum
# The MD5 hashes should match
# Test HTTPS
curl -v https://qfield.yourcompany.com/api/v1/status/
Additional Nginx Configuration
You can add custom nginx configuration by placing .conf files in:
Example - Add custom headers:
# ./conf/nginx/config.d/security-headers.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
These files are automatically included in the main nginx.conf.
TLS/SSL Best Practices
Security Recommendations
-
Always use HTTPS in production
DEBUG=0
QFIELDCLOUD_TLS_CERT="/etc/letsencrypt/live/${QFIELDCLOUD_HOST}/fullchain.pem"
QFIELDCLOUD_TLS_KEY="/etc/letsencrypt/live/${QFIELDCLOUD_HOST}/privkey.pem"
-
Enable HSTS (HTTP Strict Transport Security)
# In ./conf/nginx/config.d/hsts.conf
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
-
Use strong cipher suites
- Let’s Encrypt automatically uses strong ciphers
- nginx is configured with secure defaults
-
Enable OCSP stapling
- Enabled by default in QFieldCloud’s nginx configuration
-
Regular certificate renewal
- Let’s Encrypt automatically renews every 60 days
- Monitor certificate expiration dates
Certificate Monitoring
Check certificate expiration:
# For Let's Encrypt
docker compose exec certbot certbot certificates
# For any certificate
echo | openssl s_client -servername qfield.yourcompany.com -connect qfield.yourcompany.com:443 2>/dev/null | openssl x509 -noout -dates
Set up monitoring alerts for certificates expiring within 30 days.
Troubleshooting
Mixed Content Warnings
Issue: Browser shows mixed content warnings
Solution: Ensure all resources load over HTTPS. Check:
- External scripts and stylesheets
- API endpoints
- WebSocket connections
Certificate Chain Issues
Issue: “Unable to verify certificate chain”
Solution:
- Ensure full certificate chain is included
- Check intermediate certificates are present
- Verify certificate order (server cert → intermediates → root)
nginx Configuration Errors
Issue: nginx won’t start after certificate change
Solution:
# Test nginx configuration
docker compose exec nginx nginx -t
# Check nginx logs
docker compose logs nginx
# Verify file paths and permissions
docker compose exec nginx ls -la /etc/nginx/certs/
docker compose exec nginx ls -la /etc/letsencrypt/live/
SSL Test
Test your SSL configuration:
# Quick test
curl -vI https://qfield.yourcompany.com
# Detailed analysis
nmap --script ssl-enum-ciphers -p 443 qfield.yourcompany.com
For comprehensive testing, use:
Next Steps
After configuring SSL certificates:
- Test HTTPS access thoroughly
- Configure Database and Storage
- Set up monitoring for certificate expiration
- Review Environment Configuration
- Implement regular backup procedures