<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Resul Öztaş</title>
    <description>The latest articles on DEV Community by Resul Öztaş (@resul_oztas).</description>
    <link>https://dev.to/resul_oztas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4039688%2F2e0a3d1f-0bdf-4da1-9eb1-623dc9df743c.png</url>
      <title>DEV Community: Resul Öztaş</title>
      <link>https://dev.to/resul_oztas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/resul_oztas"/>
    <language>en</language>
    <item>
      <title>Why I Ship Laravel Instead of WordPress for SMB Clients</title>
      <dc:creator>Resul Öztaş</dc:creator>
      <pubDate>Fri, 07 Aug 2026 06:34:13 +0000</pubDate>
      <link>https://dev.to/resul_oztas/why-i-ship-laravel-instead-of-wordpress-for-smb-clients-136l</link>
      <guid>https://dev.to/resul_oztas/why-i-ship-laravel-instead-of-wordpress-for-smb-clients-136l</guid>
      <description>&lt;p&gt;I run a small agency out of Istanbul building corporate websites for small and medium businesses — clinics, hygiene service providers, IT partners. Almost every prospective client asks the same question upfront: "Are you doing this in WordPress?" My answer is usually no, and here's the technical reasoning behind it.&lt;/p&gt;

&lt;p&gt;The attack surface problem&lt;/p&gt;

&lt;p&gt;A typical WordPress install for a corporate site ends up with 15-30 plugins: SEO, forms, caching, security, page builders, backups, image optimization. Each plugin is an independent codebase, independently maintained, independently vulnerable. The WPScan vulnerability database alone tracks thousands of plugin CVEs, and a huge share of real-world WordPress compromises trace back to outdated or poorly maintained plugins rather than WordPress core itself.&lt;/p&gt;

&lt;p&gt;With Laravel, the surface area is defined by what you actually write. No bundled functionality you don't use sitting there as dead weight with a CVE waiting to happen. When I built a passive security scanning tool for &lt;a href="https://resuloztas.com/guvenlik-analizi" rel="noopener noreferrer"&gt;security posture assessment&lt;/a&gt; — pulling from Shodan, crt.sh, SSL Labs, and the CIRCL CVE API — the difference in exposed surface between a lean Laravel deployment and a plugin-heavy WordPress site was stark just from open-source intelligence alone, no active scanning required.&lt;/p&gt;

&lt;p&gt;Performance is architectural, not bolted on&lt;/p&gt;

&lt;p&gt;Page builder plugins (Elementor, Divi, etc.) generate HTML/CSS that's optimized for the editing experience, not for the browser. Nested divs, inline styles, render-blocking assets from a dozen different plugin authors who never coordinated with each other.&lt;/p&gt;

&lt;p&gt;A Laravel + Tailwind stack starts from a blank slate. Every class, every asset, every query is intentional. Core Web Vitals scores reflect that directly — not because Laravel is inherently "faster" than PHP-based WordPress (they share a language), but because the code you ship is exactly the code the page needs, nothing more.&lt;/p&gt;

&lt;p&gt;Infrastructure control matters more than people think&lt;/p&gt;

&lt;p&gt;My stack runs on Hetzner VPS with Proxmox, Docker containers, and Cloudflare in front. That level of infrastructure control is straightforward with a custom Laravel app — you know exactly what's running, what ports are open, what's exposed.&lt;/p&gt;

&lt;p&gt;WordPress hosting often abstracts this away (managed hosting, one-click installs), which is convenient but means less visibility into what's actually running on the server. For clients handling customer data or payment flows, that visibility isn't optional — it's the baseline.&lt;/p&gt;

&lt;p&gt;Where WordPress still wins&lt;/p&gt;

&lt;p&gt;I won't pretend Laravel is the right call for everything. Content-heavy sites publishing frequently, tight budgets, non-technical teams needing to self-manage content — WordPress's ecosystem and content management maturity is hard to beat there. The calculus changes when the priority shifts to a small attack surface, predictable long-term maintenance cost, and full infrastructure ownership.&lt;/p&gt;

