Skip to main content

Overview

QFieldCloud requires HTTPS for secure communication. You can use:
  1. Let’s Encrypt - Free, automated certificates (recommended for production)
  2. Self-signed certificates - Automatically generated for development
  3. Custom certificates - Bring your own certificates
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:
LETSENCRYPT_STAGING=1

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:
  1. Verify certificate paths in .env
  2. Check certificate files exist:
    docker compose exec nginx ls -la /etc/letsencrypt/live/${QFIELDCLOUD_HOST}/
    
  3. 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

2. Configure Environment

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:
./conf/nginx/config.d/
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

  1. 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"
    
  2. Enable HSTS (HTTP Strict Transport Security)
    # In ./conf/nginx/config.d/hsts.conf
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
  3. Use strong cipher suites
    • Let’s Encrypt automatically uses strong ciphers
    • nginx is configured with secure defaults
  4. Enable OCSP stapling
    • Enabled by default in QFieldCloud’s nginx configuration
  5. 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:
  1. Test HTTPS access thoroughly
  2. Configure Database and Storage
  3. Set up monitoring for certificate expiration
  4. Review Environment Configuration
  5. Implement regular backup procedures

Build docs developers (and LLMs) love