<?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: Muhammad Ikhsan Nur Rafid</title>
    <description>The latest articles on DEV Community by Muhammad Ikhsan Nur Rafid (@_xzens).</description>
    <link>https://dev.to/_xzens</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%2F1893457%2F630a9f9d-23b4-4b7d-be6d-ba6a1097bfa7.jpeg</url>
      <title>DEV Community: Muhammad Ikhsan Nur Rafid</title>
      <link>https://dev.to/_xzens</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_xzens"/>
    <language>en</language>
    <item>
      <title>HydraSec: Running Six Pentest Tools From One Web App, Built With Docker</title>
      <dc:creator>Muhammad Ikhsan Nur Rafid</dc:creator>
      <pubDate>Mon, 09 Nov 2026 18:12:43 +0000</pubDate>
      <link>https://dev.to/_xzens/hydrasec-running-six-pentest-tools-from-one-web-app-built-with-docker-2a8o</link>
      <guid>https://dev.to/_xzens/hydrasec-running-six-pentest-tools-from-one-web-app-built-with-docker-2a8o</guid>
      <description>&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;&lt;br&gt;
Small businesses and MSMEs are digitizing through websites, but they rarely have the budget for professional penetration testing. Meanwhile, the industry-standard tools (Nmap, Nuclei, xray, XSStrike, sqlmap, ffuf) are free but command-line heavy, each produces reports in a different format, and running them against your own site without proper isolation is risky. The predictable outcome: website owners skip security testing entirely.&lt;/p&gt;

&lt;p&gt;HydraSec is my answer: a self-hosted web application that consolidates all six tools into one interface. You point it at a website you own, and it runs the scan inside an isolated ephemeral container, streams the live CLI output straight to your browser through xterm.js, normalizes every finding into a single database schema, and adds your scan to a public leaderboard. Total cost: Rp0, running entirely on your own machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi7u4da7wkdd4m046jbca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi7u4da7wkdd4m046jbca.png" alt="arch" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The stack is nine containers: an Nginx gateway, a React frontend, a Node.js API, PostgreSQL, Redis (BullMQ), a background worker, MailPit for OTP email delivery, plus Prometheus and cAdvisor for telemetry. The design principle is strict separation: a dedicated internal network for app services and a sandbox network for the scanning tools, so a scanner can never reach the database. Tool containers spawn on demand as non-root users with all capabilities dropped, memory caps, PID limits, and a per-tool timeout, then destroy themselves when the scan ends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Docker details that mattered&lt;/strong&gt;&lt;br&gt;
The frontend uses a multi-stage build, which is the cheapest win in the whole project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;FROM node:20-alpine AS build&lt;br&gt;
COPY package.json package-lock.json* ./&lt;br&gt;
RUN npm install&lt;br&gt;
COPY . .&lt;br&gt;
RUN npm run build&lt;br&gt;
FROM nginx:1.27-alpine&lt;br&gt;
COPY --from=build /app/dist /usr/share/nginx/html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Only the final stage ships, so the image is 74 MB instead of 400+ MB of Node.js and node_modules. Every base image is pinned to a specific version (no latest), and the tool sources are pinned to exact commit hashes.&lt;/p&gt;

&lt;p&gt;The orchestration rule is equally simple: the API never spawns containers. Jobs go into a Redis queue (BullMQ) and the worker runs at most two tools at a time:&lt;br&gt;
&lt;strong&gt;docker-compose.yml&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;background-worker:&lt;br&gt;
  volumes:&lt;br&gt;
    - /var/run/docker.sock:/var/run/docker.sock&lt;br&gt;
    - tooldata:/data&lt;br&gt;
  environment:&lt;br&gt;
    WORKER_CONCURRENCY: 2&lt;br&gt;
  networks: [internal, sandbox]&lt;/code&gt;&lt;br&gt;
Ten simultaneous scans queue safely instead of OOM-ing the host. Security was treated as a chain: parameterized SQL everywhere, OTP codes stored as SHA-256 hashes (there are no passwords at all), an SSRF guard that resolves DNS and rejects private ranges, and strict input whitelists before anything reaches a CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run it locally&lt;/strong&gt;&lt;br&gt;
bash&lt;br&gt;
&lt;code&gt;git clone https://github.com/Ikhsaaan334/hydrasec &amp;amp;&amp;amp; cd hydrasec&lt;br&gt;
bash setup.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sign in with an email and a one-time code, pick a unique username, choose a tool, and watch the scan stream live into your terminal. When it finishes, every finding lands in one normalized table you can export as JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3mhxbd65lg8x2tqjre9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3mhxbd65lg8x2tqjre9v.png" alt="1" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F92aem0aq5zj5yyebqqlp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F92aem0aq5zj5yyebqqlp.png" alt="2" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmr7fro3203h4bk3rzrm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmr7fro3203h4bk3rzrm5.png" alt="3" width="800" height="211"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo5b7j1w6j5vg87adk264.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo5b7j1w6j5vg87adk264.png" alt="4" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fue1c8g8ed1njbd2gv5jl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fue1c8g8ed1njbd2gv5jl.png" alt="5" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8ilkyx33qi9gwbrcvf1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8ilkyx33qi9gwbrcvf1j.png" alt="6" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6j4l5imbzldglqhka55.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6j4l5imbzldglqhka55.png" alt="7" width="799" height="449"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvhv190l3l6wb5g2w96op.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvhv190l3l6wb5g2w96op.png" alt="8" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgz2fwgpuwotchwjuutb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgz2fwgpuwotchwjuutb.png" alt="9" width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I learned&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multi-stage builds are the cheapest performance win in containerization: one extra FROM cut my frontend image by 6x.&lt;/li&gt;
&lt;li&gt;cgroups make ephemeral sandboxes practical: memory caps and PID limits per tool container are what let two aggressive scanners run side by side safely.&lt;/li&gt;
&lt;li&gt;Test before you ship, always. A 2024 binary against 2026 template formats crashed instantly; the bug only surfaced when I actually ran the scan instead of trusting the build.&lt;/li&gt;
&lt;li&gt;Security is a chain: one latest tag or one unpinned dependency weakens an otherwise hardened setup.&lt;/li&gt;
&lt;li&gt;AI-assisted development needs a human in the loop: I used an AI coding assistant heavily for scaffolding, but every fix, test, and architectural call went through my own hands (full declaration in the repo README).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Links&lt;br&gt;
Repository: &lt;a href="https://github.com/Ikhsaaan334/hydrasec/" rel="noopener noreferrer"&gt;https://github.com/Ikhsaaan334/hydrasec/&lt;/a&gt; &lt;br&gt;
Demo video: &lt;a href="https://youtu.be/---Ny7KHdEk" rel="noopener noreferrer"&gt;https://youtu.be/---Ny7KHdEk&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>cybersecurity</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