&lt;p&gt;If you're curious about the corporate web design approach I take with clients, I wrote more &lt;a href="https://resuloztas.com/hizmetler/kurumsal-web-tasarim" rel="noopener noreferrer"&gt;about it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Curious how other devs building for SMB clients weigh this trade-off — especially around plugin sprawl and long-term maintenance burden. Would love to hear how others handle it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>wordpress</category>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>The Hidden Infrastructure Tax of "Cheap" Web Deployments (And Why We Moved to Custom Docker Stacks)</title>
      <dc:creator>Resul Öztaş</dc:creator>
      <pubDate>Wed, 29 Jul 2026 14:37:28 +0000</pubDate>
      <link>https://dev.to/resul_oztas/the-hidden-infrastructure-tax-of-cheap-web-deployments-and-why-we-moved-to-custom-docker-stacks-5epj</link>
      <guid>https://dev.to/resul_oztas/the-hidden-infrastructure-tax-of-cheap-web-deployments-and-why-we-moved-to-custom-docker-stacks-5epj</guid>
      <description>&lt;p&gt;Clients often ask me why there is such a massive price discrepancy in web development quotes. They see one agency offering a functional site for $500, and another quoting $5,000+ for seemingly the exact same visual result. What they don't see is the hidden infrastructure tax that comes due long after the site goes live.&lt;/p&gt;

&lt;p&gt;For years, the industry standard for fast client delivery has been dropping a heavy monolithic CMS onto a shared hosting plan, slapping on a commercial theme, and installing dozens of different plugins to handle basic functionality like SEO, caching, and contact forms. From a frontend perspective, it looks fine and the client is happy. From a DevOps and security perspective, it's a ticking time bomb.&lt;/p&gt;

&lt;p&gt;When you deploy an architecture heavily reliant on third-party plugins, you are not just maintaining your own code; you are adopting the technical debt of anonymous developers across the globe. Over time, this results in what I call "CMS Decay". You are only as secure as the worst-written, most neglected plugin in your stack. I actually wrote a &lt;a href="https://resuloztas.com/guvenlik-analizi" rel="noopener noreferrer"&gt;passive security scanner&lt;/a&gt; recently simply because of how often I found abandoned subdomains running outdated, highly vulnerable CMS versions.&lt;/p&gt;

&lt;p&gt;Beyond security, performance takes a massive hit. Every plugin installation leaves orphaned rows in the database. Eventually, your Time to First Byte (TTFB) spikes simply because the server is querying thousands of dead rows on every single page load. Hitting the "Update All" button on a production environment in this state feels less like maintenance and more like playing Russian Roulette with a client's business.&lt;/p&gt;

&lt;p&gt;To escape this endless cycle of patching and praying, we fundamentally shifted our deployment approach. Instead of dealing with plugin conflicts, we standardized our pipeline around custom, containerized architecture.&lt;/p&gt;

&lt;p&gt;We now build tailored, modular applications using Laravel or Python. There is zero bloat. If a client needs a blog and a contact form, we write exactly the models and controllers needed for that specific logic. Everything is then fully containerized. The application, the database (MariaDB/PostgreSQL), and the Redis cache run in their own isolated Docker containers. We orchestrate these Docker stacks on Proxmox VMs or LXC containers, giving us hardware-level snapshotting. If something goes catastrophically wrong, rolling back the entire server state takes about 30 seconds.&lt;/p&gt;

&lt;p&gt;All incoming traffic is routed through Nginx Proxy Manager or OpenResty, which handles automated Let's Encrypt SSL certificates and basic rate limiting before a single packet even touches the application container.&lt;/p&gt;

&lt;p&gt;The biggest advantage of this custom stack is raw performance. You don't need a premium caching plugin when you can directly configure Redis to handle session states and query caching in Laravel. You don't need an image optimization plugin when you can handle WebP conversion directly at the server level. By removing the bloated abstraction layer of a traditional CMS, achieving a 90+ score on Google's Core Web Vitals becomes a natural byproduct of good engineering, rather than an endless game of whack-a-mole with optimization tools.&lt;/p&gt;

&lt;p&gt;Cheap deployments are always expensive to maintain. The upfront cost of architecting a clean, containerized web application pays massive dividends the moment you realize you don't have to spend your weekend patching an emergency zero-day vulnerability in a random slider plugin.&lt;/p&gt;

&lt;p&gt;If you are curious about how we architect these custom, high-performance solutions, or if you just want to talk server infrastructure and technical SEO, you can check out my work over at &lt;a href="https://resuloztas.com" rel="noopener noreferrer"&gt;resuloztas.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>architecture</category>
      <category>security</category>
    </item>
    <item>
      <title>Why I Built a Security Scanner That Never Touches the Target</title>
      <dc:creator>Resul Öztaş</dc:creator>
      <pubDate>Sat, 25 Jul 2026 11:07:31 +0000</pubDate>
      <link>https://dev.to/resul_oztas/why-i-built-a-security-scanner-that-never-touches-the-target-4123</link>
      <guid>https://dev.to/resul_oztas/why-i-built-a-security-scanner-that-never-touches-the-target-4123</guid>
      <description>&lt;p&gt;A client asked me to build a "quick security check" tool for their agency's lead generation funnel, the kind where a visitor types in a domain and gets a security score back. Simple enough in concept. Then I actually sat down to build it and ran straight into a legal wall I hadn't fully thought through.&lt;/p&gt;

