<?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: Raghav</title>
    <description>The latest articles on DEV Community by Raghav (@raghavyuva).</description>
    <link>https://dev.to/raghavyuva</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3094143%2Fbcd6301c-c3e4-4daa-ad83-ec6b9a5ce8d6.jpeg</url>
      <title>DEV Community: Raghav</title>
      <link>https://dev.to/raghavyuva</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raghavyuva"/>
    <language>en</language>
    <item>
      <title>The Art of Vibe Coding With Actual Discipline</title>
      <dc:creator>Raghav</dc:creator>
      <pubDate>Mon, 08 Dec 2025 06:14:49 +0000</pubDate>
      <link>https://dev.to/raghavyuva/the-art-of-vibe-coding-with-actual-discipline-lo</link>
      <guid>https://dev.to/raghavyuva/the-art-of-vibe-coding-with-actual-discipline-lo</guid>
      <description>&lt;h3&gt;
  
  
  Why speed feels great but structure keeps you sane
&lt;/h3&gt;

&lt;p&gt;Every day I see developers firing off prompts to tools like Cursor, Claude Code, and every other AI Powered editor out there. The speed is addictive. You get instant wins, quick fixes, and a sense that you’re moving faster than ever. But what this really means is you’re building on shaky ground. It works today, then bites you later.&lt;/p&gt;

&lt;p&gt;I want to break down how I use AI in my workflow while building &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt;, how I wish my teammates approached it, and why keeping core engineering practices intact still matters. Before we get into the solutions, it helps to understand where things start going wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where vibe coding quietly derails (so as you!)
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Fy0u3zdpotpj0fh1ckvel.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.amazonaws.com%2Fuploads%2Farticles%2Fy0u3zdpotpj0fh1ckvel.png" alt="Vibe Coding Pitfalls" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vibe coding can make you feel like a 10x engineer, even when you’re not actually steering the ship.
&lt;/li&gt;
&lt;li&gt;After enough prompts, you lose track of what changed and why. Suddenly you need someone else to explain your own code.
&lt;/li&gt;
&lt;li&gt;Edits become scattered, inconsistent, and sometimes downright chaotic. I’ve seen people commit things like &lt;code&gt;SUMMARY.md&lt;/code&gt; right into their main codebase.
&lt;/li&gt;
&lt;li&gt;Collaboration becomes a mess because no one shares the same mental model of the project anymore.
&lt;/li&gt;
&lt;li&gt;Pair programming takes a hit since everyone is locked into their own AI driven bubble.
&lt;/li&gt;
&lt;li&gt;Knowledge transfer becomes painful. New teammates end up re prompting the model just to understand what’s going on.
&lt;/li&gt;
&lt;li&gt;The team’s engineering culture starts drifting away from solid, intentional practices.
&lt;/li&gt;
&lt;li&gt;Running multiple &lt;a href="https://www.ibm.com/think/topics/agentic-workflows" rel="noopener noreferrer"&gt;agentic workflows&lt;/a&gt; across different repos introduces confusion instead of clarity.
&lt;/li&gt;
&lt;li&gt;And at the end of the day, you’re reduced to someone who just gives orders to an AI and hopes it does the right thing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that you can probably relate to at least a few of the pain points above, this is where things get interesting. Let’s look at how we can take all that chaos, turn it around, and make vibe coding actually work without sacrificing engineering discipline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Turning raw prompts into intentional, consistent workflows
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2F9rbx26hwsl3lj2wciqh6.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.amazonaws.com%2Fuploads%2Farticles%2F9rbx26hwsl3lj2wciqh6.png" alt="Prompting Workflow" width="600" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prompting isn’t just a skill anymore. It’s becoming a core part of how we write software with LLMs. The better your prompts, the better your outcomes. And when you treat prompting like an engineering practice rather than a shortcut, you start seeing consistent, predictable results.&lt;/p&gt;

&lt;p&gt;Here’s how to approach it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ask for step by step output&lt;/strong&gt; : Break your instructions into clear, sequential steps. It gives the model structure and reduces randomness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tell the model when to stop&lt;/strong&gt; : If you want to review something, specify that the model should pause once a certain part is done. It keeps you in control of the flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interrupt when things drift&lt;/strong&gt; : If the model starts hallucinating or going off track, stop it immediately and re prompt with a tighter instruction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reinforce project rules every time&lt;/strong&gt; : Mention coding conventions, folder structure, architectural rules, or any non negotiables in your prompt so the model prioritizes them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a reusable prompt structure&lt;/strong&gt; : Build templates for feature development, bug fixes, refactoring, testing, and documentation.
If you’re using &lt;a href="https://cursor.com" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;, keep them inside your &lt;code&gt;.cursor&lt;/code&gt; folder for quick access.
The same structure can be shared with your team so everyone works with the same clarity.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Review like an engineer, not an AI operator
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Fz87r8x80gzavby4ymdep.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.amazonaws.com%2Fuploads%2Farticles%2Fz87r8x80gzavby4ymdep.png" alt="Engineering Review" width="456" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Writing code with an LLM doesn't end when the editor stops typing. The real work begins at review. Own what you push, catch problems early, and use models as tools not replacements.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Take responsibility&lt;/strong&gt;
You asked the model to write this. When a pull request fills up with comments, don't panic. Lead the review, reply to feedback, and fix issues before they hit &lt;code&gt;main&lt;/code&gt;. Ownership keeps the team confident and the codebase healthy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self review first&lt;/strong&gt;
Don’t blindly trust the model. Run the code, step through logic, and search for bugs. Remove stray emojis, clean up variable names, and format things the way you would if you wrote it yourself. You are the engineer, the model is the assistant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentic review as a second pass&lt;/strong&gt;
Use an automated reviewer or another model to scan for style, edge cases, or security issues. This is not a replacement for human judgment, treat it as a high quality linter that finds what you might miss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix small issues immediately&lt;/strong&gt;
Address minor comments and nits as they appear. Small problems compound quickly. Fixing them now prevents larger rework later and keeps the review cycle fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Think big while shipping small&lt;/strong&gt;
Ship simple, useful changes. But keep an eye on scale. Ask: will this pattern hold at 10x users, or 10x contributors? Balance pragmatic simplicity with design that scales.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Let automation enforce what your team can’t afford to forget
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Fe4vvsolc51lez12qeq0u.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.amazonaws.com%2Fuploads%2Farticles%2Fe4vvsolc51lez12qeq0u.png" alt="Automation/CI/CD" width="800" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your CI CD pipeline is the backbone of everything you ship. It starts as early as your pre-commit and pre-push hooks, and it follows your code all the way to production. A strong pipeline enforces discipline even when vibe coding tries to pull you in every direction.&lt;/p&gt;

&lt;p&gt;Make sure your pipeline covers the essentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coding standards
&lt;/li&gt;
&lt;li&gt;Linters and formatters
&lt;/li&gt;
&lt;li&gt;Compilation and type checks
&lt;/li&gt;
&lt;li&gt;Commit message rules
&lt;/li&gt;
&lt;li&gt;Mandatory reviews with enough depth
&lt;/li&gt;
&lt;li&gt;Extra review cycles when the change is risky
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;a href="https://graphite.com/guides/in-depth-guide-ci-cd-best-practices" rel="noopener noreferrer"&gt;solid pipeline&lt;/a&gt; catches what you miss, keeps your team aligned, and makes sure every feature lands clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  Care about the process, not just the output
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Ffp6uy0o2z3uoabmghdc8.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.amazonaws.com%2Fuploads%2Farticles%2Ffp6uy0o2z3uoabmghdc8.png" alt="Engineering Process" width="447" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open source works because people care. They care about the community, the standards, the craft, and the long term health of the project. Small teams that vibe code without shared principles slowly drift into sloppy engineering because the only thing they focus on is the outcome, not how they got there.&lt;/p&gt;

&lt;p&gt;If you’re someone who believes process matters, who values clean change history, who refuses to push a feature wrapped in a hundred hidden bugs, then this mindset becomes non negotiable. Respect the craft. Respect the principles. And don’t forget the tactics that keep your workflow sharp.&lt;/p&gt;

&lt;p&gt;What you ship is important. How you ship it matters even more.&lt;/p&gt;

