Plan your subdomains like production systems (what you’re building determines the controls)
Law firms increasingly run client portals, AI assistants, and intake forms on subdomains. This practical checklist covers DNS, TLS, WAF, Droplet hardening, and change governance.
Law firms increasingly run client portals, AI assistants, intake forms, and webhooks on subdomains (for example, portal.yourfirm.com). Done right, this keeps client-facing systems on a familiar, trustworthy domain; done wrong, a DNS/TLS/proxy misstep can expose confidential data — or break email deliverability. This section gives you a practical, end-to-end checklist to stand up subdomains on DigitalOcean behind Cloudflare and then keep them governed like production systems. If you want us to review your Cloudflare + DigitalOcean configuration for a client-facing portal, contact Promise Legal.
Mental model: Registrar → Cloudflare DNS → Cloudflare edge (WAF/TLS) → DigitalOcean Droplet (origin).
- Inventory every subdomain; classify: portal/AI/intake/API/webhooks/email-only.
- Preserve email DNS before changes: MX, SPF, DKIM, DMARC.
- Pick proxy mode per record (proxied for web apps; DNS-only for email-related hostnames).
- Set SSL/TLS to Full (strict); enforce HTTPS; add HSTS cautiously.
- Harden the Droplet: SSH keys, non-root sudo, UFW/firewall rules.
- Choose an origin cert strategy (Origin CA or Let’s Encrypt) + automate renewal.
- Backups & patching: define cadence and run a test restore.
- Access controls: SSO/MFA, least privilege, audit logs (Cloudflare + DO).
- Change governance: change review, rollback plan, and post-change verification.
Related reading: Why subdomains matter for modern law firms and How to set up a subdomain using Cloudflare and a DigitalOcean Droplet for lawyers.
Before you create any DNS records, treat each subdomain as its own “application boundary” with an owner, a risk profile, and minimum controls. Start by building a simple inventory table with: subdomain, purpose (portal/AI/intake), data sensitivity, auth method, business owner, vendor/hosting, and an uptime target. This one sheet becomes your source of truth for audits, renewals, and change review.
Next, decide Proxied vs DNS-only per hostname. Choose Proxied (orange cloud) when you need Cloudflare protections (WAF, rate limiting, bot mitigation), want to hide the origin IP, or can benefit from caching. Choose DNS-only (gray cloud) for email-related records and for services that don’t behave correctly behind a reverse proxy.
Finally, use governance-friendly names: portal., intake., assistant., api., status. Avoid mixing marketing pages and sensitive workflows on the same hostname.
- portal.examplelaw.com (proxied, WAF)
- intake.examplelaw.com (proxied, rate limits on submissions)
- assistant.examplelaw.com (proxied, strict auth + logging)
For more patterns and use cases, see Subdomains for Law Firms: Building Client Portals, AI Tools, and Internal Systems.
Preserve DNS and email deliverability before you touch Cloudflare proxying
Goal: add or change subdomains without interrupting firm email. Before you switch nameservers or start clicking the orange cloud, export the current DNS zone (CSV/zone file/screenshot) so you can rapidly roll back.
- Identify email-critical records and mark them “hands off”: MX, SPF (TXT), DKIM (TXT/CNAME selectors), DMARC (TXT), plus any autodiscover/autoconfig records your mail provider uses.
- Key rule: Cloudflare’s standard proxy only supports web traffic (HTTP/HTTPS). Cloudflare notes that SMTP (port 25) is not proxied unless Spectrum is configured — so any DNS record used for email should remain DNS-only (gray cloud).
- Create web subdomains correctly: add an A/AAAA record from intake.yourfirm.com to the Droplet IP; proxy it only if it’s web traffic. Keep mail hostnames (for example, mail.) DNS-only.
Verify: dig MX examplelaw.com; dig TXT examplelaw.com (SPF/DMARC); and confirm DKIM selector records resolve exactly as your provider specifies.
Common pitfall: “We turned on the orange cloud for everything and email broke.” The quick fix is to switch email-related hostnames back to DNS-only and restore the original MX/SPF/DKIM/DMARC values.
Example: add intake.examplelaw.com while leaving Microsoft 365/Google Workspace records untouched. Optional: use a dedicated mail.examplelaw.com subdomain for transactional email with a strict DNS-only rule.
Configure Cloudflare SSL/TLS correctly (why Full (strict) is the baseline for client-facing legal systems)
Outcome: encrypted traffic end-to-end — browser → Cloudflare → your DigitalOcean Droplet — so client data is not exposed in transit between Cloudflare and the origin.
- Cloudflare dashboard → SSL/TLS → Overview: set encryption mode to Full (strict). This requires a valid origin certificate (unexpired, hostname matches CN/SAN, and issued by a publicly trusted CA or Cloudflare Origin CA).
- SSL/TLS → Edge Certificates: turn Always Use HTTPS on; enable Automatic HTTPS Rewrites only if your app still serves mixed HTTP asset links; set Minimum TLS Version to 1.2+ (or 1.3 when compatible).
- Origin authentication: choose Cloudflare Origin Certificate (best when you always front the service with Cloudflare) or Let’s Encrypt (best when you need direct origin access). If available, enable Authenticated Origin Pulls (mTLS) so only Cloudflare can connect to the origin.
- HSTS: start with a short max-age and expand gradually; do not preload until you’ve validated every subdomain and redirect path.
Verify: run curl -I https://subdomain.examplelaw.com and confirm a clean 301/200 chain, no redirect loop, and that you are not using Flexible SSL.
Troubleshooting: 526 usually means Cloudflare cannot validate the origin certificate (expired/mismatched hostname/incomplete chain). 525 typically indicates an SSL handshake failure — confirm the origin is listening on 443 with the expected cert and ciphers.
Example: portal.examplelaw.com served by Nginx on a Droplet with a Cloudflare Origin Certificate installed; Cloudflare set to Full (strict).
Choose Cloudflare proxy, WAF, and rate limiting settings that fit portals, AI assistants, and intake forms
Start with a simple rule: anything that accepts credentials, uploads, or client narratives should be proxied unless you have a documented exception. Then tailor controls to the workload.
- Client portal: Proxied; enable WAF managed rules + bot protection; apply stricter rate limits on /login and password reset.
- Intake forms: Proxied; rate limit POST endpoints; add Turnstile/CAPTCHA where appropriate.
- AI assistant (web/app/API): Proxied; WAF + API protections (API Shield if available); aggressive abuse controls on chat and token-heavy endpoints.
- Third-party webhooks: often DNS-only (some senders can’t tolerate proxying) or proxied with strict allowlists — document the choice either way.
Cloudflare hardening steps: go to Security → WAF and turn on managed rules, then tune (reduce false positives on client portals). In Security → Bots/Rate Limiting, protect login, password reset, and form-submit routes. In DNS, decide orange/gray cloud per record and write down why any sensitive hostname is DNS-only. For admin surfaces, use Cloudflare Access (Zero Trust) to require SSO and restrict by group.
Example: for assistant.examplelaw.com, rate limit /api/chat and restrict /admin to an SSO group via Cloudflare Access. For broader AI governance considerations beyond edge controls, see Navigating Agentic AI: Understanding Functionality, Risks, and Governance.
Harden the DigitalOcean Droplet like it holds client data (because it does)
Assume any portal/AI/intake subdomain processes confidential client information. Your Droplet should be hardened like a production system, not a dev box.
- Create a non-root user and grant sudo; keep root for emergency recovery only.
- Enforce SSH keys only: disable password authentication and disable root SSH login in /etc/ssh/sshd_config.
- SSH configuration: changing the default port is optional (it reduces noise but doesn’t replace key-based auth). If you change it, document it and ensure your firewall matches.
- Firewall (UFW) baseline:
ufw allow OpenSSHufw allow 80/tcpandufw allow 443/tcp(or restrict 80 if you only redirect)ufw default deny incoming
- Advanced: consider restricting inbound 443 to Cloudflare IP ranges to reduce direct-to-origin exposure (but plan for maintenance access and Cloudflare IP updates).
- fail2ban (optional): add sensible jails for SSH and review bans to avoid locking out legitimate admins.
- Logging: confirm auth logs are enabled; centralize logs if feasible so you can investigate incidents even if the Droplet is compromised.
Verify: SSH as the non-root user succeeds; password login fails; a port scan shows only intended ports open.
Example: an intake app Droplet exposes only 80/443 publicly; SSH (22) is restricted to admin IPs/VPN; the admin panel is placed behind SSO via Cloudflare Access.
Manage certificates and renewals without “hero work” (origin cert strategy + automation)
Goal: prevent certificate-expiry outages and keep Cloudflare Full (strict) working reliably for client-facing subdomains.
Option A: Cloudflare Origin Certificate (best when the service is always behind Cloudflare). Install the origin cert and key on the Droplet (Nginx/Apache) and treat renewal as an operational task: set a calendar reminder well before expiration and, where possible, script replacement + service reload. Limitation: Origin certs are trusted by Cloudflare, not by browsers — so they won’t work if users bypass Cloudflare and hit the Droplet directly.
Option B: Let’s Encrypt (best when you need direct origin access or want multi-CDN flexibility). Use certbot and rely on systemd timers/cron for auto-renew, plus an automatic Nginx/Apache reload.
- Store private keys with least-privilege filesystem permissions; restrict who can read them.
- Document cert file paths, the renewal method, and exact reload commands.
- Monitor expiry (alerts at 30/14/7 days) so renewals aren’t “hero work.”
Troubleshooting: redirect loops often happen when both Cloudflare and the origin force HTTPS inconsistently; fix by standardizing on one redirect strategy and confirming the app sees the correct scheme (e.g., X-Forwarded-Proto). Mixed-content warnings usually mean the app still serves HTTP asset URLs — update app config or use targeted rewrites.
Example: a portal uses a Cloudflare Origin Certificate on the Droplet, Cloudflare is set to Full (strict), and redirects are tested end-to-end in staging before production rollout.
Build resilience: backups, patching cadence, and a test restore (the part firms skip until it hurts)
Security controls don’t matter if you can’t recover quickly from a bad deploy, compromised credential, or disk failure. Treat resilience as a required control for any client-facing portal, intake form, or AI system.
- Backups: enable DigitalOcean Backups and/or scheduled snapshots. If you run a database, back it up separately from the Droplet image (and test consistency). Encrypt backups where possible, restrict who can access/restore them, and define RPO/RTO that match business expectations (intake and portals usually need tighter targets than marketing sites).
- Patching: apply OS security updates weekly; review app dependencies monthly. Plan reboots and maintenance windows (including client communications when appropriate) and track OS end-of-life dates so you’re not forced into emergency migrations.
- Test restore (write it down): restore a snapshot to a new Droplet in a staging project/VPC, validate the app, TLS, and login flow, then document the exact steps and the time it took.
Example: after a broken release, you roll back by restoring the last-known-good snapshot and redeploying Nginx/app configuration from version control, then re-running your verification checklist before reopening intake.
Control access like a firm, not a hobby project (SSO, least privilege, auditability)
Most law-firm outages and security incidents around subdomains start with an access mistake: too many admins, shared accounts, or no logs. Your goal is SSO + least privilege + auditability across Cloudflare, DigitalOcean, and the app.
- Cloudflare: require SSO (Google Workspace/M365/Okta) and MFA for all users; use security keys for privileged roles. Separate roles so “DNS editor” can manage specific records, “security admin” can change WAF/TLS, and “billing” cannot touch production settings. Review audit logs on a set cadence (e.g., weekly) for DNS changes, firewall rule edits, and new API tokens.
- DigitalOcean: separate projects by environment (prod vs staging), assign team roles, and promptly remove access on departures. Use API tokens sparingly, store them in a secrets manager, and rotate them on a schedule and after any suspected exposure.
- Application: put admin routes (e.g., /admin) behind SSO/allowlists (Cloudflare Access, VPN, or both). Use service accounts for automation and scope them to the minimum permissions required.
Example: a marketing vendor can update www DNS records but cannot access portal/assistant hostnames, Cloudflare WAF settings, or the DigitalOcean production project.
Establish change-review governance (a lightweight process that prevents outages and security regressions)
For law firms, DNS/TLS/WAF changes are high-impact: a single toggle can take down intake, lock clients out of a portal, or silently weaken encryption. The fix is a lightweight, repeatable change-review process that makes risky edits deliberate and reversible.
Copy/paste change request template:
- Objective: what are we changing and why?
- Affected subdomain(s): hostname(s) + environment (prod/staging).
- Risk level: low/medium/high (and why).
- Planned time: window + who is on point.
- Approver: named owner (two-person rule for prod DNS/WAF/SSL).
- Rollback plan: exact steps to revert (DNS export, previous WAF rule, prior cert).
- Validation steps: what must work before closing the change.
Use maintenance windows and define client-communication triggers (e.g., portal downtime > 5 minutes). Keep a logged, time-bound break-glass procedure for emergencies.
Config management: store DNS exports, firewall rules, and Nginx configs in a private repo; maintain a runbook for key rotation, access revocation, and restores.
Post-change verification: DNS resolves; TLS is Full (strict) and valid; login/intake submissions work; email records are unchanged; Cloudflare rules aren’t overblocking.
Next steps: inventory subdomains, standardize on Full (strict), implement backups + test restore, enable SSO/least privilege, and schedule an independent configuration review with Promise Legal.