&lt;p&gt;Here's the problem. The obvious way to build something like this is to run an active scan: port scan the target, maybe throw a few known exploit checks at it, see what comes back. That's how most security scanning tools work, and it's also, depending on jurisdiction, potentially illegal if you don't own the system you're scanning. Where I operate, unauthorized access to a computer system, even a read-only probe, falls under the same statute as actually breaking in. A visitor typing a random competitor's domain into my tool and getting me to port-scan it on their behalf was not a liability I wanted to hold.&lt;/p&gt;

&lt;p&gt;So the tool had to be entirely passive. No packet gets sent to the target system, full stop. Everything comes from third-party services that have already scanned the internet and cached the results, meaning I'm querying a database, not the target.&lt;/p&gt;

&lt;p&gt;Four sources ended up covering most of what a basic security posture check needs.&lt;/p&gt;

&lt;p&gt;SSL Labs' API gives you certificate validity, protocol version, and cipher suite strength without touching the target directly beyond what a normal HTTPS handshake would do anyway, since that's inherent to loading the page at all.&lt;/p&gt;

&lt;p&gt;Shodan and Censys are the interesting ones. Both continuously scan the entire public IPv4 space and cache what they find, open ports, running services, banner strings. Querying their API means you're reading data they already collected, not initiating your own scan. This is the core trick that makes passive scanning legally defensible: the scanning already happened, by someone else, and it's public information now.&lt;/p&gt;

&lt;p&gt;Certificate Transparency logs, queried through crt.sh, turned out to be the most useful source for a specific failure mode I kept seeing in the wild: forgotten subdomains. Every SSL certificate ever issued for a domain gets logged publicly, permanently, as part of the CT system browsers now require. That means every staging., test., or old-checkout. subdomain someone spun up two years ago and forgot about is sitting in a public log somewhere, discoverable, and usually running whatever unpatched software was current when it was abandoned.&lt;/p&gt;

&lt;p&gt;CIRCL's CVE API rounds it out, cross-referencing any software versions I can passively fingerprint against known vulnerabilities.&lt;/p&gt;

&lt;p&gt;The interesting engineering constraint here wasn't really the APIs themselves, it was designing the whole pipeline around the assumption that I have zero interaction with the target beyond what a normal browser request already does. Every design decision funnels back to that one rule. It's a narrower tool than an active scanner would produce, the report is genuinely less deep than what a real pentest gives you, but it's a tool anyone can point at any domain without a lawyer getting involved, and for a lead-gen funnel that's actually the more useful trade-off.&lt;/p&gt;

&lt;p&gt;If you're building something similar and want to compare notes on the passive-only approach, or want to &lt;a href="https://resuloztas.com/guvenlik-analizi" rel="noopener noreferrer"&gt;see it running&lt;/a&gt;, I write about the infrastructure and security side of my work at &lt;a href="https://resuloztas.com" rel="noopener noreferrer"&gt;resuloztas.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>api</category>
      <category>webdev</category>
      <category>serverless</category>
    </item>
    <item>
      <title>The Silent Threat of Off-by-Slash: How Your Reverse Proxy is Leaking Source Code</title>
      <dc:creator>Resul Öztaş</dc:creator>
      <pubDate>Thu, 23 Jul 2026 10:03:53 +0000</pubDate>
      <link>https://dev.to/resul_oztas/the-silent-threat-of-off-by-slash-how-your-reverse-proxy-is-leaking-source-code-534j</link>
      <guid>https://dev.to/resul_oztas/the-silent-threat-of-off-by-slash-how-your-reverse-proxy-is-leaking-source-code-534j</guid>
      <description>&lt;p&gt;I have spent countless hours auditing infrastructure setups, from bare-metal servers to sprawling Docker swarms, and one of the most persistent yet easily overlooked vulnerabilities I encounter involves how reverse proxies handle URI normalization. We often treat our web servers as impenetrable black boxes once the SSL certificates are wired up and the traffic is flowing, but the reality is that a single missing character in a configuration file can compromise the entire underlying system.&lt;/p&gt;