&lt;p&gt;Follow these steps and vibe coding stops being chaotic. It becomes a fast, accountable way to build without sacrificing engineering craft. These approaches are my way of balancing the things, if you are someone with whom it resonates then feel free to &lt;a href="https://github.com/raghavyuva" rel="noopener noreferrer"&gt;follow me&lt;/a&gt; for more such resonating effects! &lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Jekyll almost killed our vitepress docs</title>
      <dc:creator>Raghav</dc:creator>
      <pubDate>Sun, 13 Jul 2025 15:41:45 +0000</pubDate>
      <link>https://dev.to/raghavyuva/how-jkyll-almost-killed-our-vitepress-docs-3ph8</link>
      <guid>https://dev.to/raghavyuva/how-jkyll-almost-killed-our-vitepress-docs-3ph8</guid>
      <description>&lt;p&gt;We created &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt; to simplify self-hosting. Think of it as Heroku or Netlify, but built for developers who want full control, especially when working with Docker apps. Naturally, we used Nixopus itself to host our own documentation in the early days. But as we rolled out alpha builds and moved fast, the setup started pushing back. To make sure our docs stayed accessible and reliable for users, we temporarily shifted to GitHub Pages. That’s when Jekyll, GitHub’s default static site generator, started messing with our VitePress setup. Here’s what happened.&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.amazonaws.com%2Fuploads%2Farticles%2F58h41k7qyeo55joeoa4f.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.amazonaws.com%2Fuploads%2Farticles%2F58h41k7qyeo55joeoa4f.png" alt="the process" width="628" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving Docs to GitHub Pages: What We Did
&lt;/h2&gt;

&lt;p&gt;We started by setting up a custom domain for our docs at &lt;code&gt;docs.nixopus.com&lt;/code&gt;. After adding a &lt;code&gt;CNAME&lt;/code&gt; file to the repository, we updated the DNS records to point to GitHub’s servers. Domain validation went through without any hiccups. Next, we had to choose how GitHub Pages would serve our documentation. &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.amazonaws.com%2Fuploads%2Farticles%2Flq8gsyb3ii8uyp9ykrsx.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.amazonaws.com%2Fuploads%2Farticles%2Flq8gsyb3ii8uyp9ykrsx.png" alt="Github pages deploy steps" width="776" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We picked the branch method for simplicity. We set it to deploy from the &lt;code&gt;master&lt;/code&gt; branch and pointed it to the &lt;code&gt;/docs&lt;/code&gt; directory, where our VitePress site lives. That got the docs live on the domain, but it also opened the door to a new set of issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration Catastrophe: Looks Like Docs, Feels Like Chaos
&lt;/h2&gt;

&lt;p&gt;When we first got the docs live, something felt off. They loaded, but with zero CSS. No layout, no colors, just raw text sitting on the screen. Technically the site was working, but let’s be honest, it was unusable.&lt;/p&gt;

&lt;p&gt;We had a GitHub Action set up to build and deploy the docs on every push to &lt;code&gt;master&lt;/code&gt;. At one point, we switched the deployment method from branch based to GitHub Actions, then back again, hoping it would help.&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.amazonaws.com%2Fuploads%2Farticles%2Fuv39mo4ieszei4yxm96p.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.amazonaws.com%2Fuploads%2Farticles%2Fuv39mo4ieszei4yxm96p.png" alt="Style Chaos" width="581" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Actions ran without errors. The pages deployed. But the styling came and went like a ghost. And that kind of inconsistency is the worst kind of bug to chase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Couldn't Pin Down the Root Cause
&lt;/h2&gt;

&lt;p&gt;We were convinced the problem was with VitePress. This &lt;a href="https://github.com/vuejs/vitepress/issues/3317" rel="noopener noreferrer"&gt;GitHub issue&lt;/a&gt; matched what we were seeing almost perfectly, so we tweaked our VitePress config, redeployed, and boom it worked.&lt;br&gt;
For a moment, at least. The next time we pushed to &lt;code&gt;master&lt;/code&gt;, the problem came back. No styles again. At this point, our GitHub Actions were running flawlessly. No errors, no skipped steps, nothing unusual.&lt;/p&gt;

&lt;p&gt;We opened a &lt;a href="https://discord.gg/skdcq39Wpv" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; thread to track the issue in real time and started logging when the bug would appear. But without a clear pattern, it felt like chasing shadows.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Burnout Moment
&lt;/h2&gt;

&lt;p&gt;One day, while talking to a &lt;a href="https://github.com/raghavyuva/nixopus/issues" rel="noopener noreferrer"&gt;Nixopus contributor&lt;/a&gt; about the docs issue, something clicked. I opened up the GitHub Actions tab to double check the workflow we were using to build and deploy the documentation. That’s when I noticed something strange two GitHub Actions were running for the same trigger.&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.amazonaws.com%2Fuploads%2Farticles%2Fzyfxp5n00o8087ho676q.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.amazonaws.com%2Fuploads%2Farticles%2Fzyfxp5n00o8087ho676q.png" alt="Unexpected github actions" width="587" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I paused. We only had one workflow file in the repo. So where was the second action coming from? I took a closer look at both. One was clearly ours. The other seemed to be generated by GitHub itself, tied to the "Pages" deployment configuration. Suddenly, it made sense. We had unknowingly set&lt;/p&gt;

&lt;h2&gt;
  
  
  We weren’t going crazy. We were just getting Jekylled.
&lt;/h2&gt;

&lt;p&gt;This one was so ridiculous &amp;amp; funny at the same time, we couldn’t help but laugh once we figured it out. Remember how we chose to deploy from a GitHub branch? Turns out, GitHub was quietly running its own internal deployment step for Pages. At the same time, our custom GitHub Action was also building and deploying the site.&lt;/p&gt;

&lt;p&gt;The catch was when GitHub’s default Pages deploy ran first, it served our VitePress site without any CSS. Completely styleless. Then, when our GitHub Action ran after it, it deployed the styled version. That’s why it &lt;em&gt;sometimes&lt;/em&gt; looked fine and we were racing against GitHub’s own deploy job. and yep, GitHub’s deploy was using Jekyll under the hood, even though we had no &lt;code&gt;.nojekyll&lt;/code&gt; file in the repo. Classic Pages behavior. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;What looked like a flaky VitePress bug turned out to be a silent tug-of-war between GitHub Pages and our own deployment pipeline. GitHub was defaulting to Jekyll, quietly breaking our styles, and we didn’t even notice it at first because our own action would sometimes fix it afterward.&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.amazonaws.com%2Fuploads%2Farticles%2Fj796qg6fwrxxwzl41e73.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.amazonaws.com%2Fuploads%2Farticles%2Fj796qg6fwrxxwzl41e73.png" alt="Jekyll and github" width="612" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fix? We disabled the default GitHub Pages deploy and let our GitHub Action handle everything. Clean, predictable, and no more surprise Jekyll attacks. Lesson learned ?  when something works "sometimes," dig deeper. There's probably a rogue process you didn’t invite to the party.&lt;/p&gt;

&lt;p&gt;If you're someone who wants to streamline ServerOps without the usual mess, &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt; might be exactly what you're looking for. And if you enjoy chasing down weird bugs like this one, &lt;a href="https://discord.gg/skdcq39Wpv" rel="noopener noreferrer"&gt;join us on Discord&lt;/a&gt;  we’d love to have you around. Let’s hunt bugs, ship clean infra, and laugh through the chaos together.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>From Migrations to Seed : Working with Fixtures in Nixopus</title>
      <dc:creator>Raghav</dc:creator>
      <pubDate>Sun, 29 Jun 2025 18:41:52 +0000</pubDate>
      <link>https://dev.to/raghavyuva/from-migrations-to-seed-working-with-fixtures-in-nixopus-2e95</link>
      <guid>https://dev.to/raghavyuva/from-migrations-to-seed-working-with-fixtures-in-nixopus-2e95</guid>
      <description>&lt;p&gt;Hey, we’re always up for exploring something cool at &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt;, and this time, we’re diving into fixtures. Now, the word &lt;strong&gt;fixtures&lt;/strong&gt; might sound a bit too technical and not immediately clear to many of our fellow developers so let’s break it down, and you’ll see exactly what we mean. Let’s dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Breakdown
&lt;/h2&gt;

