Building a Self Hostable Installer, Lessons from Nixopus

Building a Self Hostable Installer, Lessons from Nixopus

Source: Dev.to

Why We’re Writing This ## The Early Days: Bash Scripts ## Moving to a Proper CLI ## Why Python Typer ## Refactoring the Installer ## How the installer looks like ## Keeping the CLI Clean but Flexible ## The Next Problem We Hit ## Discoverability vs Overwhelm ## Documentation Isn’t Always Enough ## The Install Command Generator ## Conclusion While we spent and reworked the Nixopus installer many times, this feels like the right moment to share our experience and the lessons we learned along the way. When your product is self hostable and open source, installation becomes tricky. Why? Because it is not the usual flow of opening a website, logging in, and clicking around to explore features. With Nixopus, we wanted people to experience everything from the ground up by self hosting it on their own infrastructure. We started small. The first version was a simple Bash script for self hosting. It worked well for a few days. But as we began introducing new features and more ideas around improving the initial installation and self hosting experience, the Bash codebase started growing rapidly.The number of lines kept increasing and complexity crept in faster than we expected At some point, it no longer felt like we were working on a few small scripts. It felt like we were building and maintaining a full user experience layer. Simple tasks, like finding duplicates in an array, suddenly felt heavy. Not because the problem itself was hard, but because we were solving it in Bash. We were not here to solve a “find duplicates in an array” problem. We were here to build a product. What we really wanted was something Straightforward, Quick to adopt, Easy to move fast with the installer needed to support the product, not slow us down. This was also the point where we realized that if we wanted to scale this, we needed a proper CLI. With that in mind, we chose Python Typer https://typer.tiangolo.com/ It is built on top of Rich, which made a big difference for us. All of this was straightforward. The overall developer experience was simple, fast enough, more than anything the experience it gives to user.. We then took our large Bash script and refactored it into multiple smaller files, each broken down by domain: Each responsibility lived in its own focused module. This is how it eventually turned out: $ nixopus [OPTIONS] COMMAND [ARGS]... We added a few core commands like install update version uninstall Other smaller commands were intentionally left unregistered to avoid adding unnecessary complexity for the end user. When needed, we can easily register those internal commands from a single file and they work as expected. For example SSH key generation, and setting up environment variables. These can be tedious when configuring a development environment. Instead of handling that manually, it becomes as simple as running: This approach keeps the default CLI clean while still giving us full control to expose more commands when they are actually needed. We felt good about the changes for a few days, and the early success of that decision was clear. But soon, new ideas started piling up. Now users had clear commands like install, but a new problem showed up. The real question became this. How do we help users discover and understand these parameters in a way that does not overwhelm them? Take ports as a simple example: Even though we have everything documented in our CLI reference it can still be hard.Sometimes even for me and I self host Nixopus multiple times a week, patience and user behavior matter a lot here. So we came up with a Nixopus install command generator. The idea was simple: This lives directly in our documentation and allows users to customize their nixopus install command step by step, with context, instead of guessing or digging through flags. It is always the case of improving from your past experiences, there is no handbook for anything, so take a right decision at right times. If you’re building something and facing similar challenges, I hope this story helps you make the right decisions. If you’ve already gone through something like this, I’d love to hear your experience. Follow me for more detailed stories like this. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse - Easier for users to try Nixopus - Room to introduce more commands in the future - Showing progress bars during installation - Pretty printing command output - Clean logging - SSH key generation - Preflight checks - Docker service management - Dependency installation - Proxy initialization - The nixopus install command had a large number of configurable options - Each option existed for a reason - Expecting users to understand all of them upfront was unrealistic - Different services use different ports - Many servers already have ports in use - Users need the ability to customize them - Users also need guidance on when and why to do so - Most users do not want to read long lists of flags - They want things to work - They want guidance only when something actually needs attention - Help users understand which flags do what - Guide them interactively - Generate the install command before they actually run it