&lt;p&gt;Consider a typical scenario where Nginx is sitting in front of a modern web application or a static asset container. You configure a location directive to route traffic to a specific backend microservice. If you define the location path without a trailing slash but append a URI to the proxy pass directive, you are inadvertently creating a bridge for directory traversal. An attacker can craft a request that appends a relative path traversal sequence directly to the intended endpoint. Because of how the proxy reconstructs the forwarded request, the upstream server processes the normalized path, completely bypassing the intended directory restrictions.&lt;/p&gt;

&lt;p&gt;This is known in the security community as an off-by-slash vulnerability, and it is terrifyingly common in production environments. The mechanics behind this flaw lie in the subtle differences between how Nginx processes prefix matches. When a request comes in, the server matches the URI against the defined locations. If a malicious payload containing dot-dot-slash sequences is appended to a vulnerable endpoint, the proxy strips the matched prefix and forwards the remainder. If that prefix lacked a trailing slash, the resulting URI sent to the backend begins directly with those traversal characters. The backend application, assuming the proxy has already validated and sanitized the request, obediently serves files from outside the intended web root.&lt;/p&gt;

&lt;p&gt;I have seen entire environment files, database credentials, and private SSH keys extracted this way within seconds during penetration tests. The proxy is doing exactly what you told it to do, but the logic gap between the frontend router and the backend file system creates a catastrophic blind spot.&lt;/p&gt;

&lt;p&gt;Fixing this architectural flaw requires a fundamental understanding of how your proxy interacts with your upstream services. The golden rule is strict consistency. If your location block ends with a slash, your upstream URL in the proxy pass directive must also end with a slash. It sounds elementary, but when you are managing hundreds of routing rules, legacy endpoints, and microservices across multiple deployment environments, these small details easily slip through the cracks of standard code reviews. You have to explicitly test how your server handles malformed normalization attempts, rather than just verifying that the "happy path" works for your legitimate users.&lt;/p&gt;

&lt;p&gt;Infrastructure security is never a one-time configuration effort; it is a continuous process of challenging your own architecture. You have to actively hunt for these logical gaps before automated scanners or malicious actors find them for you. Taking a proactive approach to your server blocks and proxy rules is the only way to ensure your application layer remains isolated. If you are uncertain about the integrity of your current web architecture or want an expert set of eyes to investigate your attack surface, I run deep-dive security audits and vulnerability assessments. You can review the details of my testing methodology and request a comprehensive security analysis at &lt;a href="https://resuloztas.com/guvenlik-analizi" rel="noopener noreferrer"&gt;https://resuloztas.com/guvenlik-analizi&lt;/a&gt; to ensure your infrastructure is genuinely hardened against these subtle but devastating architectural flaws.&lt;/p&gt;

</description>
      <category>security</category>
      <category>nginx</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Running Docker on Proxmox: LXC vs VMs and the Firewall Rules That Actually Matter</title>
      <dc:creator>Resul Öztaş</dc:creator>
      <pubDate>Tue, 21 Jul 2026 09:06:15 +0000</pubDate>
      <link>https://dev.to/resul_oztas/running-docker-on-proxmox-lxc-vs-vms-and-the-firewall-rules-that-actually-matter-4hkd</link>
      <guid>https://dev.to/resul_oztas/running-docker-on-proxmox-lxc-vs-vms-and-the-firewall-rules-that-actually-matter-4hkd</guid>
      <description>&lt;p&gt;A few months ago I pulled an old i7-7700 box out of a closet, threw 15GB of RAM at it, and turned it into my home lab. No GPU, nothing fancy. I run Proxmox VE on it and use it for agent workloads and internal automation while my actual client sites live on Hetzner. What surprised me was how many small decisions on this box ended up mattering more than the hardware itself — mainly where I put Docker and how I locked the network down.&lt;/p&gt;

&lt;p&gt;If you're setting up something similar, the first fork in the road is whether Docker goes inside an LXC container or inside a full VM. People treat this as a minor detail. It isn't.&lt;/p&gt;

&lt;p&gt;LXC vs VM is really a question of what you're willing to isolate&lt;/p&gt;

&lt;p&gt;An LXC container shares the host kernel. That's the whole trade. You get near-native performance, boot times measured in seconds, and memory overhead that's basically nothing compared to a VM — because there's no second kernel, no virtualized hardware layer, no hypervisor translating every syscall. For a home lab with 15GB total RAM, this matters a lot. Three or four VMs and you've burned half your memory on OS overhead before a single application starts.&lt;/p&gt;