&lt;p&gt;If you’ve worked with migrations before, you’ve probably come across the term &lt;em&gt;data seeding&lt;/em&gt; for databases. Even if you haven’t, let’s take a moment to understand what seeding data actually involves.&lt;/p&gt;

&lt;p&gt;By the way, if you’re not familiar with migrations yet, you might want to check out this article to see how we handle them: &lt;a href="https://dev.to/zhravan/inside-nixopus-how-we-manage-our-database-migrations-3i34"&gt;Inside Nixopus: How We Manage Our Database Migrations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Usually, during development, things can get tricky over time, especially when you have contributors and developers working together on the same project. Everyone wants everything to be quick and hassle-free so development doesn’t slow down. As a project maintainer, it’s your responsibility to enable this smooth contribution roadmap for any user who wants to help out. That’s exactly what we’re working towards at Nixopus.&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.amazonaws.com%2Fuploads%2Farticles%2Fpr4z630lbeyrl8ljyqif.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.amazonaws.com%2Fuploads%2Farticles%2Fpr4z630lbeyrl8ljyqif.png" alt="Data Seeding Life Cycle" width="800" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One major part of &lt;a href="https://docs.nixopus.com/contributing" rel="noopener noreferrer"&gt;Contributing to Nixopus&lt;/a&gt; is that after getting everything set up, Contributor still needs to do the following tasks :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You realize you need &lt;strong&gt;an admin user&lt;/strong&gt; to log in and test admin features.&lt;/li&gt;
&lt;li&gt;You also want to create &lt;strong&gt;a member user&lt;/strong&gt; for that organization to test the role based access.&lt;/li&gt;
&lt;li&gt;You might even want to enable specific features inside nixopus, and disable some!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is time consuming and error-prone, especially when you or your teammates need to do it over and over again on fresh databases. That’s exactly where data seeding comes into the picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Data Seeding?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The process of populating a database with an initial set of data.&lt;/em&gt; Simple, isn’t it?&lt;/p&gt;

&lt;p&gt;But how do we actually create one in Go using Bun ORM? This is what pushes us to explore how we can write a script to do exactly that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do Seed Files Look?
&lt;/h2&gt;

&lt;p&gt;We’ve divided our seed files into a modular folder structure. This way, everything stays organized and it’s much easier to load schema specific data when you need it.  &lt;/p&gt;

&lt;p&gt;Below is an example of the file structure and the kind of data we’ll be loading into the database later in our &lt;a href="https://github.com/raghavyuva/nixopus/blob/master/api/internal/fixtures/loader/fixture_loader.go" rel="noopener noreferrer"&gt;Codebase&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Role&lt;/span&gt;

  &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;uuid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin"&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Administrator&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;full&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;access"&lt;/span&gt;
      &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;now&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;updated_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;now&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;member&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;uuid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;member"&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Regular&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;organization&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;member"&lt;/span&gt;
      &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;now&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;updated_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;now&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;viewer&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;uuid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;viewer"&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Read-only&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;access&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;resources"&lt;/span&gt;
      &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;now&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;updated_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;now&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bun ORM in Action
&lt;/h2&gt;

&lt;p&gt;First things first, we need to get input from the user. Let’s assume the user runs a command like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go run internal/cmd/fixtures/main.go&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Then we want to accept some arguments along with this command to determine what exactly the user is trying to do, we will get into what each flag does later, for now let's go forward&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;fixturePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fixture"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"fixtures/development/complete.yml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Path to fixture file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;recreate&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"recreate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Recreate tables before loading fixtures"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;truncate&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"truncate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Truncate tables before loading fixtures"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we know what the user is actually trying to do, let’s create a Bun DSN URL which stands for &lt;strong&gt;Data Source Name URL&lt;/strong&gt;, which is a connection string used to configure and connect to databases or services.&lt;/p&gt;

&lt;p&gt;Here’s a raw example of what a Postgres DSN URL looks like: &lt;code&gt;postgres://username:password@localhost:5432/database_name?sslmode=disable&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Since we don’t want to hardcode credentials, we need to load our secrets like passwords and other configs from environment variables. Here’s how we can do that in Go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;godotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error loading .env file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;host&lt;/span&gt;     &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HOST_NAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;port&lt;/span&gt;     &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"USERNAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dbName&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_NAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sslMode&lt;/span&gt;  &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SSL_MODE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sslMode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sslMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"disable"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;dsn&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"postgres://%s:%s@%s:%s/%s?sslmode=%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sslMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have our DSN ready, we can check if our connection string is properly formatted and can be parsed without errors. The function we use for this is &lt;a href="https://pkg.go.dev/github.com/jackc/pgx/v5#ParseConfig" rel="noopener noreferrer"&gt;&lt;code&gt;pgx.ParseConfig&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pgx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dsn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to parse database config: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we are ready to go, let's connect to our database and close the connection to database as our program ends&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;sqldb&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stdlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;sqldb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqldb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pgdialect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to load all our fixtures from the YAML files in our &lt;code&gt;fixtures&lt;/code&gt; folder.  Here’s a simple flowchart that shows how the loading process works, &lt;a href="https://github.com/raghavyuva/nixopus/blob/master/api/internal/fixtures/loader/fixture_loader.go" rel="noopener noreferrer"&gt;Read The Code&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fi4uwnfs354mdhkdv2a9j.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.amazonaws.com%2Fuploads%2Farticles%2Fi4uwnfs354mdhkdv2a9j.png" alt="Fixture Loader" width="475" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After we have everything set up, we decide &lt;strong&gt;how we want to load the fixtures onto our database&lt;/strong&gt;.  This block of code checks which option the user passed when they ran the command and performs the action accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;recreate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fixtureLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadFixturesWithRecreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fixturePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;truncate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fixtureLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadFixturesWithTruncate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fixturePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fixtureLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadFixtures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fixturePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation of the Flags We Considered Earlier
&lt;/h3&gt;

&lt;p&gt;I know you must be waiting for the final touch, it's a lot of code to digest, right? So let’s take a moment to clearly understand the arguments we took earlier from the user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you used &lt;code&gt;--recreate&lt;/code&gt;, it &lt;strong&gt;drops all the tables&lt;/strong&gt;, recreates them, and then loads your fixtures into fresh tables. This is helpful if you want to start from scratch every time.&lt;/li&gt;
&lt;li&gt;If you used &lt;code&gt;--truncate&lt;/code&gt;, it &lt;strong&gt;empties all rows&lt;/strong&gt; but keeps the tables themselves (the structure stays intact), then loads your fixtures.&lt;/li&gt;
&lt;li&gt;If you didn’t pass any of those flags, it simply &lt;strong&gt;inserts the fixture data as-is&lt;/strong&gt;, without dropping or truncating anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Conclusion
&lt;/h2&gt;

&lt;p&gt;Do you think this could be done even better? Hmm that’s exactly why we’d love to have you join our &lt;a href="https://discord.gg/skdcq39Wpv" rel="noopener noreferrer"&gt;Discord community&lt;/a&gt;!   Want to see what we’re building and what we’ve accomplished so far? Take a look at our &lt;a href="https://github.com/raghavyuva/nixopus/blob/master/CHANGELOG.md" rel="noopener noreferrer"&gt;CHANGELOG.md&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Come help us shape the future of &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus a next-gen ServerOps management platform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

</description>
      <category>go</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>api</category>
    </item>
    <item>
      <title>Don't Be a Foolish, Contributing to Open Source the Right Way</title>
      <dc:creator>Raghav</dc:creator>
      <pubDate>Sun, 22 Jun 2025 13:30:14 +0000</pubDate>
      <link>https://dev.to/raghavyuva/dont-be-a-foolish-contributing-to-open-source-the-right-way-1907</link>
      <guid>https://dev.to/raghavyuva/dont-be-a-foolish-contributing-to-open-source-the-right-way-1907</guid>
      <description>&lt;h2&gt;
  
  
  Don't be a foolish
&lt;/h2&gt;

