Articles

December 21, 2025

How To: Safely Anonymize Production Data In Laravel

In almost every company I’ve worked with, there’s a moment when someone asks: > “Can we get a copy of production data for staging or local debugging?” And almost every time, that question is followed by hesitation. Production data is valuable — but it’s also dangerous. It contains emails, names, phone numbers, IDs, and other sensitive information that shouldn’t casually move around. Yet teams still need realistic data to: - debug real-world issues - test edge cases - reproduce bugs - validate migrations - support QA and external reviews This tension is what led me to build [Veil](https://github.com/signdeck/veil). ## The problem with most “solutions” In practice, I’ve seen teams handle this in a few common (and risky) ways: - writing one-off SQL scripts to mask data - manually editing dumps - partially anonymizing only obvious columns - copying production data and “hoping for the best” These approaches are: - error-prone - inconsistent - hard to repeat - easy to forget or misconfigure And once data leaks, you can’t undo it. ## What I wanted instead I wanted a solution that was: - repeatable — the same anonymization rules every time - configuration-driven — no ad-hoc scripts - safe by default — sensitive columns are explicitly handled - usable in real workflows — not just demos Most importantly, I wanted something teams could trust when exporting production-like data. ## Introducing Veil [Veil is a Laravel package that helps you export database snapshots while anonymising sensitive columns.](https://github.com/signdeck/veil) It’s designed for scenarios like: - creating staging databases - sharing data with developers or contractors - debugging production issues locally - preparing datasets for testing or QA Instead of modifying data manually, you define anonymization rules per table and column. Veil then applies those rules consistently during export. Under the hood, Veil builds on top of `spatie/laravel-db-snapshots` and `phpmyadmin/sql-parser`, and adds a focused anonymization layer on top. The goal is simple: **keep your data useful without exposing what shouldn’t be exposed.** ## Why I open-sourced it This isn’t a theoretical problem, it’s something I’ve encountered repeatedly — across companies and teams. Rather than solving it privately again, I decided to open-source Veil so: - other teams don’t have to reinvent the same scripts - the solution can be reviewed and improved - the workflow stays transparent and predictable Open source felt like the right place for this kind of tooling. ## Where Veil fits long-term Veil is now maintained under the [SignDeck](https://getsigndeck.com) GitHub organization — alongside other open-source tools we use internally. SignDeck itself is a lightweight platform for collecting documents and signatures, where handling sensitive data responsibly is a core concern. Veil grew out of that same mindset: **treat production data with care, even when you need to work with it**. ## Sounds familiar? If you’ve ever: - needed production-like data for debugging - worried about leaking sensitive information - written masking scripts you didn’t fully trust Veil might be useful for you. You can find it here: 👉 https://github.com/signdeck/veil ⸻ ## Final note This post isn’t about tools for the sake of tools. It’s about acknowledging that data safety and developer productivity don’t have to be at odds — if the right abstractions exist. Veil is my attempt at one of those abstractions.

November 21, 2025

Protect Your Admin Panel with Cloudflare Zero Trust — For Free!

*A quick security win — no coding, no plugins, no cost.* 🎯 **Why protect your Admin Panel?** Admin URLs are like gold mines for attackers. Even if your login is secure, exposing these URLs publicly allows: - Bot scanning - Brute-force attempts - Vulnerability probing The best protection? Make them invisible to the internet. ## 🚀 Solution: Hide Admin Panel behind Cloudflare Zero Trust 🛠️ **What we'll do?** We'll block public access to `/admin` (and related URLs), and allow access only to authorized users — protected by email, Google Login, OTP or identity provider. ### Step-by-Step Setup 1️⃣ **Go to Cloudflare -> Zero Trust** - Login to Cloudflare. Then on the sidebar click **Zero Trust** - Choose the free plan, but Cloudflare will still ask you to provide payment details 2️⃣ **Manage Identity Providers** - On Zero Trust Dashboard, on the sidebar click **Integrations** -> **Identity providers** - These will provide a way for you to authenticate for your login panel. **One-time PIN** is enabled by default — this will send an OTP to the registered email address. - Of course, you can also add other ways to authenticate: ![Zero Trust Login Methods](https://marvinquezon.com/storage/uploads/screenshot-2025-11-21-at-113647-am.png) 3️⃣ **Create a Policy** - On the sidebar click **Access controls** -> **Policies** - On Policy Name: Allow Team Members (or whatever policy name you want that makes sense) - Duration: Set to default: 24 hours - Then on **Add Rules** -> **Selector** choose **Emails** - here you can add the emails of your team members who will need access to your admin panel. - Once done, scroll down and click **Save** 4️⃣ **Add your Application** - On the sidebar click **Access controls** -> **Applications** - Click **Add Application** then select **Self-hosted** - Application Name: **My Website Admin** (or whatever makes sense to you) - Click on **Add public hostname** -> Input your domain and path to admin like so ``` Domain: https://mydomain.com Path: /admin* // This will secure the admin and all related URLs ``` - Then on Access Policies -> click **Select existing policies** then apply the policy that you've created - Then scroll down to **Login Methods** and make sure **Accept all available identity providers** is turned on so that any providers you've setup on the 2nd step will be used. - Then **Save** 5️⃣ **Test** - Visit your admin panel - Instead of admin login, you'll see Cloudflare Access prompt - Provide an email that was added on Step 3 -> enter code that was sent to the email -> Cloudflare grants access - After that, you'll see your normal admin login page — but only after identity check ⭐️ **Why This Works (Even on Free Plan)** ✔️ Access rules (email-based) ✔️ One-time PIN ✔️ Google login ✔️ Protect multiple paths ✔️ Works with Laravel, WordPress, Node, etc. ## 🔚 Final Thoughts This is the fastest way to secure your admin panel — without changing any code, installing any package, or paying for a plan. *Makes your panel invisible, protected, and accessible only to you — for free.*

November 16, 2025

How to Add Cloudflare Turnstile to Laravel in 5 Minutes (No Packages Required)

If you’ve built a public-facing web app, you eventually run into the same annoying problem: bots. They fill out your forms, spam your inbox, and waste your server’s time. Most developers immediately think of Google reCAPTCHA, but there’s a cleaner option that solves the same problem without the tracking baggage: **Cloudflare Turnstile**. Turnstile is Cloudflare’s privacy-friendly CAPTCHA alternative. * ❌ No user friction. * 🚍 No weird “click the traffic lights” puzzles. (ehem.. Google) * ⏲️ And setup takes only a few minutes. In this quick guide, I’ll show you why you should use Turnstile — and how to integrate it into a Laravel app without any third-party packages. ## Why use Cloudflare Turnstile? Here are the biggest reasons I migrated to it: **1. No user frustration** Turnstile doesn’t make users solve puzzles. It verifies silently in the background unless something looks suspicious. **2. Privacy-respecting** Unlike reCAPTCHA, Turnstile doesn’t track users across the web. No profiling, no annoying consent banners. **3. Dead simple to implement** It’s literally: * Load a script * Place a widget * Verify the token server-side Done! **4. Completely free** Cloudflare offers Turnstile with unlimited usage on the free plan. ### Step 1 — Create a Turnstile Widget in Cloudflare 1. Log in to Cloudflare 2. Application Security → Turnstile 3. Click **Add Widget** 4. Set: * Name: e.g: my-domain-name-turnstile * Add Hostnames: If you already have existing hostnames setup in Cloudflare you can select it, or you can just type your domain name manually. You can also add your local domains here - very useful if you are using Herd on your local machine. * Widget Mode: Managed (recommended) * Would you like to opt for pre-clearance for this site?: Just select "No" 5. Copy your **Site Key** and **Secret Key** ### Step 2 — Add the Keys, Widget and Script into Laravel Add these to your `.env` file ``` # Cloudflare Turnstile Captcha TURNSTILE_ENABLED=true # This will be so that you can just disable it quickly, especially on your tests TURNSTILE_URL=https://challenges.cloudflare.com/turnstile/v0/siteverify TURNSTILE_SITE_KEY=Your-Turnstile-Site-Key TURNSTILE_SECRET_KEY=Your-Turnstile-Secret-Key ``` Then, configure these values on your `config/services.php` file ``` // On services.php 'turnstile' => [ 'enabled' => env('TURNSTILE_ENABLED', false), 'turnstile_url' => env('TURNSTILE_URL'), 'site_key' => env('TURNSTILE_SITE_KEY'), 'secret_key' => env('TURNSTILE_SECRET_KEY'), ], ``` Then add the Widget into your Blade template — this usually goes into public facing forms such as registration, forgot password, contact us, etc. ``` ``` Then add their script outside the body of your base template ``` ``` ### Step 3 — Create a Rule class and use it on your form validations This sample rule class below provides a way to ignore `required` validation on the Turnstile field if the `config('services.turnstile.enabled')` is set to `false`. ```

Marvin Quezon · Copyright © 2026 · Privacy · Sitemap