Skip to main content

Let's Encrypt Setup for FileWave Server (macOS)

This article is in beta. Please reach out to josh.levitsky@filewave.com to use this together while this banner is here so that we can just validate that everything works well for you. I'll remove this banner once I'm aware of several positive outcomes. 

Feb 24, 2026 - Initial Version published for macOS. 

What

This Knowledge Base (KB) article covers the macOS FileWave Let’s Encrypt script:

  • filewave-letsencrypt-macos.zsh

The script supports two challenge methods:

  • HTTP-01 (standalone certbot)
  • DNS-01 (Cloudflare API token)

Both paths handle certificate request, FileWave certificate injection, and renewal automation.

When/Why

Use this when your FileWave server runs on macOS and you need a trusted SSL certificate for secure communication.

  • Use HTTP-01 when TCP/80 can be reached from the internet.
  • Use DNS-01 (Cloudflare) when TCP/80 is blocked/unavailable, or you prefer DNS validation.

This documented process is for macOS 14 or newer. If you are a Hosted customer, FileWave can handle certificate management for you: SSL Certificate Management for Custom Domains (FileWave-Hosted Servers).

How

Prerequisites

  • FileWave server on macOS 14 or newer
  • Root/sudo access
  • Public DNS name (FQDN) for the FileWave server
  • Homebrew installed (https://brew.sh)
  • If using DNS validation: Cloudflare API token with DNS edit permissions for the zone
  • DNS utilities available (nslookup or dig)

If TCP/80 is not available, select DNS-01 (Cloudflare) during install.

Homebrew note

The script must be launched with sudo from a normal macOS admin account (so Homebrew actions can run as the invoking user).

    ✅ Expected: user shell → sudo ./filewave-letsencrypt-macos.zsh --install ❌ Not supported: direct root shell (sudo su - then run script)

    If Homebrew is missing, the script stops and prompts you to install Homebrew from https://brew.sh, then re-run the script.run.

    Install steps

    1. Download the script with wget:

      wget -O filewave-letsencrypt-macos.zsh https://kb.filewave.com/attachments/498
      
    2. Make it executable:

      chmod +x filewave-letsencrypt-macos.zsh
      
    3. Run install:

      sudo ./filewave-letsencrypt-macos.zsh --install
      
    4. Follow prompts for:

      • Hostname (FQDN)
      • Email
      • Validation method:
        • 1 = HTTP-01
        • 2 = DNS-01 (Cloudflare)
      • If DNS-01 is selected: Cloudflare API token
    5. Confirm values when prompted.

    6. Verify output for success messages and final summary.

    What the script does

    • Validates macOS version (14+) and root execution
    • Validates that FileWave server paths exist (/usr/local/bin/fwcontrol, /usr/local/filewave/certs)
    Validates hostname and email Validates DNS resolution (tries 8.8.8.8, then system resolver fallback) Backs up existing certs under /usr/local/filewave/certs/backup-<timestamp>/ Installs/validates certbot Requests a new certificate using the selected challenge method For DNS-01 (Cloudflare): creates /etc/letsencrypt/secrets/cloudflare.ini automatically with secure permissions Updates FileWave mdm_cert_trusted DB flag (when FileWave PostgreSQL binary exists) Creates renewal deploy hook:
    • /etc/letsencrypt/renewal-hooks/deploy/filewave-server-cert.sh
    Preserves existing cert file owner/group when replacing certificates Creates launchd renewal automation:
    • /Library/LaunchDaemons/com.filewave.letsencrypt.renew.plist
    • /usr/local/filewave/sbin/filewave-letsencrypt-renew.zsh
    Immediately injects cert into FileWave and restarts server services

    Uninstall

    To remove integration files created by the script:

    sudo ./filewave-letsencrypt-macos.zsh --uninstall
    

    This removes FileWave renewal hook, launch daemon/runner files, legacy cron file (if present), and Cloudflare credentials file (if present). The script intentionally leaves certbot installed.

    DNS-01 Cloudflare plugin details (macOS)

    If the Cloudflare plugin is missing, the script attempts installation using Certbot’s Homebrew Python environment:

    $(brew --prefix certbot)/libexec/bin/python3 -m pip install certbot-dns-cloudflare
    

    Manual verification:

    certbot plugins | grep -i cloudflare
    

    Validation / test commands

    Confirm launchd job is loaded

    sudo launchctl print system/com.filewave.letsencrypt.renew
    

    Optional forced renewal test

    sudo certbot renew --force-renewal
    

    Troubleshooting

    1) FileWave server prerequisites failed

    If script reports missing FileWave binaries/paths:

      Verify /usr/local/bin/fwcontrol exists. Verify /usr/local/filewave/certs exists. Re-run on the FileWave server host (not a non-FileWave Mac).

      2) Certificate request failed (HTTP-01)

      Ensure inbound TCP/80 is reachable, then retry:

      sudo certbot -n --agree-tos --standalone certonly -d "<FQDN>" -m "<EMAIL>"
      sudo certbot renew --force-renewal
      

      2)3) Certificate request failed (DNS-01 Cloudflare)

      Ensure token permissions and retry:

      sudo certbot -n --agree-tos --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/secrets/cloudflare.ini certonly -d "<FQDN>" -m "<EMAIL>"
      sudo certbot renew --force-renewal
      

      3)4) FileWave UI shows old certificate behavior

      If older behavior persists, verify mdm_cert_trusted is set in PostgreSQL:

      image.png

      /usr/local/filewave/postgresql/bin/psql -d mdm -U django
      
      insert into ios_preferences values('mdm_cert_trusted', TRUE) on conflict (key) do nothing;
      
      update ios_preferences set value='true' where key='mdm_cert_trusted';
      
      \q
      

      4)5) launchd renewal not running

      • Verify daemon loaded:

        sudo launchctl print system/com.filewave.letsencrypt.renew
        
      • Inspect renewal log:

        sudo tail -n 200 /var/log/filewave-letsencrypt-renew.log