&lt;p&gt;I know most people follow some great influencers.  Wait let me put this another way :p &lt;strong&gt;Every influencer builds a set of people to follow them.&lt;/strong&gt; This holds true across industries including ours software engineering. Influencers want attention. They want you &lt;em&gt;hooked&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
And truth be told, a lot of us are just... there for the taking. Like prey.  You might be asking, "Why are you even talking about influencers?" Simple: &lt;strong&gt;don’t be a prey&lt;/strong&gt;.  Don’t get hooked just because someone &lt;em&gt;told&lt;/em&gt; you to.  Take what you want &lt;em&gt;not&lt;/em&gt; what they want to sell. &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.amazonaws.com%2Fuploads%2Farticles%2Fy6sqh2konvf8cjm2oxyc.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.amazonaws.com%2Fuploads%2Farticles%2Fy6sqh2konvf8cjm2oxyc.png" alt="Influencers about open-source" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me give you a small reality check,  People have rushed into open source just to get goodies.  Or to show off a contribution. Or flex open sourcing.  And hey, I get it competition is tough. So now the real question is  &lt;strong&gt;How do you stay smart and still stand out without losing yourself?&lt;/strong&gt;  Let’s move to the next part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be a gentlemen
&lt;/h2&gt;

&lt;p&gt;We just saw what’s messed up. Now let’s flip that.  Let’s talk about &lt;em&gt;how&lt;/em&gt; to contribute meaningfully. And yeah, be one among the smart folks without acting like you know everything.&lt;/p&gt;

&lt;p&gt;You think making changes to the codebase is the only way to contribute? That’s where most people go wrong.  Open source isn’t just about pull requests.  Let me break it down.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Replace your paid software with open source alternatives
&lt;/h3&gt;

&lt;p&gt;Start with what you use every day phone, laptop, browser extensions, editors. You’ll be surprised how many open source tools are out there doing the job &lt;em&gt;better&lt;/em&gt; than the paid ones. &lt;/p&gt;

&lt;p&gt;For example:  Instead of using some heavy VPS management dashboard, switch to something like &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt; which is open-source, self-hostable, built by folks who understand what pain means. You’re not just saving money here.  You’re supporting real engineers building real tools for the community.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Now that you’ve switched, show some gratitude
&lt;/h3&gt;

&lt;p&gt;You replaced it. You’re using it.  The least you can do? &lt;strong&gt;Star the repo&lt;/strong&gt;. Maintainers don’t see your thank you tweets. But they &lt;em&gt;do&lt;/em&gt; see stars. You didn’t pay for it.  You didn’t file bugs.  You didn’t contribute.  At least star it?&lt;/p&gt;

&lt;p&gt;It’s a simple way of saying : &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.amazonaws.com%2Fuploads%2Farticles%2Fbh7fx51mi98hgybcmqwj.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.amazonaws.com%2Fuploads%2Farticles%2Fbh7fx51mi98hgybcmqwj.png" alt="Open Source Software Helping People" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. If you’ve got money, don’t pay but &lt;strong&gt;sponsor&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Yeah, I said it wrong. You’re not &lt;em&gt;paying&lt;/em&gt; anyone.  You’re &lt;strong&gt;sponsoring&lt;/strong&gt; the effort. Projects have recurring costs. Time is money. And if you believe in the tool, why not put in a small amount every month? It doesn’t have to be big. Just enough to say, “I care.”&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Spread the word
&lt;/h3&gt;

&lt;p&gt;If you found something amazing, don’t keep it to yourself. Send it to a friend. Drop it in your dev Discord.  Write a LinkedIn post. Tweet about how it helped you. We all love that little high when someone goes “thanks for suggesting this" right? Give others that chance too.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Found a bug? Got an idea?
&lt;/h3&gt;

&lt;p&gt;Okay now it’s time to open GitHub or GitLab. But please don’t be that person who opens an issue like:&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.amazonaws.com%2Fuploads%2Farticles%2Fmk0o4bedtutxuyfo5dgt.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.amazonaws.com%2Fuploads%2Farticles%2Fmk0o4bedtutxuyfo5dgt.png" alt="Random Man Shouting Not Working Issue on Github" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow the &lt;code&gt;ISSUE_TEMPLATE&lt;/code&gt; if not found then do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define the &lt;strong&gt;problem&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;context&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Share the &lt;strong&gt;steps to reproduce&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Mention your &lt;strong&gt;environment&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Suggest a solution if you have one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it’s a feature, explain what you’re trying to do, and how this feature would help. Don’t just drop a one-liner and disappear. That’s worse than not reporting at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Know how to fix it? Do it right.
&lt;/h3&gt;