&lt;p&gt;A VM, on the other hand, gets its own kernel and a real boundary enforced by hardware virtualization extensions (VT-x/AMD-V), not just kernel namespaces. If something inside breaks out, it's breaking out of an actual virtual machine, not just a namespace boundary that a kernel exploit could theoretically punch through.&lt;/p&gt;

&lt;p&gt;So the practical rule I landed on: anything that's mine, that I trust, that just needs to run efficiently — internal tools, automation scripts, my agent pipelines — goes in LXC. Anything that touches untrusted input directly, or that I'd rather not think about too hard from a security perspective, gets a VM. It's not paranoia, it's just matching the isolation level to the actual risk.&lt;/p&gt;

&lt;p&gt;Docker inside LXC is fine, but only if you do the nesting right&lt;/p&gt;

&lt;p&gt;This is where people get stuck. Docker wants to create its own namespaces, cgroups, and network bridges — and by default, an unprivileged LXC container won't let it, because unprivileged containers deliberately restrict what the process inside can do to the kernel.&lt;/p&gt;

&lt;p&gt;The fix isn't switching to a privileged container as a first instinct, even though that's the fastest way to make the error go away. Privileged containers run as root on the host's actual UID, which means a container escape is a host compromise, full stop. What you want instead is keeping the container unprivileged and explicitly enabling nesting and keyctl in its configuration, which unlocks just enough kernel features for Docker's own namespacing to work while keeping the container's root mapped to an unprivileged UID on the host. It takes two lines in the container config. Once that's set, Docker runs inside LXC almost exactly like it would on bare metal, and you keep the isolation boundary that unprivileged containers give you.&lt;/p&gt;

&lt;p&gt;I only reach for privileged LXC when a workload genuinely needs raw device access — GPU passthrough, certain hardware pass-through scenarios — and even then I try to scope it as tightly as possible.&lt;/p&gt;

&lt;p&gt;The firewall is where most home labs quietly fail&lt;/p&gt;

&lt;p&gt;Proxmox has a firewall built in at three layers: datacenter, node, and individual VM/CT. Most guides show you how to open a port. Almost none of them explain why the datacenter-level rules matter more than people assume.&lt;/p&gt;

&lt;p&gt;The mistake I see constantly — and made myself, early on — is configuring firewall rules per container and calling it done. That works until you have fifteen containers and you're maintaining fifteen slightly different rule sets, and eventually one of them drifts and quietly exposes something it shouldn't. What actually holds up is defining security groups at the datacenter level — one for "internal services, no external access," one for "web-facing, ports 80/443 only," one for "management access from my own IP range only" — and then just assigning containers to the right group. The rules live in one place. When I need to change something, I change it once.&lt;/p&gt;

&lt;p&gt;On top of that, Proxmox's firewall works at the bridge level before traffic even reaches a container's own iptables rules, which means you get a real security boundary independent of whatever the container's own OS is doing. I still run fail2ban inside anything exposing SSH, and ufw as a second layer inside containers that face the internet, but the Proxmox firewall is what stops most of the noise before it gets that far. Defense in depth isn't a buzzword here, it's just fewer 3am log entries.&lt;/p&gt;

&lt;p&gt;One more thing that trips people up: Proxmox's firewall is disabled by default even after you configure rules, at both the datacenter and node level independently. I've seen more than one setup where someone wrote a full rule set, felt done, and never actually flipped the enable switch. Check both toggles.&lt;/p&gt;

&lt;p&gt;What this setup actually gets you&lt;/p&gt;

&lt;p&gt;None of this is exotic. It's an old desktop CPU, consumer RAM, and Proxmox doing what it does well — letting you run a mix of lightweight LXC containers and properly isolated VMs on hardware that would choke if you tried to run everything as full VMs. The firewall layering is the part that took me longest to get right, mostly because the instinct is to configure it reactively, container by container, instead of designing the security groups first and assigning containers into them.&lt;/p&gt;

&lt;p&gt;If you're running something similar and want to compare notes, or if you're curious about the agent pipeline I'm running on top of this box, I write about the infrastructure and web/SEO side of things at &lt;a href="//resuloztas.com"&gt;resuloztas.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>proxmox</category>
      <category>lxc</category>
      <category>firewall</category>
    </item>
  </channel>
</rss>