&lt;p&gt;Let’s say you understand the issue and you have time to fix it. Here’s what you do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the labels (&lt;code&gt;good first issue&lt;/code&gt;, &lt;code&gt;help wanted&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Make sure no one else is already on it&lt;/li&gt;
&lt;li&gt;Look at the project board or discussions&lt;/li&gt;
&lt;li&gt;Read the contributing guide&lt;/li&gt;
&lt;li&gt;Set it up locally, follow formatting + linting&lt;/li&gt;
&lt;li&gt;Run tests if they exist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then create a &lt;strong&gt;clean PR&lt;/strong&gt; with a clear title and message: &lt;strong&gt;Fix: Prevent Wizard Crash on First Login&lt;/strong&gt; This PR adds a cleanup step to fix the onboarding crash issue. Ask for a review. Be open to feedback. Fix if needed.  Wait calmly and boom, your code goes live. How cool is that?&lt;/p&gt;

&lt;h2&gt;
  
  
  You just followed the ideal path
&lt;/h2&gt;

&lt;p&gt;Let’s pause and Look at what you just did You didn’t jump in just to rack up issues.You weren’t chasing a t-shirt or a contributor badge. You actually used the software, saw what was missing, felt where it hurt. You didn’t throw in a fix blindly rather you understood the context, took the time to figure things out. &lt;/p&gt;

&lt;p&gt;This wasn’t about proving anything to anyone. No influencer told you to. No hype pulled you in. You did it because it made sense. Because the problem felt real. And because somewhere deep inside, you knew you could help.That’s the difference. That’s what makes it genuine.&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.amazonaws.com%2Fuploads%2Farticles%2Fvgng52wlulz667cpxu24.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.amazonaws.com%2Fuploads%2Farticles%2Fvgng52wlulz667cpxu24.png" alt="Ideal Way to Contribute to Open Source" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't know where to start? Here's Nixopus
&lt;/h2&gt;

&lt;p&gt;Check out &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt; a modern, open-source VPS manager built for people who are tired of SSH'ing into every damn server just to restart a container or serve static files. It comes with everything you wish your hosting panel had from Docker support and TLS setup to a file manager, built-in terminal, and basic monitoring, all in one clean, self-hostable interface. Whether you’re managing a single server or juggling ten, it makes the whole thing a lot less painful. &lt;/p&gt;

&lt;p&gt;And yeah, if you find a bug, or want to improve it, now you know exactly how to go about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Look open source isn’t a popularity contest.  It’s a playground for creators, fixers, dreamers, and builders. Be intentional.  Be helpful.  Be respectful.  You don’t need permission to start. Just don’t be a foolish.&lt;/p&gt;

&lt;p&gt;Got thoughts? Share them. Got a story? I’d love to hear how &lt;em&gt;you&lt;/em&gt; started with open source. &lt;/p&gt;

&lt;h2&gt;
  
  
  You Were Here All Along So Here's a Surprise
&lt;/h2&gt;

&lt;p&gt;If you've been exploring Nixopus and thinking about getting a VPS to try it out, we’ve got something special for you.&lt;/p&gt;

&lt;p&gt;We’ve partnered with &lt;a href="https://hostup.se/en/vps/" rel="noopener noreferrer"&gt;&lt;strong&gt;Hostup&lt;/strong&gt;&lt;/a&gt;, a fast and reliable VPS provider based in Sweden, to bring an exclusive deal to the &lt;a href="https://discord.gg/skdcq39Wpv" rel="noopener noreferrer"&gt;Nixopus Community&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;🎁 What’s the Surprise?&lt;/p&gt;

&lt;p&gt;Use the code &lt;code&gt;J9UYJCQBHL&lt;/code&gt; at checkout to get 10% off recurring on any VPS plan. Whether you're self-hosting with Nixopus, managing your own infrastructure, or spinning up Docker containers this is a great chance to start with solid, affordable hosting.&lt;/p&gt;

&lt;p&gt;Go build something cool. The infra’s on discount.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>programming</category>
      <category>github</category>
      <category>contributorswanted</category>
    </item>
    <item>
      <title>The Gem of a Github Action you never used</title>
      <dc:creator>Raghav</dc:creator>
      <pubDate>Sat, 14 Jun 2025 08:43:26 +0000</pubDate>
      <link>https://dev.to/raghavyuva/the-gem-of-a-github-action-you-never-used-11i6</link>
      <guid>https://dev.to/raghavyuva/the-gem-of-a-github-action-you-never-used-11i6</guid>
      <description>&lt;p&gt;It's time I show you one of the coolest GitHub Actions we're using at &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt;.If you're like me, you're probably more curious about the &lt;strong&gt;“why”&lt;/strong&gt; than just hearing the solution QEMU.&lt;/p&gt;

&lt;p&gt;So before diving into how we use QEMU, let me walk you through the &lt;em&gt;why&lt;/em&gt; so the context is clear and the solution makes perfect sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Too Many Moving Parts: Why We Needed Emulation?
&lt;/h2&gt;

&lt;p&gt;Nixopus is a platform that streamlines your entire VPS/server workflow. But deploying it wasn’t always smooth we hit a few bottlenecks that made us rethink our existing approach.&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.amazonaws.com%2Fuploads%2Farticles%2Fuvovsktgnxgf3bfax5qu.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.amazonaws.com%2Fuploads%2Farticles%2Fuvovsktgnxgf3bfax5qu.png" alt="The need of Emulation" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s the situation, We offer a &lt;strong&gt;self-hosting one-liner installation script&lt;/strong&gt;. This script handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker setup
&lt;/li&gt;
&lt;li&gt;SSH configuration
&lt;/li&gt;
&lt;li&gt;Proxy management
&lt;/li&gt;
&lt;li&gt;Bringing up Nixopus services (API, database, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Naturally, this raised a few critical questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How can we test this installation script &lt;em&gt;every time&lt;/em&gt; we make changes?&lt;/li&gt;
&lt;li&gt;How can we be sure it works across all major Linux distributions, regardless of their initial state?&lt;/li&gt;
&lt;li&gt; How do we verify the script works with a &lt;strong&gt;matrix of different parameters&lt;/strong&gt;?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Obvious Solution You’d Think Of
&lt;/h2&gt;

&lt;p&gt;If you're anything like me, your first instinct is to think of a &lt;strong&gt;quick fix&lt;/strong&gt;, then improve upon it. So I started thinking in these directions:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. "Let’s Write Unit Tests for Each Function?"
&lt;/h3&gt;

&lt;p&gt;That was my first idea the classic starting point. But as you’ll soon see, it doesn’t really address the kind of problems we’re facing. Sure, unit tests are great. It’s tempting to think “Let’s just write a test for each function and run it on every change via CI/CD. Easy, right?”&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;Sounds good in theory.&lt;/em&gt;  But &lt;em&gt;falls apart in practice.&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;Why? Because we're not just dealing with simple logic here we’re dealing with the full complexity of what our installer sets up. Now ask yourself : How do you unit test that without turning your test suite into a full blown Docker simulator Mocking all of that? At that point, you’re not testing your install script... you’re testing your mock environment.&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.amazonaws.com%2Fuploads%2Farticles%2Frlqs2a2s6jxailn033h0.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.amazonaws.com%2Fuploads%2Farticles%2Frlqs2a2s6jxailn033h0.png" alt="The Secret Funding" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that’s when I knew unit tests alone weren’t going to cut it&lt;/p&gt;

&lt;h3&gt;
  
  
  2. "How about manually testing the installer before release?"
&lt;/h3&gt;

&lt;p&gt;I figured if nothing else works, I’ll just set up a GitHub Action that SSHes into my VPS and runs the installer.  I even explored &lt;a href="https://github.com/appleboy/ssh-action" rel="noopener noreferrer"&gt;&lt;code&gt;appleboy/ssh-action&lt;/code&gt;&lt;/a&gt; to automate this through GitHub Actions.&lt;/p&gt;

&lt;p&gt;Sounds promising, right? You could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run tests on every push&lt;/li&gt;
&lt;li&gt;Validate the installer across multiple config permutations using matrix builds&lt;/li&gt;
&lt;li&gt;Catch failures early&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here’s where it started to fall apart:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You need a &lt;strong&gt;dedicated VPS just for testing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;How do you &lt;strong&gt;run parallel executions&lt;/strong&gt; of the installer, especially when &lt;code&gt;systemd&lt;/code&gt; is involved?
&lt;/li&gt;
&lt;li&gt;Want to test different distros? Well… you'd need a VPS for &lt;em&gt;each&lt;/em&gt; one.&lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2Fh2bzvw81p3qhis7vlxsp.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.amazonaws.com%2Fuploads%2Farticles%2Fh2bzvw81p3qhis7vlxsp.png" alt="Complexity of Multiple Distribution Testing" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. "Virtualization is the easy-peasy solution, right?"
&lt;/h3&gt;

&lt;p&gt;At this point, the idea of spinning up virtual machines felt like a natural next step.  We were close testing on a real VPS worked, but lacked multi-distro flexibility.&lt;/p&gt;

&lt;p&gt;That’s when tools like &lt;a href="https://developer.hashicorp.com/vagrant" rel="noopener noreferrer"&gt;HashiCorp Vagrant&lt;/a&gt; caught my eye.  It provides a full-featured way to manage virtual machine lifecycles.  &lt;/p&gt;

&lt;p&gt;So in theory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We dedicate one VPS for testing&lt;/li&gt;
&lt;li&gt;Spin up VMs for each target distro&lt;/li&gt;
&lt;li&gt;Run the installation script in each&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds solid. But then reality kicked in:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;"Wait... aren’t we over-engineering this just to test an install script?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s be honest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do we really want to maintain VM lifecycle logic inside our CI?
&lt;/li&gt;
&lt;li&gt;Do we even have enough system resources on a single VPS to run multiple distros &lt;em&gt;in parallel&lt;/em&gt;?&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Now you might be thinking — "Why not just use containers?"
&lt;/h4&gt;

&lt;p&gt;Yup. Same thought crossed my mind. But that idea died the moment I remembered&lt;br&gt;&lt;br&gt;
We’re dealing with &lt;code&gt;systemd&lt;/code&gt;, low-level networking, service bootstrapping stuff containers just aren’t great at simulating. &lt;strong&gt;And that’s how we ended up looking at full system emulation...&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Life Saviour: &lt;a href="https://github.com/docker/setup-qemu-action" rel="noopener noreferrer"&gt;QEMU GitHub Action&lt;/a&gt; from Docker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;qemu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up QEMU&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-qemu-action@v3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.qemu.org/" rel="noopener noreferrer"&gt;QEMU&lt;/a&gt; is a generic and open-source machine emulator and virtualizer.&lt;/p&gt;

&lt;p&gt;After walking through all those pain points distro variations, systemd compatibility, real OS behavior, parameter matrix testing  QEMU turned out to be the &lt;strong&gt;cleanest and most reliable solution&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;And the best part?&lt;br&gt;&lt;br&gt;
It worked out-of-the-box &lt;em&gt;without any fuss&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Did We Learn From All This?
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Fu1y3s1475irghih86kwm.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.amazonaws.com%2Fuploads%2Farticles%2Fu1y3s1475irghih86kwm.png" alt="Nixopus Logo" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might be thinking &lt;strong&gt;“Why not just look at how other projects test their self-hosting installation scripts?”&lt;/strong&gt; You're right that would’ve been the easier route.  But here’s the thing: we’re not just blindly following others.  We’re solving a real-world, reproducible problem &lt;em&gt;with intent&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Others might have elegant test setups or they might be winging it behind the scenes.&lt;br&gt;&lt;br&gt;
What matters is the &lt;strong&gt;process&lt;/strong&gt; we went through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hitting walls&lt;/li&gt;
&lt;li&gt;Considering workarounds&lt;/li&gt;
&lt;li&gt;Evaluating complexity vs. scalability&lt;/li&gt;
&lt;li&gt;Finally arriving at a solution that fits &lt;strong&gt;our needs&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And funny enough all of this, just to test a one-liner installation script 😂&lt;/p&gt;

&lt;p&gt;But hey, that’s engineering. &lt;/p&gt;

&lt;p&gt;If you know any better approach than this let's talk more and shape it out. if you are someone who is interested in such engineering take ups here we are &lt;a href="https://discord.gg/skdcq39Wpv" rel="noopener noreferrer"&gt;Join our Community&lt;/a&gt; &lt;/p&gt;

</description>
      <category>github</category>
      <category>githubactions</category>
      <category>docker</category>
      <category>vps</category>
    </item>
    <item>
      <title>How Docker Contexts Transformed My Multi-Environment Workflow</title>
      <dc:creator>Raghav</dc:creator>
      <pubDate>Tue, 10 Jun 2025 17:09:27 +0000</pubDate>
      <link>https://dev.to/raghavyuva/how-docker-contexts-transformed-my-multi-environment-workflow-20hg</link>
      <guid>https://dev.to/raghavyuva/how-docker-contexts-transformed-my-multi-environment-workflow-20hg</guid>
      <description>&lt;p&gt;One fine evening, I was working on my project &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Nixopus&lt;/a&gt;. Nixopus is a self-hostable application that puts an end to the chaos of traditional VPS management.. As part of the setup process, I had written a script to automate its deployment across different environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Context of the Problem
&lt;/h2&gt;

&lt;p&gt;Nixopus internally relies on Docker for running and managing its services, so the script had to ensure full and secure access to Docker on the host machine. Here's what it needed to handle across any environment:&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.amazonaws.com%2Fuploads%2Farticles%2F7d16xn98z36h7hx9hivr.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.amazonaws.com%2Fuploads%2Farticles%2F7d16xn98z36h7hx9hivr.png" alt="Nixopus Docker" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify Docker installation&lt;/strong&gt; — Check whether Docker was already installed on the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install Docker if missing&lt;/strong&gt; — Make sure to install docker and docker dependencies that are compatible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version compatibility check&lt;/strong&gt; — If Docker is already present, compare its version with what Nixopus requires to ensure smooth operation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate TLS certificates&lt;/strong&gt; — Use &lt;a href="https://www.openssl.org/" rel="noopener noreferrer"&gt;&lt;code&gt;openssl&lt;/code&gt;&lt;/a&gt; to create certificates that allow secure connections to Docker over &lt;a href="https://en.wikipedia.org/wiki/Transport_Layer_Security" rel="noopener noreferrer"&gt;TLS&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Docker daemon&lt;/strong&gt; — Modify the &lt;code&gt;daemon.json&lt;/code&gt; file to:

&lt;ul&gt;
&lt;li&gt;Use the generated TLS certificates,&lt;/li&gt;
&lt;li&gt;Enable secure communication,&lt;/li&gt;
&lt;li&gt;Bind Docker to the required network interfaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate Docker access&lt;/strong&gt; — Reload or restart Docker using &lt;code&gt;systemd&lt;/code&gt; (or another service manager) and ensure secure remote access works as expected.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Chaotism Begins
&lt;/h2&gt;

&lt;p&gt;I &lt;em&gt;thought&lt;/em&gt; I was doing everything right — but then, one by one, problems began piling up like a stack. Let me walk you through the chaos:&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.amazonaws.com%2Fuploads%2Farticles%2Fnvjd1s6j4moalm32kfzc.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.amazonaws.com%2Fuploads%2Farticles%2Fnvjd1s6j4moalm32kfzc.png" alt="Image description" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conflicting &lt;a href="https://docs.docker.com/engine/daemon/" rel="noopener noreferrer"&gt;&lt;code&gt;daemon.json&lt;/code&gt; setups&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
What if the user already had a &lt;code&gt;daemon.json&lt;/code&gt; configured for their own purposes? Should we just go ahead and overwrite it with our custom setup?&lt;br&gt;&lt;br&gt;
At first, I naïvely said “yes.” And that’s when it hit me — we were doomed. Overwriting user configurations without merging or backing them up? A recipe for disaster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No isolation between environments&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
What if I wanted to install Nixopus on the same machine for both &lt;code&gt;production&lt;/code&gt; and &lt;code&gt;staging&lt;/code&gt;? Docker doesn't support running two separate daemons bound to different environments by default. Suddenly, our clean setup felt too rigid. I needed some form of isolation that wouldn't require spinning up full-blown &lt;a href="https://www.vmware.com/topics/virtual-machine" rel="noopener noreferrer"&gt;VMs&lt;/a&gt; or resorting to hacky workarounds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Credential conflicts and confusion&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Each environment had its own TLS certs and binding requirements. But trying to manage them manually — keeping track of which certs belonged to which context, ensuring the right IP was exposed — quickly became error-prone. One small mistake and I’d be locked out of Docker, or worse, end up exposing a production port unintentionally.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where things spiraled. Each new problem broke my illusion of control and made it clear: we needed a better, more structured way to manage Docker across environments — without losing sanity or safety.&lt;/p&gt;

&lt;p&gt;And that’s when Docker &lt;strong&gt;contexts&lt;/strong&gt; entered the scene - like a life saviour&lt;/p&gt;

&lt;h2&gt;
  
  
  Efficient Chaos Management with Docker Context
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Ff2dj1y14ytuad251bkwi.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.amazonaws.com%2Fuploads%2Farticles%2Ff2dj1y14ytuad251bkwi.png" alt="Docker Context Example" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/engine/manage-resources/contexts/" rel="noopener noreferrer"&gt;Docker Context&lt;/a&gt; lets me solve many of the problems I used to face in multi-environment Docker workflows. It brings &lt;strong&gt;isolation&lt;/strong&gt;, &lt;strong&gt;simplicity&lt;/strong&gt;, and &lt;strong&gt;clarity&lt;/strong&gt; to the way I manage local, staging, and production setups.&lt;/p&gt;

&lt;p&gt;With Docker Context, I can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolate environments cleanly&lt;/li&gt;
&lt;li&gt;Use different ports for different daemons&lt;/li&gt;
&lt;li&gt;Configure environment-specific &lt;a href="https://www.digicert.com/tls-ssl/tls-ssl-certificates" rel="noopener noreferrer"&gt;TLS certificates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Avoid the chaos of switching between shell exports, flags, or config files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the best part? It’s &lt;em&gt;really&lt;/em&gt; easy to use. No messy commands. No juggling environment variables. Just simple CLI instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker context create production 
docker context use production 
docker context ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these, I can switch between environments effortlessly, knowing that each one is securely configured and neatly separated from the rest&lt;/p&gt;

&lt;h2&gt;
  
  
  Have We Solved Our Docker Daemon Problem Yet?
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Fyqa0zj2vow0213dpy7p9.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.amazonaws.com%2Fuploads%2Farticles%2Fyqa0zj2vow0213dpy7p9.png" alt="Docker Deamon" width="672" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While Docker Contexts make it easy to switch between different Docker environments from the client side, they don’t solve the problem of running multiple Docker daemons with separate &lt;code&gt;daemon.json&lt;/code&gt; configurations. Docker still expects a single, global &lt;code&gt;daemon.json&lt;/code&gt; file — there's no built-in way to maintain separate configs for different environments on the same machine&lt;/p&gt;

&lt;h3&gt;
  
  
  So how did i work around that?
&lt;/h3&gt;

&lt;p&gt;Here’s the trick: instead of trying to juggle multiple &lt;code&gt;daemon.json&lt;/code&gt; files, i  used &lt;strong&gt;systemd service overrides&lt;/strong&gt;. This allows me to run &lt;strong&gt;multiple Docker daemons&lt;/strong&gt;, each configured with its own port, TLS settings, and data directory — without touching the default config.&lt;/p&gt;

&lt;p&gt;With Docker Contexts handling the client-side switching and &lt;a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html" rel="noopener noreferrer"&gt;systemd overrides&lt;/a&gt; managing isolated daemon instances, I finally got true multi-environment control — clean, secure, and conflict-free.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Nixopus?
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Frxjzvcy6azcp8cowa6de.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.amazonaws.com%2Fuploads%2Farticles%2Frxjzvcy6azcp8cowa6de.png" alt="Nixopus - Streamline your server workflow" width="600" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/raghavyuva/introducing-nixopus-all-in-one-open-source-vps-management-solution-4keg"&gt;Nixopus is a self-hostable application&lt;/a&gt; that puts an end to the chaos of traditional &lt;a href="https://en.wikipedia.org/wiki/Virtual_private_server" rel="noopener noreferrer"&gt;VPS&lt;/a&gt; management.&lt;/p&gt;

&lt;p&gt;Whether you're running multiple environments, deploying Docker containers, managing static sites, or just tinkering with servers for fun — Nixopus gives you a clean, powerful web interface to do it all.&lt;/p&gt;

&lt;p&gt;No more memorizing commands, editing obscure config files, or SSH-ing into every box manually. With Nixopus, you can focus on what really matters: building your side project, running your business, or learning infrastructure at your own pace — without the stress.It’s open-source, community-driven, and designed for developers who value &lt;strong&gt;clarity&lt;/strong&gt;, &lt;strong&gt;control&lt;/strong&gt;, and &lt;strong&gt;simplicity&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Did You Know About Docker Contexts and This Hack?
&lt;/h2&gt;

&lt;p&gt;Were you already using Docker Contexts or aware of this systemd override trick?&lt;br&gt;&lt;br&gt;
Or how do &lt;em&gt;you&lt;/em&gt; usually manage these kinds of multi-environment challenges?&lt;/p&gt;

&lt;p&gt;Maybe there’s an even better solution we haven’t thought of yet — and we’d love to hear about it.&lt;/p&gt;

&lt;p&gt;At Nixopus, we believe in &lt;strong&gt;community-driven development&lt;/strong&gt;. We're building a powerful, open-source VPS workflow manager — and solving real-world infrastructure pain points together.&lt;/p&gt;

&lt;p&gt;If you're passionate about DevOps, automation, or self-hosting, &lt;a href="https://discord.gg/skdcq39Wpv" rel="noopener noreferrer"&gt;join our community&lt;/a&gt; and help shape the future of server management.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>docker</category>
      <category>vps</category>
      <category>linux</category>
    </item>
    <item>
      <title>Introducing Nixopus - All in one Open Source VPS Management Solution</title>
      <dc:creator>Raghav</dc:creator>
      <pubDate>Tue, 29 Apr 2025 13:23:09 +0000</pubDate>
      <link>https://dev.to/raghavyuva/introducing-nixopus-all-in-one-open-source-vps-management-solution-4keg</link>
      <guid>https://dev.to/raghavyuva/introducing-nixopus-all-in-one-open-source-vps-management-solution-4keg</guid>
      <description>&lt;p&gt;I'm a long-term VPS user, and I've been using VPS servers for various purposes over the last 5–6 years. Sometimes, though, managing a VPS feels unnecessarily terrible.&lt;br&gt;
I know it can be tempting to think, "Well, isn't it your fault for not knowing how to manage it properly?" I see your point, and I have to admit that I do agree with you to a certain degree. But here's the thing: whether I'm a pro at managing a VPS or not, it should be a breeze!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Prefer a quick overview? 👉 &lt;a href="https://youtu.be/DrDGWNq4JM4?si=yfr-f5mycSVFJIgs" rel="noopener noreferrer"&gt;Watch the Nixopus Demo&lt;/a&gt;&lt;br&gt;&lt;br&gt;
(You can always come back to explore the full details below!)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Control Panels &amp;amp; Tools
&lt;/h2&gt;

&lt;p&gt;These days, I notice fewer people relying on traditional control panels — for good reasons.Tech-savvy users often prefer advanced, modern GUI tools, or they work directly through the terminal.&lt;/p&gt;

&lt;p&gt;Take a simple example: when I want to host an application I've built, I usually have two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a CI/CD pipeline (for example, using GitHub Actions), which requires configuring SSH keys, private access options, environment variables, and adapting pipelines as configurations evolve.&lt;/li&gt;
&lt;li&gt;Or use self-hosting tools like &lt;a href="https://coolify.io" rel="noopener noreferrer"&gt;Coolify&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speaking of Coolify — it’s a &lt;strong&gt;great&lt;/strong&gt; project. I personally admire its scope, have used it, and was even part of the Coolify Discord community.&lt;br&gt;
However, Coolify primarily focuses on self-hosting capabilities. It's a fantastic choice if your goal is just that — &lt;strong&gt;self-hosting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But as a user, I wanted more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A powerful file manager,&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Google Cloud / AWS Cloud Shell&lt;/strong&gt;-like experience,&lt;/li&gt;
&lt;li&gt;A modern interface to manage my server, apps, and files — all in one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wasn’t ready to install separate tools and manage them individually for each task.&lt;br&gt;
That’s when I decided: &lt;strong&gt;Why not create something that combines all these needs into one seamless VPS management tool?&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Fogva834egeg6k7t6ay14.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.amazonaws.com%2Fuploads%2Farticles%2Fogva834egeg6k7t6ay14.png" alt="Nixopus Introduction" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nixopus is your all-in-one platform to make VPS management simple, fast, and hassle-free. Whether you're a developer, system administrator, or just someone running your own server, Nixopus brings everything you need into one place — no extra setup, no messy configurations.&lt;/p&gt;

&lt;p&gt;With Nixopus, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Host your applications easily with one-click deployments,&lt;/li&gt;
&lt;li&gt;Access a built-in terminal just like Google Cloud Shell or AWS CloudShell,&lt;/li&gt;
&lt;li&gt;Navigate your server files with a modern, intuitive file manager,&lt;/li&gt;
&lt;li&gt;Manage domains, TLS certificates, notifications, and more — all from a clean, simple dashboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No need to install multiple tools or stitch things together manually — Nixopus gives you everything you need to deploy, monitor, manage, and maintain your servers — right at your fingertips.&lt;/p&gt;

&lt;p&gt;This is just the beginning — and as Nixopus grows, it's going to get even more powerful, with more features driven by community feedback and real-world needs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To install Nixopus on your VPS, ensure you have sudo access and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/raghavyuva/nixopus/refs/heads/master/scripts/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Optional Parameters
&lt;/h3&gt;

&lt;p&gt;You can customize your installation by providing the following optional parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--api-domain&lt;/code&gt;: Specify the domain where the Nixopus API will be accessible (e.g., &lt;code&gt;nixopusapi.example.tld&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--app-domain&lt;/code&gt;: Specify the domain where the Nixopus app will be accessible (e.g., &lt;code&gt;nixopus.example.tld&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--email&lt;/code&gt; or &lt;code&gt;-e&lt;/code&gt;: Set the email for the admin account&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--password&lt;/code&gt; or &lt;code&gt;-p&lt;/code&gt;: Set the password for the admin account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example with optional parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/raghavyuva/nixopus/refs/heads/master/scripts/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--api-domain&lt;/span&gt; nixopusapi.example.tld &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--app-domain&lt;/span&gt; nixopus.example.tld &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--email&lt;/span&gt; admin@example.tld &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--password&lt;/span&gt; Adminpassword@123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Accessing Nixopus
&lt;/h3&gt;

&lt;p&gt;After successful installation, you can access the Nixopus dashboard by visiting the URL you specified in the &lt;code&gt;--app-domain&lt;/code&gt; parameter (e.g., &lt;code&gt;https://nixopus.example.tld&lt;/code&gt;). Use the email and password you provided during installation to log in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;I'm excited to walk you through what Nixopus has to offer.&lt;br&gt;
Let’s start exploring its features!&lt;/p&gt;

&lt;h3&gt;
  
  
  Self-Hosting
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Fuafd79zpyuepkqmdmloi.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.amazonaws.com%2Fuploads%2Farticles%2Fuafd79zpyuepkqmdmloi.png" alt="Self Hosting With Nixopus" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Nixopus, you can easily host applications on your own server, manage them, and monitor them — all in one place.&lt;br&gt;
Nixopus currently offers build packs for &lt;strong&gt;Dockerfiles&lt;/strong&gt; and &lt;strong&gt;static sites&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I know, I know — you’re probably expecting even more options!&lt;br&gt;
But remember, this is just an &lt;strong&gt;alpha release&lt;/strong&gt;.&lt;br&gt;
I intentionally chose not to build everything at once and publish it a year later — only to find out it doesn’t meet the real needs of users.&lt;br&gt;
Instead, I want to &lt;strong&gt;grow Nixopus together with the community&lt;/strong&gt;, one step at a time!&lt;/p&gt;

&lt;p&gt;Nixopus' self-hosting capabilities also offer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easy to configure modern TLS&lt;/strong&gt;, including modern ciphersuites, including out-of-the-box support for multiple signed CAs.,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub integration&lt;/strong&gt; — connect your repository and set up automatic deployments when you push changes to specified branches,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easily configure and quickly redeploy&lt;/strong&gt; configurations or even new instances of your applications.,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application deletion&lt;/strong&gt; when it's no longer needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Nixopus, you don’t have to perform extra manual steps — it listens, builds, and updates for you.&lt;br&gt;
&lt;strong&gt;Simple. Reliable. Developer-first.&lt;/strong&gt; &lt;a href="https://docs.nixopus.com/self-host" rel="noopener noreferrer"&gt;Know more&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Powerful Terminal
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Fnb33iokonmjyrdg0ycuf.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.amazonaws.com%2Fuploads%2Farticles%2Fnb33iokonmjyrdg0ycuf.png" alt="Nixopus Terminal" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you log in for the first time, you’ll notice a terminal conveniently located at the bottom of the dashboard.You can toggle it easily — just like in enterprise tools such as Visual Studio Code — by pressing &lt;strong&gt;(Ctrl/Command + J)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This terminal is designed to offer a similar experience to working with &lt;strong&gt;Google Cloud Shell&lt;/strong&gt; or &lt;strong&gt;AWS CloudShell&lt;/strong&gt;, but with an eye toward even &lt;strong&gt;better&lt;/strong&gt;, &lt;strong&gt;more elegant&lt;/strong&gt; features in upcoming releases!&lt;/p&gt;

&lt;p&gt;Thinking of a cool feature you'd love to see in the terminal?&lt;br&gt;
You're more than welcome to &lt;a href="https://docs.nixopus.com/contributing/" rel="noopener noreferrer"&gt;contribute&lt;/a&gt; — come shape the future of Nixopus' terminal alongside fellow developers and make it truly your own!&lt;/p&gt;

&lt;h3&gt;
  
  
  File Manager
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Femf6w1hrklkgyz1bkzit.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.amazonaws.com%2Fuploads%2Farticles%2Femf6w1hrklkgyz1bkzit.png" alt="Nixopus File Manager" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nixopus also features a built-in &lt;strong&gt;File Manager&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can access it easily from the sidebar — and from there, you know the basics: navigate, manage, and organize your server files intuitively. Currently, the File Manager is very basic, as the focus is on stability and core functionality, since this is still the alpha stage.&lt;/p&gt;

&lt;p&gt;Needless to say, there are many useful features, developer-friendly add-ons, and a plethora of cosmetic updates on the roadmap.&lt;/p&gt;

&lt;h3&gt;
  
  
  8 More Features You’ll Love
&lt;/h3&gt;

&lt;p&gt;Beyond the major features we covered earlier, Nixopus also offers a variety of powerful customizations and enhancements through its settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dark/Light Mode&lt;/strong&gt; — Easily switch between dark and light themes based on your preference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Fonts&lt;/strong&gt; — Choose from a collection of cool fonts! (I’ll admit — picking the perfect font isn’t my strong suit — so I’ve made sure you can choose the one that suits &lt;em&gt;you&lt;/em&gt; best!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language Selector&lt;/strong&gt; — Prefer using software in your native language? Me too! (I'm a proud Kannadiga, so Kannada is already available!) Want to &lt;a href="https://github.com/raghavyuva/nixopus/issues" rel="noopener noreferrer"&gt;add your language&lt;/a&gt; or improve existing translations that feel robotic? Let’s collaborate and make it truly human-friendly!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two-Factor Authentication and SSH-Based Connections to Your Server&lt;/strong&gt; — When it comes to &lt;a href="https://github.com/raghavyuva/nixopus/actions/workflows/security.yml" rel="noopener noreferrer"&gt;security&lt;/a&gt;, I personally want Nixopus to include many best practices and security-related features — because we are exposing our server on the web, right!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Management &amp;amp; Auditing&lt;/strong&gt; — You can add team members, manage permissions, and track activities. (Yes, we already have an auditing system that logs who did what and when!) More advanced team and organization features are planned for the beta release — stay tuned!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain Management&lt;/strong&gt; — Add and verify your domains right inside Nixopus. This makes it seamless to connect your domains while &lt;a href="https://docs.nixopus.com/self-host/" rel="noopener noreferrer"&gt;self-hosting&lt;/a&gt; your apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Notifications&lt;/strong&gt; — Choose the types of notifications you want to receive, and get alerted via &lt;strong&gt;Email&lt;/strong&gt;, &lt;strong&gt;Slack&lt;/strong&gt;, or &lt;strong&gt;Discord&lt;/strong&gt; — your choice!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-Update&lt;/strong&gt; — Stay up to date effortlessly! You can either enable automatic updates when we release new features and fixes, or manually trigger updates with a single click from the dashboard’s top-right corner.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The features you see today are just a &lt;strong&gt;glimpse&lt;/strong&gt; of Nixopus' true potential.&lt;br&gt;
&lt;a href="https://docs.nixopus.com/introduction/#nixopus-stability" rel="noopener noreferrer"&gt;Stability&lt;/a&gt;, power, and polish will come from refining these features — and yes, by writing &lt;strong&gt;beautiful, robust tests&lt;/strong&gt; along the way!&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Coming Next?
&lt;/h2&gt;

&lt;p&gt;I know you’re probably even more excited than I am — so let’s talk about what’s next!&lt;br&gt;
My goal is to make Nixopus truly &lt;strong&gt;enterprise-ready&lt;/strong&gt; and &lt;strong&gt;stable&lt;/strong&gt; as a VPS management solution.&lt;/p&gt;

&lt;p&gt;Here are a few key areas I’m focusing on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security best practices&lt;/strong&gt; — &lt;em&gt;High importance&lt;/em&gt; (Security is absolutely critical. Expect this to be a top priority.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polish and production-grade stability&lt;/strong&gt; — &lt;em&gt;High importance&lt;/em&gt; (Making Nixopus rock-solid, well-tested, and reliable for real-world deployments.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-server management&lt;/strong&gt; — &lt;em&gt;Medium importance&lt;/em&gt; (I want you to connect and switch between multiple servers easily.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Config/Script Marketplace&lt;/strong&gt; — &lt;em&gt;Medium importance&lt;/em&gt; (A place where you can find and share scripts/configurations. I’ll write a detailed post soon explaining what it is and why I believe it’s needed.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community-driven development&lt;/strong&gt; — &lt;em&gt;Extremely important&lt;/em&gt; (I don’t want to build Nixopus in the dark. Every developer has different perspectives — you might love a feature I don’t, or dislike something I love. That’s the beauty of building &lt;em&gt;together&lt;/em&gt;.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Show Your Support
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Fs9wrd7gx6nxw8amjm75c.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.amazonaws.com%2Fuploads%2Farticles%2Fs9wrd7gx6nxw8amjm75c.png" alt="Nixopus is Open Source" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nixopus is meant to be &lt;strong&gt;community-driven&lt;/strong&gt;, and for that, I kindly ask for your support.I’m fully aware that the current &lt;strong&gt;alpha release&lt;/strong&gt; has rough edges — and that’s intentional.Rather than hyping it as “production-ready” when it’s not, I chose to release early to gather &lt;strong&gt;honest community feedback&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is your chance to shape Nixopus!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can help by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starring us on &lt;a href="https://github.com/raghavyuva/nixopus" rel="noopener noreferrer"&gt;Github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sponsors/raghavyuva" rel="noopener noreferrer"&gt;Sponsoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Contributing,&lt;/li&gt;
&lt;li&gt;Sharing it with your friends,&lt;/li&gt;
&lt;li&gt;Or even telling the harsh truths — if you didn’t like something, &lt;a href="//mailto:raghavyuva@gmail.com"&gt;I &lt;em&gt;want&lt;/em&gt; to hear it&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every word, every contribution, every opinion matters — and it’s all welcomed with open arms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Most readily available comparable products on the market are limited, not developer-friendly, or very user-unfriendly in terms of price and availability. Apparently, there is a huge gap and problem that Nixopus as a project is trying to address.&lt;/p&gt;

&lt;p&gt;Nixopus is community driven, developer friendly and constantly evolving. With a few private deployments, including by friends, the amount of usable feedback is turning Nixopus into a truly modern server management tool with features that server admins are really looking for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://discord.gg/skdcq39Wpv" rel="noopener noreferrer"&gt;Join the community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>cloud</category>
      <category>go</category>
    </item>
  </channel>
</rss>
